mirror of
https://gitee.com/johng/gf
synced 2026-07-06 13:42:46 +08:00
fix issue in custom mapping for gconv.Struct
This commit is contained in:
@ -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")
|
||||
})
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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")
|
||||
})
|
||||
}
|
||||
|
||||
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user