Skip to content

Commit

Permalink
fix(util/gconv): one parameter to same tag in multiple struct attribu…
Browse files Browse the repository at this point in the history
…tes mapping failed (#3822)
  • Loading branch information
helloteemo authored Oct 14, 2024
1 parent 4b5f637 commit 5288b70
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 24 deletions.
50 changes: 50 additions & 0 deletions util/gconv/gconv_z_unit_issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -707,3 +707,53 @@ func doTestIssue3800(t *testing.T) {
t.Assert(structL.StructA.UpdatedTick, structK.Master.UpdatedTick)
})
}

// https:/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))
})
}
58 changes: 34 additions & 24 deletions util/gconv/internal/structcache/structcache_cached_struct_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
tagOrFieldNameArray := csi.genPriorityTagAndFieldName(field, priorityTags)
for _, tagOrFieldName := range tagOrFieldNameArray {
cachedFieldInfo, found := csi.tagOrFiledNameToFieldInfoMap[tagOrFieldName]
newFieldInfo := csi.makeOrCopyCachedInfo(
field, fieldIndexes, priorityTags, cachedFieldInfo, tagOrFieldName,
)
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 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),
)
return
}

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)
}
// If the types are different, some information needs to be reset
alreadyExistFieldInfo.OtherSameNameField = append(
alreadyExistFieldInfo.OtherSameNameField,
csi.makeCachedFieldInfo(field, fieldIndexes, priorityTags),
)
newFieldInfo.IsField = currTagOrFieldName == field.Name
return
}

// copyCachedInfoWithFieldIndexes copies and returns a new CachedFieldInfo based on given CachedFieldInfo, but different
Expand Down

0 comments on commit 5288b70

Please sign in to comment.