diff --git a/container/gvar/gvar.go b/container/gvar/gvar.go index a3e310658..c573a5b32 100644 --- a/container/gvar/gvar.go +++ b/container/gvar/gvar.go @@ -235,100 +235,6 @@ func (v *Var) GTime(format ...string) *gtime.Time { return gconv.GTime(v.Val(), format...) } -// Map converts to map[string]interface{}. -func (v *Var) Map(tags ...string) map[string]interface{} { - return gconv.Map(v.Val(), tags...) -} - -// MapStrStr converts to map[string]string. -func (v *Var) MapStrStr(tags ...string) map[string]string { - return gconv.MapStrStr(v.Val(), tags...) -} - -// MapStrVar converts to map[string]*Var. -func (v *Var) MapStrVar(tags ...string) map[string]*Var { - m := v.Map(tags...) - if len(m) > 0 { - vMap := make(map[string]*Var) - for k, v := range m { - vMap[k] = New(v) - } - return vMap - } - return nil -} - -// MapDeep converts to map[string]interface{} recursively. -func (v *Var) MapDeep(tags ...string) map[string]interface{} { - return gconv.MapDeep(v.Val(), tags...) -} - -// MapDeep converts to map[string]string recursively. -func (v *Var) MapStrStrDeep(tags ...string) map[string]string { - return gconv.MapStrStrDeep(v.Val(), tags...) -} - -// MapStrVarDeep converts to map[string]*Var recursively. -func (v *Var) MapStrVarDeep(tags ...string) map[string]*Var { - m := v.MapDeep(tags...) - if len(m) > 0 { - vMap := make(map[string]*Var) - for k, v := range m { - vMap[k] = New(v) - } - return vMap - } - return nil -} - -// Struct maps value of to . -// The parameter should be a pointer to a struct instance. -// The parameter is used to specify the key-to-attribute mapping rules. -func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error { - return gconv.Struct(v.Val(), pointer, mapping...) -} - -// Struct maps value of to recursively. -// The parameter should be a pointer to a struct instance. -// The parameter is used to specify the key-to-attribute mapping rules. -func (v *Var) StructDeep(pointer interface{}, mapping ...map[string]string) error { - return gconv.StructDeep(v.Val(), pointer, mapping...) -} - -// Structs converts to given struct slice. -func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.Structs(v.Val(), pointer, mapping...) -} - -// StructsDeep converts to given struct slice recursively. -func (v *Var) StructsDeep(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.StructsDeep(v.Val(), pointer, mapping...) -} - -// MapToMap converts map type variable to another map type variable . -// The elements of should be type of struct/*struct. -func (v *Var) MapToMap(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.MapToMap(v.Val(), pointer, mapping...) -} - -// MapToMapDeep recursively converts map type variable to another map type variable . -// The elements of should be type of struct/*struct. -func (v *Var) MapToMapDeep(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.MapToMapDeep(v.Val(), pointer, mapping...) -} - -// MapToMaps converts map type variable to another map type variable . -// The elements of should be type of []struct/[]*struct. -func (v *Var) MapToMaps(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.MapToMaps(v.Val(), pointer, mapping...) -} - -// MapToMapsDeep recursively converts map type variable to another map type variable . -// The elements of should be type of []struct/[]*struct. -func (v *Var) MapToMapsDeep(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.MapToMapsDeep(v.Val(), pointer, mapping...) -} - // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Var) MarshalJSON() ([]byte, error) { return json.Marshal(v.Val()) diff --git a/container/gvar/gvar_map.go b/container/gvar/gvar_map.go new file mode 100644 index 000000000..8b4282b0a --- /dev/null +++ b/container/gvar/gvar_map.go @@ -0,0 +1,87 @@ +// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gvar + +import "github.com/gogf/gf/util/gconv" + +// Map converts and returns as map[string]interface{}. +func (v *Var) Map(tags ...string) map[string]interface{} { + return gconv.Map(v.Val(), tags...) +} + +// MapStrStr converts and returns as map[string]string. +func (v *Var) MapStrStr(tags ...string) map[string]string { + return gconv.MapStrStr(v.Val(), tags...) +} + +// MapStrVar converts and returns as map[string]*Var. +func (v *Var) MapStrVar(tags ...string) map[string]*Var { + m := v.Map(tags...) + if len(m) > 0 { + vMap := make(map[string]*Var) + for k, v := range m { + vMap[k] = New(v) + } + return vMap + } + return nil +} + +// MapDeep converts and returns as map[string]interface{} recursively. +func (v *Var) MapDeep(tags ...string) map[string]interface{} { + return gconv.MapDeep(v.Val(), tags...) +} + +// MapDeep converts and returns as map[string]string recursively. +func (v *Var) MapStrStrDeep(tags ...string) map[string]string { + return gconv.MapStrStrDeep(v.Val(), tags...) +} + +// MapStrVarDeep converts and returns as map[string]*Var recursively. +func (v *Var) MapStrVarDeep(tags ...string) map[string]*Var { + m := v.MapDeep(tags...) + if len(m) > 0 { + vMap := make(map[string]*Var) + for k, v := range m { + vMap[k] = New(v) + } + return vMap + } + return nil +} + +// Maps converts and returns as map[string]string. +// See gconv.Maps. +func (v *Var) Maps(tags ...string) []map[string]interface{} { + return gconv.Maps(v.Val(), tags...) +} + +// MapToMap converts map type variable to another map type variable . +// See gconv.MapToMap. +func (v *Var) MapToMap(pointer interface{}) (err error) { + return gconv.MapToMap(v.Val(), pointer) +} + +// MapToMapDeep converts map type variable to another map type variable +// recursively. +// See gconv.MapToMapDeep. +func (v *Var) MapToMapDeep(pointer interface{}) (err error) { + return gconv.MapToMapDeep(v.Val(), pointer) +} + +// MapToMaps converts map type variable to another map type variable . +// See gconv.MapToMaps. +func (v *Var) MapToMaps(pointer interface{}, mapping ...map[string]string) (err error) { + return gconv.MapToMaps(v.Val(), pointer, mapping...) +} + +// MapToMapsDeep converts map type variable to another map type variable +// recursively. +// See gconv.MapToMapsDeep. +func (v *Var) MapToMapsDeep(pointer interface{}, mapping ...map[string]string) (err error) { + return gconv.MapToMapsDeep(v.Val(), pointer, mapping...) +} diff --git a/container/gvar/gvar_struct.go b/container/gvar/gvar_struct.go new file mode 100644 index 000000000..c963be690 --- /dev/null +++ b/container/gvar/gvar_struct.go @@ -0,0 +1,33 @@ +// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gvar + +import "github.com/gogf/gf/util/gconv" + +// Struct maps value of to . +// The parameter should be a pointer to a struct instance. +// The parameter is used to specify the key-to-attribute mapping rules. +func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error { + return gconv.Struct(v.Val(), pointer, mapping...) +} + +// Struct maps value of to recursively. +// The parameter should be a pointer to a struct instance. +// The parameter is used to specify the key-to-attribute mapping rules. +func (v *Var) StructDeep(pointer interface{}, mapping ...map[string]string) error { + return gconv.StructDeep(v.Val(), pointer, mapping...) +} + +// Structs converts and returns as given struct slice. +func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) (err error) { + return gconv.Structs(v.Val(), pointer, mapping...) +} + +// StructsDeep converts and returns as given struct slice recursively. +func (v *Var) StructsDeep(pointer interface{}, mapping ...map[string]string) (err error) { + return gconv.StructsDeep(v.Val(), pointer, mapping...) +} diff --git a/container/gvar/gvar_z_unit_test.go b/container/gvar/gvar_z_unit_basic_test.go similarity index 80% rename from container/gvar/gvar_z_unit_test.go rename to container/gvar/gvar_z_unit_basic_test.go index b0c9b370b..a3ae8cff4 100644 --- a/container/gvar/gvar_z_unit_test.go +++ b/container/gvar/gvar_z_unit_basic_test.go @@ -9,14 +9,10 @@ package gvar_test import ( "bytes" "encoding/binary" - "encoding/json" "github.com/gogf/gf/util/gconv" - "math" "testing" "time" - "github.com/gogf/gf/frame/g" - "github.com/gogf/gf/container/gvar" "github.com/gogf/gf/test/gtest" ) @@ -305,90 +301,6 @@ func Test_Duration(t *testing.T) { }) } -func Test_Map(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - m := g.Map{ - "k1": "v1", - "k2": "v2", - } - objOne := gvar.New(m, true) - t.Assert(objOne.Map()["k1"], m["k1"]) - t.Assert(objOne.Map()["k2"], m["k2"]) - }) -} - -func Test_Struct(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - type StTest struct { - Test int - } - - Kv := make(map[string]int, 1) - Kv["Test"] = 100 - - testObj := &StTest{} - - objOne := gvar.New(Kv, true) - - objOne.Struct(testObj) - - t.Assert(testObj.Test, Kv["Test"]) - }) - gtest.C(t, func(t *gtest.T) { - type StTest struct { - Test int8 - } - o := &StTest{} - v := gvar.New(g.Slice{"Test", "-25"}) - v.Struct(o) - t.Assert(o.Test, -25) - }) -} - -func Test_Json(t *testing.T) { - // Marshal - gtest.C(t, func(t *gtest.T) { - s := "i love gf" - v := gvar.New(s) - b1, err1 := json.Marshal(v) - b2, err2 := json.Marshal(s) - t.Assert(err1, err2) - t.Assert(b1, b2) - }) - - gtest.C(t, func(t *gtest.T) { - s := int64(math.MaxInt64) - v := gvar.New(s) - b1, err1 := json.Marshal(v) - b2, err2 := json.Marshal(s) - t.Assert(err1, err2) - t.Assert(b1, b2) - }) - - // Unmarshal - gtest.C(t, func(t *gtest.T) { - s := "i love gf" - v := gvar.New(nil) - b, err := json.Marshal(s) - t.Assert(err, nil) - - err = json.Unmarshal(b, v) - t.Assert(err, nil) - t.Assert(v.String(), s) - }) - - gtest.C(t, func(t *gtest.T) { - var v gvar.Var - s := "i love gf" - b, err := json.Marshal(s) - t.Assert(err, nil) - - err = json.Unmarshal(b, &v) - t.Assert(err, nil) - t.Assert(v.String(), s) - }) -} - func Test_UnmarshalValue(t *testing.T) { type V struct { Name string diff --git a/container/gvar/gvar_z_unit_json_test.go b/container/gvar/gvar_z_unit_json_test.go new file mode 100644 index 000000000..f18bc5546 --- /dev/null +++ b/container/gvar/gvar_z_unit_json_test.go @@ -0,0 +1,59 @@ +// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gvar_test + +import ( + "encoding/json" + "github.com/gogf/gf/container/gvar" + "github.com/gogf/gf/test/gtest" + "math" + "testing" +) + +func Test_Json(t *testing.T) { + // Marshal + gtest.C(t, func(t *gtest.T) { + s := "i love gf" + v := gvar.New(s) + b1, err1 := json.Marshal(v) + b2, err2 := json.Marshal(s) + t.Assert(err1, err2) + t.Assert(b1, b2) + }) + + gtest.C(t, func(t *gtest.T) { + s := int64(math.MaxInt64) + v := gvar.New(s) + b1, err1 := json.Marshal(v) + b2, err2 := json.Marshal(s) + t.Assert(err1, err2) + t.Assert(b1, b2) + }) + + // Unmarshal + gtest.C(t, func(t *gtest.T) { + s := "i love gf" + v := gvar.New(nil) + b, err := json.Marshal(s) + t.Assert(err, nil) + + err = json.Unmarshal(b, v) + t.Assert(err, nil) + t.Assert(v.String(), s) + }) + + gtest.C(t, func(t *gtest.T) { + var v gvar.Var + s := "i love gf" + b, err := json.Marshal(s) + t.Assert(err, nil) + + err = json.Unmarshal(b, &v) + t.Assert(err, nil) + t.Assert(v.String(), s) + }) +} diff --git a/container/gvar/gvar_z_unit_map_test.go b/container/gvar/gvar_z_unit_map_test.go new file mode 100644 index 000000000..181344761 --- /dev/null +++ b/container/gvar/gvar_z_unit_map_test.go @@ -0,0 +1,26 @@ +// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gvar_test + +import ( + "github.com/gogf/gf/container/gvar" + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/test/gtest" + "testing" +) + +func Test_Map(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + m := g.Map{ + "k1": "v1", + "k2": "v2", + } + objOne := gvar.New(m, true) + t.Assert(objOne.Map()["k1"], m["k1"]) + t.Assert(objOne.Map()["k2"], m["k2"]) + }) +} diff --git a/container/gvar/gvar_z_unit_maptomap_test.go b/container/gvar/gvar_z_unit_maptomap_test.go new file mode 100644 index 000000000..708d0a3d1 --- /dev/null +++ b/container/gvar/gvar_z_unit_maptomap_test.go @@ -0,0 +1,69 @@ +// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gvar_test + +import ( + "github.com/gogf/gf/container/gvar" + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/test/gtest" + "testing" +) + +func Test_MapToMap(t *testing.T) { + // map[int]int -> map[string]string + // empty original map. + gtest.C(t, func(t *gtest.T) { + m1 := g.MapIntInt{} + m2 := g.MapStrStr{} + t.Assert(gvar.New(m1).MapToMap(&m2), nil) + t.Assert(len(m1), len(m2)) + }) + // map[int]int -> map[string]string + gtest.C(t, func(t *gtest.T) { + m1 := g.MapIntInt{ + 1: 100, + 2: 200, + } + m2 := g.MapStrStr{} + t.Assert(gvar.New(m1).MapToMap(&m2), nil) + t.Assert(m2["1"], m1[1]) + t.Assert(m2["2"], m1[2]) + }) + // map[string]interface{} -> map[string]string + gtest.C(t, func(t *gtest.T) { + m1 := g.Map{ + "k1": "v1", + "k2": "v2", + } + m2 := g.MapStrStr{} + t.Assert(gvar.New(m1).MapToMap(&m2), nil) + t.Assert(m2["k1"], m1["k1"]) + t.Assert(m2["k2"], m1["k2"]) + }) + // map[string]string -> map[string]interface{} + gtest.C(t, func(t *gtest.T) { + m1 := g.MapStrStr{ + "k1": "v1", + "k2": "v2", + } + m2 := g.Map{} + t.Assert(gvar.New(m1).MapToMap(&m2), nil) + t.Assert(m2["k1"], m1["k1"]) + t.Assert(m2["k2"], m1["k2"]) + }) + // map[string]interface{} -> map[interface{}]interface{} + gtest.C(t, func(t *gtest.T) { + m1 := g.MapStrStr{ + "k1": "v1", + "k2": "v2", + } + m2 := g.MapAnyAny{} + t.Assert(gvar.New(m1).MapToMap(&m2), nil) + t.Assert(m2["k1"], m1["k1"]) + t.Assert(m2["k2"], m1["k2"]) + }) +} diff --git a/container/gvar/gvar_z_unit_struct_test.go b/container/gvar/gvar_z_unit_struct_test.go new file mode 100644 index 000000000..deb33d0c1 --- /dev/null +++ b/container/gvar/gvar_z_unit_struct_test.go @@ -0,0 +1,42 @@ +// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gvar_test + +import ( + "github.com/gogf/gf/container/gvar" + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/test/gtest" + "testing" +) + +func Test_Struct(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + type StTest struct { + Test int + } + + Kv := make(map[string]int, 1) + Kv["Test"] = 100 + + testObj := &StTest{} + + objOne := gvar.New(Kv, true) + + objOne.Struct(testObj) + + t.Assert(testObj.Test, Kv["Test"]) + }) + gtest.C(t, func(t *gtest.T) { + type StTest struct { + Test int8 + } + o := &StTest{} + v := gvar.New(g.Slice{"Test", "-25"}) + v.Struct(o) + t.Assert(o.Test, -25) + }) +} diff --git a/encoding/gjson/gjson_api.go b/encoding/gjson/gjson_api.go index 8f00f1084..6df82414d 100644 --- a/encoding/gjson/gjson_api.go +++ b/encoding/gjson/gjson_api.go @@ -35,8 +35,8 @@ func (j *Json) IsNil() bool { // It returns all values of current Json object if is given empty or string ".". // It returns nil if no value found by . // -// We can also access slice item by its index number in , -// eg: "items.name.first", "list.10". +// We can also access slice item by its index number in like: +// "list.10", "array.0.name", "array.0.1.id". // // It returns a default value specified by if value for is not found. func (j *Json) Get(pattern string, def ...interface{}) interface{} { @@ -78,8 +78,7 @@ func (j *Json) GetVars(pattern string, def ...interface{}) []*gvar.Var { return gvar.New(j.Get(pattern, def...)).Vars() } -// GetMap retrieves the value by specified , -// and converts it to map[string]interface{}. +// GetMap retrieves and returns the value by specified as map[string]interface{}. func (j *Json) GetMap(pattern string, def ...interface{}) map[string]interface{} { result := j.Get(pattern, def...) if result != nil { @@ -88,8 +87,7 @@ func (j *Json) GetMap(pattern string, def ...interface{}) map[string]interface{} return nil } -// GetMapStrStr retrieves the value by specified , -// and converts it to map[string]string. +// GetMapStrStr retrieves and returns the value by specified as map[string]string. func (j *Json) GetMapStrStr(pattern string, def ...interface{}) map[string]string { result := j.Get(pattern, def...) if result != nil { @@ -98,6 +96,15 @@ func (j *Json) GetMapStrStr(pattern string, def ...interface{}) map[string]strin return nil } +// GetMaps retrieves and returns the value by specified as []map[string]interface{}. +func (j *Json) GetMaps(pattern string, def ...interface{}) []map[string]interface{} { + result := j.Get(pattern, def...) + if result != nil { + return gconv.Maps(result) + } + return nil +} + // GetJson gets the value by specified , // and converts it to a un-concurrent-safe Json object. func (j *Json) GetJson(pattern string, def ...interface{}) *Json { @@ -323,25 +330,28 @@ func (j *Json) GetStructsDeep(pattern string, pointer interface{}, mapping ...ma } // GetMapToMap retrieves the value by specified and converts it specified map variable. -// The parameter of should be type of *map. +// See gconv.MapToMap. func (j *Json) GetMapToMap(pattern string, pointer interface{}, mapping ...map[string]string) error { return gconv.MapToMap(j.Get(pattern), pointer, mapping...) } // GetMapToMapDeep retrieves the value by specified and converts it specified map -// variable recursively. The parameter of should be type of *map. +// variable recursively. +// See gconv.MapToMapDeep. func (j *Json) GetMapToMapDeep(pattern string, pointer interface{}, mapping ...map[string]string) error { return gconv.MapToMapDeep(j.Get(pattern), pointer, mapping...) } // GetMapToMaps retrieves the value by specified and converts it specified map slice -// variable. The parameter of should be type of []map/*map. +// variable. +// See gconv.MapToMaps. func (j *Json) GetMapToMaps(pattern string, pointer interface{}, mapping ...map[string]string) error { return gconv.MapToMaps(j.Get(pattern), pointer, mapping...) } // GetMapToMapsDeep retrieves the value by specified and converts it specified map slice -// variable recursively. The parameter of should be type of []map/*map. +// variable recursively. +// See gconv.MapToMapsDeep. func (j *Json) GetMapToMapsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error { return gconv.MapToMapsDeep(j.Get(pattern), pointer, mapping...) } diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index a5ba1047a..686165f60 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -9,6 +9,7 @@ package gconv import ( "encoding/json" "errors" + "github.com/gogf/gf/errors/gerror" "reflect" "strings" @@ -291,21 +292,31 @@ func MapStrStrDeep(value interface{}, tags ...string) map[string]string { return nil } -// MapToMap converts map type variable to another map type variable using reflect. -// The parameter of should be type of *map. +// MapToMap converts map type variable to another map type variable using +// reflect. +// See doMapToMap. func MapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) error { return doMapToMap(params, pointer, false, mapping...) } -// MapToMapDeep recursively converts map type variable to another map type variable using reflect. -// The elements of should be type of *map. +// MapToMapDeep converts map type variable to another map type variable using +// reflect recursively. +// See doMapToMap. func MapToMapDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error { return doMapToMap(params, pointer, true, mapping...) } // doMapToMap converts map type variable to another map type variable . -// The elements of should be type of *map. -func doMapToMap(params interface{}, pointer interface{}, deep bool, mapping ...map[string]string) error { +// +// The parameter can be any type of map, like: +// map[string]string, map[string]struct, , map[string]*struct, etc. +// +// The parameter should be type of *map, like: +// map[int]string, map[string]struct, , map[string]*struct, etc. +// +// The optional parameter is used for struct attribute to map key mapping, which makes +// sense only if the items of original map is type struct. +func doMapToMap(params interface{}, pointer interface{}, deep bool, mapping ...map[string]string) (err error) { var ( paramsRv = reflect.ValueOf(params) paramsKind = paramsRv.Kind() @@ -317,6 +328,10 @@ func doMapToMap(params interface{}, pointer interface{}, deep bool, mapping ...m if paramsKind != reflect.Map { return errors.New("params should be type of map") } + // Empty params map, no need continue. + if paramsRv.Len() == 0 { + return nil + } var pointerRv reflect.Value if v, ok := pointer.(reflect.Value); ok { pointerRv = v @@ -329,28 +344,55 @@ func doMapToMap(params interface{}, pointer interface{}, deep bool, mapping ...m pointerKind = pointerRv.Kind() } if pointerKind != reflect.Map { - return errors.New("pointer should be type of map") + return errors.New("pointer should be type of *map") } + defer func() { + // Catch the panic, especially the reflect operation panics. + if e := recover(); e != nil { + err = gerror.NewfSkip(1, "%v", e) + } + }() var ( - err error paramsKeys = paramsRv.MapKeys() pointerKeyType = pointerRv.Type().Key() pointerValueType = pointerRv.Type().Elem() + pointerValueKind = pointerValueType.Kind() dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys)) ) + // Retrieve the true element type of target map. + if pointerValueKind == reflect.Ptr { + pointerValueKind = pointerValueType.Elem().Kind() + } for _, key := range paramsKeys { e := reflect.New(pointerValueType).Elem() - if deep { - if err = StructDeep(paramsRv.MapIndex(key).Interface(), e, mapping...); err != nil { - return err - } - } else { - if err = Struct(paramsRv.MapIndex(key).Interface(), e, mapping...); err != nil { - return err + switch pointerValueKind { + case reflect.Map, reflect.Struct: + if deep { + if err = StructDeep(paramsRv.MapIndex(key).Interface(), e, mapping...); err != nil { + return err + } + } else { + if err = Struct(paramsRv.MapIndex(key).Interface(), e, mapping...); err != nil { + return err + } } + default: + e.Set( + reflect.ValueOf( + Convert( + paramsRv.MapIndex(key).Interface(), + pointerValueType.String(), + ), + ), + ) } dataMap.SetMapIndex( - reflect.ValueOf(Convert(key.Interface(), pointerKeyType.Name())), + reflect.ValueOf( + Convert( + key.Interface(), + pointerKeyType.Name(), + ), + ), e, ) } @@ -359,20 +401,31 @@ func doMapToMap(params interface{}, pointer interface{}, deep bool, mapping ...m } // MapToMaps converts map type variable to another map type variable . -// The parameter of should be type of []map/*map. +// See doMapToMaps. func MapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) error { return doMapToMaps(params, pointer, false, mapping...) } -// MapToMapsDeep recursively converts map type variable to another map type variable . -// The parameter of should be type of []map/*map. +// MapToMapsDeep converts map type variable to another map type variable +// recursively. +// See doMapToMaps. func MapToMapsDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error { return doMapToMaps(params, pointer, true, mapping...) } // doMapToMaps converts map type variable to another map type variable . -// The parameter of should be type of []map/*map. -func doMapToMaps(params interface{}, pointer interface{}, deep bool, mapping ...map[string]string) error { +// +// The parameter can be any type of map, of which the item type is slice map, like: +// map[int][]map, map[string][]map. +// +// The parameter should be type of *map, of which the item type is slice map, like: +// map[string][]struct, map[string][]*struct. +// +// The optional parameter is used for struct attribute to map key mapping, which makes +// sense only if the items of original map is type struct. +// +// TODO it's supposed supporting target type like: map[int][]map, map[string][]map. +func doMapToMaps(params interface{}, pointer interface{}, deep bool, mapping ...map[string]string) (err error) { var ( paramsRv = reflect.ValueOf(params) paramsKind = paramsRv.Kind() @@ -384,6 +437,10 @@ func doMapToMaps(params interface{}, pointer interface{}, deep bool, mapping ... if paramsKind != reflect.Map { return errors.New("params should be type of map") } + // Empty params map, no need continue. + if paramsRv.Len() == 0 { + return nil + } var ( pointerRv = reflect.ValueOf(pointer) pointerKind = pointerRv.Kind() @@ -393,29 +450,39 @@ func doMapToMaps(params interface{}, pointer interface{}, deep bool, mapping ... pointerKind = pointerRv.Kind() } if pointerKind != reflect.Map { - return errors.New("pointer should be type of map") + return errors.New("pointer should be type of *map/**map") } + defer func() { + // Catch the panic, especially the reflect operation panics. + if e := recover(); e != nil { + err = gerror.NewfSkip(1, "%v", e) + } + }() var ( - err error paramsKeys = paramsRv.MapKeys() pointerKeyType = pointerRv.Type().Key() pointerValueType = pointerRv.Type().Elem() dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys)) ) for _, key := range paramsKeys { - e := reflect.New(pointerValueType).Elem().Addr() + e := reflect.New(pointerValueType).Elem() if deep { - if err = StructsDeep(paramsRv.MapIndex(key).Interface(), e, mapping...); err != nil { + if err = StructsDeep(paramsRv.MapIndex(key).Interface(), e.Addr(), mapping...); err != nil { return err } } else { - if err = Structs(paramsRv.MapIndex(key).Interface(), e, mapping...); err != nil { + if err = Structs(paramsRv.MapIndex(key).Interface(), e.Addr(), mapping...); err != nil { return err } } dataMap.SetMapIndex( - reflect.ValueOf(Convert(key.Interface(), pointerKeyType.Name())), - e.Elem(), + reflect.ValueOf( + Convert( + key.Interface(), + pointerKeyType.Name(), + ), + ), + e, ) } pointerRv.Set(dataMap) diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index af688194a..6f45ebb4c 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -1,4 +1,4 @@ -// Copyright 2017-2019 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, diff --git a/util/gconv/gconv_z_unit_map_test.go b/util/gconv/gconv_z_unit_map_test.go index d9d7a9aff..eca45d96b 100644 --- a/util/gconv/gconv_z_unit_map_test.go +++ b/util/gconv/gconv_z_unit_map_test.go @@ -55,6 +55,19 @@ func Test_Map_Slice(t *testing.T) { }) } +func Test_Maps(t *testing.T) { + params := g.Slice{ + g.Map{"id": 100, "name": "john"}, + g.Map{"id": 200, "name": "smith"}, + } + gtest.C(t, func(t *gtest.T) { + list := gconv.Maps(params) + t.Assert(len(list), 2) + t.Assert(list[0]["id"], 100) + t.Assert(list[1]["id"], 200) + }) +} + func Test_Map_StructWithGConvTag(t *testing.T) { gtest.C(t, func(t *gtest.T) { type User struct { @@ -294,295 +307,3 @@ func Test_MapDeepWithAttributeTag(t *testing.T) { t.Assert(m["base"].(map[string]interface{})["create_time"], user.CreateTime) }) } - -func Test_MapToMap(t *testing.T) { - type User struct { - Id int - Name string - } - params := g.Map{ - "key": g.Map{ - "id": 1, - "name": "john", - }, - } - gtest.C(t, func(t *gtest.T) { - m := make(map[string]User) - err := gconv.MapToMap(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 1) - t.Assert(m["key"].Id, 1) - t.Assert(m["key"].Name, "john") - }) - gtest.C(t, func(t *gtest.T) { - m := (map[string]User)(nil) - err := gconv.MapToMap(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 1) - t.Assert(m["key"].Id, 1) - t.Assert(m["key"].Name, "john") - }) - gtest.C(t, func(t *gtest.T) { - m := make(map[string]*User) - err := gconv.MapToMap(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 1) - t.Assert(m["key"].Id, 1) - t.Assert(m["key"].Name, "john") - }) - gtest.C(t, func(t *gtest.T) { - m := (map[string]*User)(nil) - err := gconv.MapToMap(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 1) - t.Assert(m["key"].Id, 1) - t.Assert(m["key"].Name, "john") - }) -} - -func Test_MapToMapDeep(t *testing.T) { - type Ids struct { - Id int - Uid int - } - type Base struct { - Ids - Time string - } - type User struct { - Base - Name string - } - params := g.Map{ - "key": g.Map{ - "id": 1, - "name": "john", - }, - } - gtest.C(t, func(t *gtest.T) { - m := (map[string]*User)(nil) - err := gconv.MapToMap(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 1) - t.Assert(m["key"].Id, 0) - t.Assert(m["key"].Name, "john") - }) - gtest.C(t, func(t *gtest.T) { - m := (map[string]*User)(nil) - err := gconv.MapToMapDeep(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 1) - t.Assert(m["key"].Id, 1) - t.Assert(m["key"].Name, "john") - }) -} - -func Test_MapToMaps1(t *testing.T) { - type User struct { - Id int - Name int - } - params := g.Map{ - "key1": g.Slice{ - g.Map{"id": 1, "name": "john"}, - g.Map{"id": 2, "name": "smith"}, - }, - "key2": g.Slice{ - g.Map{"id": 3, "name": "green"}, - g.Map{"id": 4, "name": "jim"}, - }, - } - gtest.C(t, func(t *gtest.T) { - m := make(map[string][]User) - err := gconv.MapToMaps(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m["key1"][0].Id, 1) - t.Assert(m["key1"][1].Id, 2) - t.Assert(m["key2"][0].Id, 3) - t.Assert(m["key2"][1].Id, 4) - }) - gtest.C(t, func(t *gtest.T) { - m := (map[string][]User)(nil) - err := gconv.MapToMaps(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m["key1"][0].Id, 1) - t.Assert(m["key1"][1].Id, 2) - t.Assert(m["key2"][0].Id, 3) - t.Assert(m["key2"][1].Id, 4) - }) - gtest.C(t, func(t *gtest.T) { - m := make(map[string][]*User) - err := gconv.MapToMaps(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m["key1"][0].Id, 1) - t.Assert(m["key1"][1].Id, 2) - t.Assert(m["key2"][0].Id, 3) - t.Assert(m["key2"][1].Id, 4) - }) - gtest.C(t, func(t *gtest.T) { - m := (map[string][]*User)(nil) - err := gconv.MapToMaps(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m["key1"][0].Id, 1) - t.Assert(m["key1"][1].Id, 2) - t.Assert(m["key2"][0].Id, 3) - t.Assert(m["key2"][1].Id, 4) - }) -} - -func Test_MapToMaps2(t *testing.T) { - type User struct { - Id int - Name int - } - params := g.MapIntAny{ - 100: g.Slice{ - g.Map{"id": 1, "name": "john"}, - g.Map{"id": 2, "name": "smith"}, - }, - 200: g.Slice{ - g.Map{"id": 3, "name": "green"}, - g.Map{"id": 4, "name": "jim"}, - }, - } - gtest.C(t, func(t *gtest.T) { - m := make(map[int][]User) - err := gconv.MapToMaps(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m[100][0].Id, 1) - t.Assert(m[100][1].Id, 2) - t.Assert(m[200][0].Id, 3) - t.Assert(m[200][1].Id, 4) - }) - gtest.C(t, func(t *gtest.T) { - m := make(map[int][]*User) - err := gconv.MapToMaps(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m[100][0].Id, 1) - t.Assert(m[100][1].Id, 2) - t.Assert(m[200][0].Id, 3) - t.Assert(m[200][1].Id, 4) - }) - gtest.C(t, func(t *gtest.T) { - m := make(map[string][]*User) - err := gconv.MapToMaps(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m["100"][0].Id, 1) - t.Assert(m["100"][1].Id, 2) - t.Assert(m["200"][0].Id, 3) - t.Assert(m["200"][1].Id, 4) - }) -} - -func Test_MapToMapsDeep(t *testing.T) { - type Ids struct { - Id int - Uid int - } - type Base struct { - Ids - Time string - } - type User struct { - Base - Name string - } - params := g.MapIntAny{ - 100: g.Slice{ - g.Map{"id": 1, "name": "john"}, - g.Map{"id": 2, "name": "smith"}, - }, - 200: g.Slice{ - g.Map{"id": 3, "name": "green"}, - g.Map{"id": 4, "name": "jim"}, - }, - } - gtest.C(t, func(t *gtest.T) { - m := make(map[string][]*User) - err := gconv.MapToMaps(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m["100"][0].Id, 0) - t.Assert(m["100"][1].Id, 0) - t.Assert(m["100"][0].Name, "john") - t.Assert(m["100"][1].Name, "smith") - t.Assert(m["200"][0].Id, 0) - t.Assert(m["200"][1].Id, 0) - t.Assert(m["200"][0].Name, "green") - t.Assert(m["200"][1].Name, "jim") - }) - gtest.C(t, func(t *gtest.T) { - m := make(map[string][]*User) - err := gconv.MapToMapsDeep(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m["100"][0].Id, 1) - t.Assert(m["100"][1].Id, 2) - t.Assert(m["100"][0].Name, "john") - t.Assert(m["100"][1].Name, "smith") - t.Assert(m["200"][0].Id, 3) - t.Assert(m["200"][1].Id, 4) - t.Assert(m["200"][0].Name, "green") - t.Assert(m["200"][1].Name, "jim") - }) -} - -func Test_MapToMapsDeepWithTag(t *testing.T) { - type Ids struct { - Id int - Uid int - } - type Base struct { - Ids `json:"ids"` - Time string - } - type User struct { - Base `json:"base"` - Name string - } - params := g.MapIntAny{ - 100: g.Slice{ - g.Map{"id": 1, "name": "john"}, - g.Map{"id": 2, "name": "smith"}, - }, - 200: g.Slice{ - g.Map{"id": 3, "name": "green"}, - g.Map{"id": 4, "name": "jim"}, - }, - } - gtest.C(t, func(t *gtest.T) { - m := make(map[string][]*User) - err := gconv.MapToMaps(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m["100"][0].Id, 0) - t.Assert(m["100"][1].Id, 0) - t.Assert(m["100"][0].Name, "john") - t.Assert(m["100"][1].Name, "smith") - t.Assert(m["200"][0].Id, 0) - t.Assert(m["200"][1].Id, 0) - t.Assert(m["200"][0].Name, "green") - t.Assert(m["200"][1].Name, "jim") - }) - gtest.C(t, func(t *gtest.T) { - m := make(map[string][]*User) - err := gconv.MapToMapsDeep(params, &m) - t.Assert(err, nil) - t.Assert(len(m), 2) - t.Assert(m["100"][0].Id, 1) - t.Assert(m["100"][1].Id, 2) - t.Assert(m["100"][0].Name, "john") - t.Assert(m["100"][1].Name, "smith") - t.Assert(m["200"][0].Id, 3) - t.Assert(m["200"][1].Id, 4) - t.Assert(m["200"][0].Name, "green") - t.Assert(m["200"][1].Name, "jim") - }) -} diff --git a/util/gconv/gconv_z_unit_maptomap_test.go b/util/gconv/gconv_z_unit_maptomap_test.go new file mode 100644 index 000000000..eeb82d52e --- /dev/null +++ b/util/gconv/gconv_z_unit_maptomap_test.go @@ -0,0 +1,362 @@ +// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv_test + +import ( + "testing" + + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/test/gtest" + "github.com/gogf/gf/util/gconv" +) + +func Test_MapToMap1(t *testing.T) { + // map[int]int -> map[string]string + // empty original map. + gtest.C(t, func(t *gtest.T) { + m1 := g.MapIntInt{} + m2 := g.MapStrStr{} + t.Assert(gconv.MapToMap(m1, &m2), nil) + t.Assert(len(m1), len(m2)) + }) + // map[int]int -> map[string]string + gtest.C(t, func(t *gtest.T) { + m1 := g.MapIntInt{ + 1: 100, + 2: 200, + } + m2 := g.MapStrStr{} + t.Assert(gconv.MapToMap(m1, &m2), nil) + t.Assert(m2["1"], m1[1]) + t.Assert(m2["2"], m1[2]) + }) + // map[string]interface{} -> map[string]string + gtest.C(t, func(t *gtest.T) { + m1 := g.Map{ + "k1": "v1", + "k2": "v2", + } + m2 := g.MapStrStr{} + t.Assert(gconv.MapToMap(m1, &m2), nil) + t.Assert(m2["k1"], m1["k1"]) + t.Assert(m2["k2"], m1["k2"]) + }) + // map[string]string -> map[string]interface{} + gtest.C(t, func(t *gtest.T) { + m1 := g.MapStrStr{ + "k1": "v1", + "k2": "v2", + } + m2 := g.Map{} + t.Assert(gconv.MapToMap(m1, &m2), nil) + t.Assert(m2["k1"], m1["k1"]) + t.Assert(m2["k2"], m1["k2"]) + }) + // map[string]interface{} -> map[interface{}]interface{} + gtest.C(t, func(t *gtest.T) { + m1 := g.MapStrStr{ + "k1": "v1", + "k2": "v2", + } + m2 := g.MapAnyAny{} + t.Assert(gconv.MapToMap(m1, &m2), nil) + t.Assert(m2["k1"], m1["k1"]) + t.Assert(m2["k2"], m1["k2"]) + }) +} + +func Test_MapToMap2(t *testing.T) { + type User struct { + Id int + Name string + } + params := g.Map{ + "key": g.Map{ + "id": 1, + "name": "john", + }, + } + gtest.C(t, func(t *gtest.T) { + m := make(map[string]User) + err := gconv.MapToMap(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 1) + t.Assert(m["key"].Id, 1) + t.Assert(m["key"].Name, "john") + }) + gtest.C(t, func(t *gtest.T) { + m := (map[string]User)(nil) + err := gconv.MapToMap(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 1) + t.Assert(m["key"].Id, 1) + t.Assert(m["key"].Name, "john") + }) + gtest.C(t, func(t *gtest.T) { + m := make(map[string]*User) + err := gconv.MapToMap(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 1) + t.Assert(m["key"].Id, 1) + t.Assert(m["key"].Name, "john") + }) + gtest.C(t, func(t *gtest.T) { + m := (map[string]*User)(nil) + err := gconv.MapToMap(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 1) + t.Assert(m["key"].Id, 1) + t.Assert(m["key"].Name, "john") + }) +} + +func Test_MapToMapDeep(t *testing.T) { + type Ids struct { + Id int + Uid int + } + type Base struct { + Ids + Time string + } + type User struct { + Base + Name string + } + params := g.Map{ + "key": g.Map{ + "id": 1, + "name": "john", + }, + } + gtest.C(t, func(t *gtest.T) { + m := (map[string]*User)(nil) + err := gconv.MapToMap(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 1) + t.Assert(m["key"].Id, 0) + t.Assert(m["key"].Name, "john") + }) + gtest.C(t, func(t *gtest.T) { + m := (map[string]*User)(nil) + err := gconv.MapToMapDeep(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 1) + t.Assert(m["key"].Id, 1) + t.Assert(m["key"].Name, "john") + }) +} + +func Test_MapToMaps1(t *testing.T) { + type User struct { + Id int + Name int + } + params := g.Map{ + "key1": g.Slice{ + g.Map{"id": 1, "name": "john"}, + g.Map{"id": 2, "name": "smith"}, + }, + "key2": g.Slice{ + g.Map{"id": 3, "name": "green"}, + g.Map{"id": 4, "name": "jim"}, + }, + } + gtest.C(t, func(t *gtest.T) { + m := make(map[string][]User) + err := gconv.MapToMaps(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m["key1"][0].Id, 1) + t.Assert(m["key1"][1].Id, 2) + t.Assert(m["key2"][0].Id, 3) + t.Assert(m["key2"][1].Id, 4) + }) + gtest.C(t, func(t *gtest.T) { + m := (map[string][]User)(nil) + err := gconv.MapToMaps(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m["key1"][0].Id, 1) + t.Assert(m["key1"][1].Id, 2) + t.Assert(m["key2"][0].Id, 3) + t.Assert(m["key2"][1].Id, 4) + }) + gtest.C(t, func(t *gtest.T) { + m := make(map[string][]*User) + err := gconv.MapToMaps(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m["key1"][0].Id, 1) + t.Assert(m["key1"][1].Id, 2) + t.Assert(m["key2"][0].Id, 3) + t.Assert(m["key2"][1].Id, 4) + }) + gtest.C(t, func(t *gtest.T) { + m := (map[string][]*User)(nil) + err := gconv.MapToMaps(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m["key1"][0].Id, 1) + t.Assert(m["key1"][1].Id, 2) + t.Assert(m["key2"][0].Id, 3) + t.Assert(m["key2"][1].Id, 4) + }) +} + +func Test_MapToMaps2(t *testing.T) { + type User struct { + Id int + Name int + } + params := g.MapIntAny{ + 100: g.Slice{ + g.Map{"id": 1, "name": "john"}, + g.Map{"id": 2, "name": "smith"}, + }, + 200: g.Slice{ + g.Map{"id": 3, "name": "green"}, + g.Map{"id": 4, "name": "jim"}, + }, + } + gtest.C(t, func(t *gtest.T) { + m := make(map[int][]User) + err := gconv.MapToMaps(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m[100][0].Id, 1) + t.Assert(m[100][1].Id, 2) + t.Assert(m[200][0].Id, 3) + t.Assert(m[200][1].Id, 4) + }) + gtest.C(t, func(t *gtest.T) { + m := make(map[int][]*User) + err := gconv.MapToMaps(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m[100][0].Id, 1) + t.Assert(m[100][1].Id, 2) + t.Assert(m[200][0].Id, 3) + t.Assert(m[200][1].Id, 4) + }) + gtest.C(t, func(t *gtest.T) { + m := make(map[string][]*User) + err := gconv.MapToMaps(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m["100"][0].Id, 1) + t.Assert(m["100"][1].Id, 2) + t.Assert(m["200"][0].Id, 3) + t.Assert(m["200"][1].Id, 4) + }) +} + +func Test_MapToMapsDeep(t *testing.T) { + type Ids struct { + Id int + Uid int + } + type Base struct { + Ids + Time string + } + type User struct { + Base + Name string + } + params := g.MapIntAny{ + 100: g.Slice{ + g.Map{"id": 1, "name": "john"}, + g.Map{"id": 2, "name": "smith"}, + }, + 200: g.Slice{ + g.Map{"id": 3, "name": "green"}, + g.Map{"id": 4, "name": "jim"}, + }, + } + gtest.C(t, func(t *gtest.T) { + m := make(map[string][]*User) + err := gconv.MapToMaps(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m["100"][0].Id, 0) + t.Assert(m["100"][1].Id, 0) + t.Assert(m["100"][0].Name, "john") + t.Assert(m["100"][1].Name, "smith") + t.Assert(m["200"][0].Id, 0) + t.Assert(m["200"][1].Id, 0) + t.Assert(m["200"][0].Name, "green") + t.Assert(m["200"][1].Name, "jim") + }) + gtest.C(t, func(t *gtest.T) { + m := make(map[string][]*User) + err := gconv.MapToMapsDeep(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m["100"][0].Id, 1) + t.Assert(m["100"][1].Id, 2) + t.Assert(m["100"][0].Name, "john") + t.Assert(m["100"][1].Name, "smith") + t.Assert(m["200"][0].Id, 3) + t.Assert(m["200"][1].Id, 4) + t.Assert(m["200"][0].Name, "green") + t.Assert(m["200"][1].Name, "jim") + }) +} + +func Test_MapToMapsDeepWithTag(t *testing.T) { + type Ids struct { + Id int + Uid int + } + type Base struct { + Ids `json:"ids"` + Time string + } + type User struct { + Base `json:"base"` + Name string + } + params := g.MapIntAny{ + 100: g.Slice{ + g.Map{"id": 1, "name": "john"}, + g.Map{"id": 2, "name": "smith"}, + }, + 200: g.Slice{ + g.Map{"id": 3, "name": "green"}, + g.Map{"id": 4, "name": "jim"}, + }, + } + gtest.C(t, func(t *gtest.T) { + m := make(map[string][]*User) + err := gconv.MapToMaps(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m["100"][0].Id, 0) + t.Assert(m["100"][1].Id, 0) + t.Assert(m["100"][0].Name, "john") + t.Assert(m["100"][1].Name, "smith") + t.Assert(m["200"][0].Id, 0) + t.Assert(m["200"][1].Id, 0) + t.Assert(m["200"][0].Name, "green") + t.Assert(m["200"][1].Name, "jim") + }) + gtest.C(t, func(t *gtest.T) { + m := make(map[string][]*User) + err := gconv.MapToMapsDeep(params, &m) + t.Assert(err, nil) + t.Assert(len(m), 2) + t.Assert(m["100"][0].Id, 1) + t.Assert(m["100"][1].Id, 2) + t.Assert(m["100"][0].Name, "john") + t.Assert(m["100"][1].Name, "smith") + t.Assert(m["200"][0].Id, 3) + t.Assert(m["200"][1].Id, 4) + t.Assert(m["200"][0].Name, "green") + t.Assert(m["200"][1].Name, "jim") + }) +}