add function Maps for package gvar; add function GetMaps for package gjson; improve MapToMap* functions for package gconv

This commit is contained in:
John 2020-05-04 23:42:51 +08:00
parent 13e2353729
commit ec92b08f25
13 changed files with 807 additions and 513 deletions

View File

@ -235,100 +235,6 @@ func (v *Var) GTime(format ...string) *gtime.Time {
return gconv.GTime(v.Val(), format...)
}
// Map converts <v> to map[string]interface{}.
func (v *Var) Map(tags ...string) map[string]interface{} {
return gconv.Map(v.Val(), tags...)
}
// MapStrStr converts <v> to map[string]string.
func (v *Var) MapStrStr(tags ...string) map[string]string {
return gconv.MapStrStr(v.Val(), tags...)
}
// MapStrVar converts <v> 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 <v> to map[string]interface{} recursively.
func (v *Var) MapDeep(tags ...string) map[string]interface{} {
return gconv.MapDeep(v.Val(), tags...)
}
// MapDeep converts <v> to map[string]string recursively.
func (v *Var) MapStrStrDeep(tags ...string) map[string]string {
return gconv.MapStrStrDeep(v.Val(), tags...)
}
// MapStrVarDeep converts <v> 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 <v> to <pointer>.
// The parameter <pointer> should be a pointer to a struct instance.
// The parameter <mapping> 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 <v> to <pointer> recursively.
// The parameter <pointer> should be a pointer to a struct instance.
// The parameter <mapping> 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 <v> 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 <v> 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 <params> to another map type variable <pointer>.
// The elements of <pointer> 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 <params> to another map type variable <pointer>.
// The elements of <pointer> 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 <params> to another map type variable <pointer>.
// The elements of <pointer> 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 <params> to another map type variable <pointer>.
// The elements of <pointer> 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())

View File

@ -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 <v> as map[string]interface{}.
func (v *Var) Map(tags ...string) map[string]interface{} {
return gconv.Map(v.Val(), tags...)
}
// MapStrStr converts and returns <v> as map[string]string.
func (v *Var) MapStrStr(tags ...string) map[string]string {
return gconv.MapStrStr(v.Val(), tags...)
}
// MapStrVar converts and returns <v> 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 <v> as map[string]interface{} recursively.
func (v *Var) MapDeep(tags ...string) map[string]interface{} {
return gconv.MapDeep(v.Val(), tags...)
}
// MapDeep converts and returns <v> as map[string]string recursively.
func (v *Var) MapStrStrDeep(tags ...string) map[string]string {
return gconv.MapStrStrDeep(v.Val(), tags...)
}
// MapStrVarDeep converts and returns <v> 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 <v> 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 <params> to another map type variable <pointer>.
// See gconv.MapToMap.
func (v *Var) MapToMap(pointer interface{}) (err error) {
return gconv.MapToMap(v.Val(), pointer)
}
// MapToMapDeep converts map type variable <params> to another map type variable
// <pointer> recursively.
// See gconv.MapToMapDeep.
func (v *Var) MapToMapDeep(pointer interface{}) (err error) {
return gconv.MapToMapDeep(v.Val(), pointer)
}
// MapToMaps converts map type variable <params> to another map type variable <pointer>.
// 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 <params> to another map type variable
// <pointer> recursively.
// See gconv.MapToMapsDeep.
func (v *Var) MapToMapsDeep(pointer interface{}, mapping ...map[string]string) (err error) {
return gconv.MapToMapsDeep(v.Val(), pointer, mapping...)
}

View File

@ -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 <v> to <pointer>.
// The parameter <pointer> should be a pointer to a struct instance.
// The parameter <mapping> 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 <v> to <pointer> recursively.
// The parameter <pointer> should be a pointer to a struct instance.
// The parameter <mapping> 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 <v> 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 <v> as given struct slice recursively.
func (v *Var) StructsDeep(pointer interface{}, mapping ...map[string]string) (err error) {
return gconv.StructsDeep(v.Val(), pointer, mapping...)
}

View File

@ -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

View File

@ -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)
})
}

View File

@ -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"])
})
}

View File

@ -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"])
})
}

View File

@ -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)
})
}

View File

@ -35,8 +35,8 @@ func (j *Json) IsNil() bool {
// It returns all values of current Json object if <pattern> is given empty or string ".".
// It returns nil if no value found by <pattern>.
//
// We can also access slice item by its index number in <pattern>,
// eg: "items.name.first", "list.10".
// We can also access slice item by its index number in <pattern> like:
// "list.10", "array.0.name", "array.0.1.id".
//
// It returns a default value specified by <def> if value for <pattern> 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 <pattern>,
// and converts it to map[string]interface{}.
// GetMap retrieves and returns the value by specified <pattern> 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 <pattern>,
// and converts it to map[string]string.
// GetMapStrStr retrieves and returns the value by specified <pattern> 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 <pattern> 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 <pattern>,
// 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 <pattern> and converts it specified map variable.
// The parameter of <pointer> 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 <pattern> and converts it specified map
// variable recursively. The parameter of <pointer> 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 <pattern> and converts it specified map slice
// variable. The parameter of <pointer> 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 <pattern> and converts it specified map slice
// variable recursively. The parameter of <pointer> 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...)
}

View File

@ -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 <params> to another map type variable <pointer> using reflect.
// The parameter of <pointer> should be type of *map.
// MapToMap converts map type variable <params> to another map type variable <pointer> 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 <params> to another map type variable <pointer> using reflect.
// The elements of <pointer> should be type of *map.
// MapToMapDeep converts map type variable <params> to another map type variable <pointer> 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 <params> to another map type variable <pointer>.
// The elements of <pointer> should be type of *map.
func doMapToMap(params interface{}, pointer interface{}, deep bool, mapping ...map[string]string) error {
//
// The parameter <params> can be any type of map, like:
// map[string]string, map[string]struct, , map[string]*struct, etc.
//
// The parameter <pointer> should be type of *map, like:
// map[int]string, map[string]struct, , map[string]*struct, etc.
//
// The optional parameter <mapping> is used for struct attribute to map key mapping, which makes
// sense only if the items of original map <params> 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 <params> to another map type variable <pointer>.
// The parameter of <pointer> 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 <params> to another map type variable <pointer>.
// The parameter of <pointer> should be type of []map/*map.
// MapToMapsDeep converts map type variable <params> to another map type variable
// <pointer> 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 <params> to another map type variable <pointer>.
// The parameter of <pointer> should be type of []map/*map.
func doMapToMaps(params interface{}, pointer interface{}, deep bool, mapping ...map[string]string) error {
//
// The parameter <params> can be any type of map, of which the item type is slice map, like:
// map[int][]map, map[string][]map.
//
// The parameter <pointer> should be type of *map, of which the item type is slice map, like:
// map[string][]struct, map[string][]*struct.
//
// The optional parameter <mapping> 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 <pointer> 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)

View File

@ -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,

View File

@ -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")
})
}

View File

@ -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")
})
}