Merge pull request #1546 from eh-steve/eh-steve/gconv-map-recurse

Recurse map fields inside structs
This commit is contained in:
John Guo 2022-01-12 20:01:31 +08:00 committed by GitHub
commit 0534994fa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 83 additions and 1 deletions

View File

@ -323,7 +323,20 @@ func doMapConvertForMapOrStructValue(isRoot bool, value interface{}, recursive b
array[i] = doMapConvertForMapOrStructValue(false, rvAttrField.Index(i), recursive, tags...)
}
dataMap[mapKey] = array
case reflect.Map:
var (
mapKeys = rvAttrField.MapKeys()
nestedMap = make(map[string]interface{})
)
for _, k := range mapKeys {
nestedMap[String(k.Interface())] = doMapConvertForMapOrStructValue(
false,
rvAttrField.MapIndex(k).Interface(),
recursive,
tags...,
)
}
dataMap[mapKey] = nestedMap
default:
if rvField.IsValid() {
dataMap[mapKey] = reflectValue.Field(i).Interface()

View File

@ -7,7 +7,9 @@
package gconv_test
import (
"encoding/json"
"github.com/gogf/gf/v2/util/gutil"
"gopkg.in/yaml.v3"
"testing"
"github.com/gogf/gf/v2/frame/g"
@ -407,3 +409,70 @@ func Test_MapDeepWithAttributeTag(t *testing.T) {
t.Assert(m["base"].(map[string]interface{})["create_time"], user.CreateTime)
})
}
func Test_MapDeepWithNestedMapAnyAny(t *testing.T) {
type User struct {
ExtraAttributes g.Map `c:"extra_attributes"`
}
gtest.C(t, func(t *gtest.T) {
user := &User{
ExtraAttributes: g.Map{
"simple_attribute": 123,
"map_string_attribute": g.Map{
"inner_value": 456,
},
"map_interface_attribute": g.MapAnyAny{
"inner_value": 456,
123: "integer_key_should_be_converted_to_string",
},
},
}
m := gconv.MapDeep(user)
t.Assert(m, g.Map{
"extra_attributes": g.Map{
"simple_attribute": 123,
"map_string_attribute": g.Map{
"inner_value": user.ExtraAttributes["map_string_attribute"].(g.Map)["inner_value"],
},
"map_interface_attribute": g.Map{
"inner_value": user.ExtraAttributes["map_interface_attribute"].(g.MapAnyAny)["inner_value"],
"123": "integer_key_should_be_converted_to_string",
},
},
})
})
type Outer struct {
OuterStruct map[string]interface{} `c:"outer_struct" yaml:"outer_struct"`
Field3 map[string]interface{} `c:"field3" yaml:"field3"`
}
gtest.C(t, func(t *gtest.T) {
problemYaml := []byte(`
outer_struct:
field1: &anchor1
inner1: 123
inner2: 345
field2:
inner3: 456
inner4: 789
<<: *anchor1
field3:
123: integer_key
`)
parsed := &Outer{}
err := yaml.Unmarshal(problemYaml, parsed)
t.Assert(err, nil)
_, err = json.Marshal(parsed)
t.Assert(err.Error(), "json: unsupported type: map[interface {}]interface {}")
converted := gconv.MapDeep(parsed)
jsonData, err := json.Marshal(converted)
t.Assert(err, nil)
t.Assert(string(jsonData), `{"field3":{"123":"integer_key"},"outer_struct":{"field1":{"inner1":123,"inner2":345},"field2":{"inner1":123,"inner2":345,"inner3":456,"inner4":789}}}`)
})
}