mirror of
https://gitee.com/johng/gf
synced 2026-07-04 21:03:13 +08:00
fix(util/gconv): one parameter to same tag in multiple struct attributes mapping failed (#3822)
This commit is contained in:
@ -707,3 +707,53 @@ func doTestIssue3800(t *testing.T) {
|
||||
t.Assert(structL.StructA.UpdatedTick, structK.Master.UpdatedTick)
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/3821
|
||||
func Test_Issue3821(t *testing.T) {
|
||||
// Scan
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var record = map[string]interface{}{
|
||||
`user_id`: 1,
|
||||
`user_name`: "teemo",
|
||||
}
|
||||
|
||||
type DoubleInnerUser struct {
|
||||
UserId int64 `orm:"user_id"`
|
||||
}
|
||||
|
||||
type InnerUser struct {
|
||||
UserId int32 `orm:"user_id"`
|
||||
UserIdBool bool `orm:"user_id"`
|
||||
Username *string `orm:"user_name"`
|
||||
Username2 *string `orm:"user_name"`
|
||||
Username3 string `orm:"username"`
|
||||
*DoubleInnerUser
|
||||
}
|
||||
|
||||
type User struct {
|
||||
InnerUser
|
||||
UserId int `orm:"user_id"`
|
||||
UserIdBool gtype.Bool `orm:"user_id"`
|
||||
Username string `orm:"user_name"`
|
||||
Username2 string `orm:"user_name"`
|
||||
Username3 *string `orm:"user_name"`
|
||||
Username4 string `orm:"username"` // empty string
|
||||
}
|
||||
var user = &User{}
|
||||
err := gconv.StructTag(record, user, "orm")
|
||||
|
||||
t.AssertNil(err)
|
||||
t.AssertEQ(user.UserId, 1)
|
||||
t.AssertEQ(user.UserIdBool.Val(), true)
|
||||
t.AssertEQ(user.Username, "teemo")
|
||||
t.AssertEQ(user.Username2, "teemo")
|
||||
t.AssertEQ(*user.Username3, "teemo")
|
||||
t.AssertEQ(user.Username4, "")
|
||||
t.AssertEQ(user.InnerUser.UserId, int32(1))
|
||||
t.AssertEQ(user.InnerUser.UserIdBool, true)
|
||||
t.AssertEQ(*user.InnerUser.Username, "teemo")
|
||||
t.AssertEQ(*user.InnerUser.Username2, "teemo")
|
||||
t.AssertEQ(user.InnerUser.Username3, "")
|
||||
t.AssertEQ(user.DoubleInnerUser.UserId, int64(1))
|
||||
})
|
||||
}
|
||||
|
||||
@ -39,34 +39,44 @@ func (csi *CachedStructInfo) GetFieldInfo(fieldName string) *CachedFieldInfo {
|
||||
}
|
||||
|
||||
func (csi *CachedStructInfo) AddField(field reflect.StructField, fieldIndexes []int, priorityTags []string) {
|
||||
alreadyExistFieldInfo, ok := csi.tagOrFiledNameToFieldInfoMap[field.Name]
|
||||
if !ok {
|
||||
cachedFieldInfo := csi.makeCachedFieldInfo(field, fieldIndexes, priorityTags)
|
||||
for _, tagOrFieldName := range cachedFieldInfo.PriorityTagAndFieldName {
|
||||
newFieldInfo := &CachedFieldInfo{
|
||||
CachedFieldInfoBase: cachedFieldInfo.CachedFieldInfoBase,
|
||||
IsField: tagOrFieldName == field.Name,
|
||||
}
|
||||
csi.tagOrFiledNameToFieldInfoMap[tagOrFieldName] = newFieldInfo
|
||||
if newFieldInfo.IsField {
|
||||
csi.FieldConvertInfos = append(csi.FieldConvertInfos, newFieldInfo)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// If the field name and type are the same
|
||||
if alreadyExistFieldInfo.StructField.Type == field.Type {
|
||||
alreadyExistFieldInfo.OtherSameNameField = append(
|
||||
alreadyExistFieldInfo.OtherSameNameField,
|
||||
csi.copyCachedInfoWithFieldIndexes(alreadyExistFieldInfo, fieldIndexes),
|
||||
tagOrFieldNameArray := csi.genPriorityTagAndFieldName(field, priorityTags)
|
||||
for _, tagOrFieldName := range tagOrFieldNameArray {
|
||||
cachedFieldInfo, found := csi.tagOrFiledNameToFieldInfoMap[tagOrFieldName]
|
||||
newFieldInfo := csi.makeOrCopyCachedInfo(
|
||||
field, fieldIndexes, priorityTags, cachedFieldInfo, tagOrFieldName,
|
||||
)
|
||||
return
|
||||
if newFieldInfo.IsField {
|
||||
csi.FieldConvertInfos = append(csi.FieldConvertInfos, newFieldInfo)
|
||||
}
|
||||
// if the field info by `tagOrFieldName` already cached,
|
||||
// it so adds this new field info to other same name field.
|
||||
if found {
|
||||
cachedFieldInfo.OtherSameNameField = append(cachedFieldInfo.OtherSameNameField, newFieldInfo)
|
||||
} else {
|
||||
csi.tagOrFiledNameToFieldInfoMap[tagOrFieldName] = newFieldInfo
|
||||
}
|
||||
}
|
||||
// If the types are different, some information needs to be reset
|
||||
alreadyExistFieldInfo.OtherSameNameField = append(
|
||||
alreadyExistFieldInfo.OtherSameNameField,
|
||||
csi.makeCachedFieldInfo(field, fieldIndexes, priorityTags),
|
||||
)
|
||||
}
|
||||
|
||||
func (csi *CachedStructInfo) makeOrCopyCachedInfo(
|
||||
field reflect.StructField,
|
||||
fieldIndexes []int,
|
||||
priorityTags []string,
|
||||
cachedFieldInfo *CachedFieldInfo,
|
||||
currTagOrFieldName string,
|
||||
) (newFieldInfo *CachedFieldInfo) {
|
||||
if cachedFieldInfo == nil {
|
||||
// If the field is not cached, it creates a new one.
|
||||
newFieldInfo = csi.makeCachedFieldInfo(field, fieldIndexes, priorityTags)
|
||||
} else if cachedFieldInfo.StructField.Type != field.Type {
|
||||
// If the types are different, some information needs to be reset.
|
||||
newFieldInfo = csi.makeCachedFieldInfo(field, fieldIndexes, priorityTags)
|
||||
} else {
|
||||
// If the field types are the same.
|
||||
newFieldInfo = csi.copyCachedInfoWithFieldIndexes(cachedFieldInfo, fieldIndexes)
|
||||
}
|
||||
newFieldInfo.IsField = currTagOrFieldName == field.Name
|
||||
return
|
||||
}
|
||||
|
||||
// copyCachedInfoWithFieldIndexes copies and returns a new CachedFieldInfo based on given CachedFieldInfo, but different
|
||||
|
||||
Reference in New Issue
Block a user