fix issue in custom mapping for gconv.Struct

This commit is contained in:
Jack
2020-11-19 14:52:19 +08:00
parent baf51bc68f
commit 24a377d3a8
4 changed files with 97 additions and 32 deletions

View File

@ -9,6 +9,7 @@ package gdb
import (
"fmt"
"github.com/go-sql-driver/mysql"
"github.com/gogf/gf/container/gvar"
"github.com/gogf/gf/os/gcmd"
"github.com/gogf/gf/os/gtime"
"github.com/gogf/gf/test/gtest"
@ -312,3 +313,26 @@ func Test_isSubQuery(t *testing.T) {
t.Assert(isSubQuery("select 1"), true)
})
}
func TestResult_Structs1(t *testing.T) {
type A struct {
Id int `orm:"id"`
}
type B struct {
*A
Name string
}
gtest.C(t, func(t *gtest.T) {
r := Result{
Record{"id": gvar.New(nil), "name": gvar.New("john")},
Record{"id": gvar.New(nil), "name": gvar.New("smith")},
}
array := make([]*B, 2)
err := r.Structs(&array)
t.Assert(err, nil)
t.Assert(array[0].Id, 0)
t.Assert(array[1].Id, 0)
t.Assert(array[0].Name, "john")
t.Assert(array[1].Name, "smith")
})
}

View File

@ -148,18 +148,6 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
// doneMap is used to check repeated converting, its key is the real attribute name
// of the struct.
doneMap := make(map[string]struct{})
// It first checks the passed mapping rules.
if len(mapping) > 0 && len(mapping[0]) > 0 {
for mapK, mapV := range mapping[0] {
// mapV is the the attribute name of the struct.
if paramV, ok := paramsMap[mapK]; ok {
doneMap[mapV] = struct{}{}
if err := bindVarToStructAttr(elem, mapV, paramV, mapping...); err != nil {
return err
}
}
}
}
// The key of the attrMap is the attribute name of the struct,
// and the value is its replaced name for later comparison to improve performance.
@ -176,7 +164,7 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
if !utils.IsLetterUpper(elemFieldType.Name[0]) {
continue
}
// Maybe it's struct/*struct.
// Maybe it's struct/*struct embedded.
if elemFieldType.Anonymous {
elemFieldValue = elem.Field(i)
// Ignore the interface attribute if it's nil.
@ -215,35 +203,43 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
)
for mapK, mapV := range paramsMap {
attrName = ""
checkName = utils.RemoveSymbols(mapK)
// Loop to find the matched attribute name with or without
// string cases and chars like '-'/'_'/'.'/' '.
// Matching the parameters to struct tag names.
// The <tagV> is the attribute name of the struct.
for attrKey, cmpKey := range tagMap {
if strings.EqualFold(checkName, cmpKey) {
attrName = attrKey
break
// It firstly checks the passed mapping rules.
if len(mapping) > 0 && len(mapping[0]) > 0 {
if passedAttrKey, ok := mapping[0][mapK]; ok {
attrName = passedAttrKey
}
}
// Matching the parameters to struct attributes.
// It secondly checks the predefined tags and matching rules.
if attrName == "" {
for attrKey, cmpKey := range attrMap {
// Eg:
// UserName eq user_name
// User-Name eq username
// username eq userName
// etc.
checkName = utils.RemoveSymbols(mapK)
// Loop to find the matched attribute name with or without
// string cases and chars like '-'/'_'/'.'/' '.
// Matching the parameters to struct tag names.
// The <tagV> is the attribute name of the struct.
for attrKey, cmpKey := range tagMap {
if strings.EqualFold(checkName, cmpKey) {
attrName = attrKey
break
}
}
// Matching the parameters to struct attributes.
if attrName == "" {
for attrKey, cmpKey := range attrMap {
// Eg:
// UserName eq user_name
// User-Name eq username
// username eq userName
// etc.
if strings.EqualFold(checkName, cmpKey) {
attrName = attrKey
break
}
}
}
}
// No matching, give up this attribute converting.
// No matching, it gives up this attribute converting.
if attrName == "" {
continue
}

View File

@ -174,3 +174,26 @@ func Test_Structs_DirectReflectSet(t *testing.T) {
t.AssertEQ(a, b)
})
}
func Test_Structs_SliceIntAttribute(t *testing.T) {
type A struct {
Id []int
}
type B struct {
*A
Name string
}
gtest.C(t, func(t *gtest.T) {
var (
array []*B
)
err := gconv.Structs(g.Slice{
g.Map{"id": nil, "name": "john"},
g.Map{"id": nil, "name": "smith"},
}, &array)
t.Assert(err, nil)
t.Assert(len(array), 2)
t.Assert(array[0].Name, "john")
t.Assert(array[1].Name, "smith")
})
}

View File

@ -1035,3 +1035,25 @@ func Test_Struct_DirectReflectSet(t *testing.T) {
t.AssertEQ(a, b)
})
}
func Test_Struct_NilEmbeddedStructAttribute(t *testing.T) {
type A struct {
Name string
}
type B struct {
*A
Id int
}
gtest.C(t, func(t *gtest.T) {
var (
b *B
)
err := gconv.Struct(g.Map{
"id": 1,
"name": nil,
}, &b)
t.Assert(err, nil)
g.Dump(b)
})
}