Documentation
¶
Overview ¶
Package smapping is Library for collecting various operations on struct and its mapping to interface{} and/or map[string]interface{} type. Implemented to ease the conversion between Golang struct and json format together with ease of mapping selections using different part of field tagging.
The implementation is abstraction on top reflection package, reflect.
Examples ¶
The snippet code below will be used accross example for brevity
type source struct {
Label string `json:"label"`
Info string `json:"info"`
Version int `json:"version"`
Toki time.Time `json:"tomare"`
}
type sink struct {
Label string
Info string
}
type differentSink struct {
DiffLabel string `json:"label"`
NiceInfo string `json:"info"`
Version string `json:"unversion"`
Toki time.Time `json:"doki"`
}
type differentSourceSink struct {
Source source `json:"source"`
DiffSink differentSink `json:"differentSink"`
}
var toki = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
var sourceobj source = source{
Label: "source",
Info: "the origin",
Version: 1,
Toki: toki,
}
func printIfNotExists(mapped Mapped, keys ...string) {
for _, key := range keys {
if _, ok := mapped[key]; !ok {
fmt.Println(key, ": not exists")
}
}
}
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FillStruct ¶
FillStruct acts just like “json.Unmarshal“ but works with “Mapped“ instead of bytes of char that made from “json“.
Example ¶
mapped := MapFields(&sourceobj)
sinked := sink{}
err := FillStruct(&sinked, mapped)
if err != nil {
panic(err)
}
fmt.Println(sinked)
Output: {source the origin}
func FillStructByTags ¶
FillStructByTags fills the field that has tagname and tagvalue instead of Mapped key name.
Example ¶
maptags := MapTags(&sourceobj, "json")
for k, v := range maptags {
if vt, ok := v.(time.Time); ok {
fmt.Printf("maptags[%s]: %s\n", k, vt.Format(time.RFC3339))
} else {
fmt.Printf("maptags[%s]: %v\n", k, v)
}
}
diffsink := differentSink{}
err := FillStructByTags(&diffsink, maptags, "json")
if err != nil {
panic(err)
}
fmt.Println(diffsink)
Output: maptags[label]: source maptags[info]: the origin maptags[version]: 1 maptags[tomare]: 2000-01-01T00:00:00Z {source the origin 0001-01-01 00:00:00 +0000 UTC}
func SQLScan ¶ added in v0.1.3
func SQLScan(row SQLScanner, obj interface{}, tag string, x ...string) error
SQLScan is the function that will map scanning object based on provided field name or field tagged string. The tags can receive the empty string "" and then it will map the field name by default.
Example (AllFields) ¶
currtime := time.Now()
dr := createDummyRow(currtime)
result := dummyValues{}
if err := SQLScan(dr, &result, ""); err != nil {
fmt.Println("Error happened!")
return
}
fmt.Printf("NullString is Valid? %t\n", result.NullString.Valid)
fmt.Printf("result.NullString is %s\n", result.NullString.String)
fmt.Printf("NullTime is Valid? %t\n", result.NullTime.Valid)
fmt.Printf("result.NullTime.Time.Equal(dr.Values.NullTime.Time)? %t\n",
result.NullTime.Time.Equal(dr.Values.NullTime.Time))
fmt.Printf("result.Uint64 == %d\n", result.Uint64)
Output: NullString is Valid? true result.NullString is hello 異世界 NullTime is Valid? true result.NullTime.Time.Equal(dr.Values.NullTime.Time)? true result.Uint64 == 5
Example (SuppliedFields) ¶
currtime := time.Now()
dr := createDummyRow(currtime)
result := dummyValues{}
if err := SQLScan(dr, &result,
"", /* This is the tag, since we don't have so put it empty
to match the field name */
/* Below arguments are variadic and we only take several
fields from all available dummyValues */
"Int32", "Uint64", "Bool", "Bytes",
"NullString", "NullTime"); err != nil {
fmt.Println("Error happened!")
return
}
fmt.Printf("NullString is Valid? %t\n", result.NullString.Valid)
fmt.Printf("NullTime is Valid? %t\n", result.NullTime.Valid)
fmt.Printf("result.NullTime.Time.Equal(dr.Values.NullTime.Time)? %t\n",
result.NullTime.Time.Equal(dr.Values.NullTime.Time))
fmt.Printf("result.Uint64 == %d\n", result.Uint64)
Output: NullString is Valid? true NullTime is Valid? true result.NullTime.Time.Equal(dr.Values.NullTime.Time)? true result.Uint64 == 5
Types ¶
type Mapped ¶
type Mapped map[string]interface{}
Mapped simply an alias
func MapFields ¶
func MapFields(x interface{}) Mapped
MapFields maps between struct to mapped interfaces{}. The argument must be pointer struct or else it will throw panic error. Now it's implemented as MapTags with empty tag "".
Only map the exported fields.
Example ¶
mapped := MapFields(&sourceobj) printIfNotExists(mapped, "Label", "Info", "Version")
func MapTags ¶
MapTags maps the tag value of defined field tag name. This enable various field extraction that will be mapped to mapped interfaces{}.
Example (Basic) ¶
maptags := MapTags(&sourceobj, "json") printIfNotExists(maptags, "label", "info", "version")
Example (Nested) ¶
nestedSource := differentSourceSink{
Source: sourceobj,
DiffSink: differentSink{
DiffLabel: "nested diff",
NiceInfo: "nested info",
Version: "next version",
Toki: toki,
},
}
nestedMap := MapTags(&nestedSource, "json")
for k, v := range nestedMap {
fmt.Println("top key:", k)
for kk, vv := range v.(Mapped) {
if vtime, ok := vv.(time.Time); ok {
fmt.Println(" nested:", kk, vtime.Format(time.RFC3339))
} else {
fmt.Println(" nested:", kk, vv)
}
}
fmt.Println()
}
Output: top key: source nested: label source nested: info the origin nested: version 1 nested: tomare 2000-01-01T00:00:00Z top key: differentSink nested: label nested diff nested: info nested info nested: unversion next version nested: doki 2000-01-01T00:00:00Z
Example (TwoTags) ¶
general := generalFields{
Name: "duran",
Rank: "private",
Code: 1337,
nickname: "drone",
}
mapjson := MapTags(&general, "json")
printIfNotExists(mapjson, "name", "rank", "code")
mapapi := MapTags(&general, "api")
printIfNotExists(mapapi, "general_name", "general_rank", "general_code")
func MapTagsFlatten ¶ added in v0.1.2
MapTagsFlatten is to flatten mapped object with specific tag. The limitation of this flattening that it can't have duplicate tag name and it will give incorrect result because the older value will be written with newer map field value.
Example ¶
type (
Last struct {
Final string `json:"final"`
Destination string
}
Lv3 struct {
Lv3Str string `json:"lv3str"`
*Last
Lv3Dummy string
}
Lv2 struct {
Lv2Str string `json:"lv2str"`
Lv3
Lv2Dummy string
}
Lv1 struct {
Lv2
Lv1Str string `json:"lv1str"`
Lv1Dummy string
}
)
obj := Lv1{
Lv1Str: "level 1 string",
Lv1Dummy: "baka",
Lv2: Lv2{
Lv2Dummy: "bakabaka",
Lv2Str: "level 2 string",
Lv3: Lv3{
Lv3Dummy: "bakabakka",
Lv3Str: "level 3 string",
Last: &Last{
Final: "destination",
Destination: "overloop",
},
},
},
}
for k, v := range MapTagsFlatten(&obj, "json") {
fmt.Printf("key: %s, value: %v\n", k, v)
}
Output: key: final, value: destination key: lv1str, value: level 1 string key: lv2str, value: level 2 string key: lv3str, value: level 3 string
func MapTagsWithDefault ¶
MapTagsWithDefault maps the tag with optional fallback tags. This to enable tag differences when there are only few difference with the default “json“ tag.
Example ¶
type higherCommon struct {
General generalFields `json:"general"`
Communality string `json:"common"`
Available bool `json:"available" api:"is_available"`
}
rawjson := []byte(`{
"general": {
name: "duran",
rank: "private",
code: 1337,
},
"common": "rare",
"available": true
}`)
hc := higherCommon{}
_ = json.Unmarshal(rawjson, &hc)
maptags := MapTagsWithDefault(&hc, "api", "json")
printIfNotExists(maptags, "available")
Output: available : not exists
type SQLScanner ¶ added in v0.1.3
type SQLScanner interface {
Scan(dest ...interface{}) error
}
SQLScanner is the interface that dictate any type that implement Scan method to be compatible with sql.Row Scan method.