mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
improve package gconv
This commit is contained in:
@ -87,6 +87,7 @@ func TagFields(pointer interface{}, priority []string) ([]Field, error) {
|
||||
// Note that,
|
||||
// 1. It only retrieves the exported attributes with first letter up-case from struct.
|
||||
// 2. The parameter `priority` should be given, it only retrieves fields that has given tag.
|
||||
// 3. If one field has no specified tag, it uses its field name as result map key.
|
||||
func TagMapName(pointer interface{}, priority []string) (map[string]string, error) {
|
||||
fields, err := TagFields(pointer, priority)
|
||||
if err != nil {
|
||||
@ -94,7 +95,11 @@ func TagMapName(pointer interface{}, priority []string) (map[string]string, erro
|
||||
}
|
||||
tagMap := make(map[string]string, len(fields))
|
||||
for _, field := range fields {
|
||||
tagMap[field.TagValue] = field.Name()
|
||||
if field.TagValue == "" {
|
||||
tagMap[field.Name()] = field.Name()
|
||||
} else {
|
||||
tagMap[field.TagValue] = field.Name()
|
||||
}
|
||||
}
|
||||
return tagMap, nil
|
||||
}
|
||||
@ -105,6 +110,7 @@ func TagMapName(pointer interface{}, priority []string) (map[string]string, erro
|
||||
// Note that,
|
||||
// 1. It only retrieves the exported attributes with first letter up-case from struct.
|
||||
// 2. The parameter `priority` should be given, it only retrieves fields that has given tag.
|
||||
// 3. If one field has no specified tag, it uses its field name as result map key.
|
||||
func TagMapField(object interface{}, priority []string) (map[string]Field, error) {
|
||||
fields, err := TagFields(object, priority)
|
||||
if err != nil {
|
||||
@ -113,7 +119,11 @@ func TagMapField(object interface{}, priority []string) (map[string]Field, error
|
||||
tagMap := make(map[string]Field, len(fields))
|
||||
for _, field := range fields {
|
||||
tagField := field
|
||||
tagMap[field.TagValue] = tagField
|
||||
if field.TagValue == "" {
|
||||
tagMap[tagField.Name()] = tagField
|
||||
} else {
|
||||
tagMap[field.TagValue] = tagField
|
||||
}
|
||||
}
|
||||
return tagMap, nil
|
||||
}
|
||||
@ -174,7 +184,9 @@ exitLoop:
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
func getFieldValuesByTagPriority(pointer interface{}, priority []string, tagMap map[string]struct{}) ([]Field, error) {
|
||||
func getFieldValuesByTagPriority(
|
||||
pointer interface{}, priority []string, repeatedTagFilteringMap map[string]struct{},
|
||||
) ([]Field, error) {
|
||||
fields, err := getFieldValues(pointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -199,17 +211,18 @@ func getFieldValuesByTagPriority(pointer interface{}, priority []string, tagMap
|
||||
}
|
||||
if tagValue != "" {
|
||||
// Filter repeated tag.
|
||||
if _, ok := tagMap[tagValue]; ok {
|
||||
if _, ok := repeatedTagFilteringMap[tagValue]; ok {
|
||||
continue
|
||||
}
|
||||
tagField := field
|
||||
tagField.TagName = tagName
|
||||
tagField.TagValue = tagValue
|
||||
tagFields = append(tagFields, tagField)
|
||||
}
|
||||
tagField := field
|
||||
tagField.TagName = tagName
|
||||
tagField.TagValue = tagValue
|
||||
tagFields = append(tagFields, tagField)
|
||||
// If this is an embedded attribute, it retrieves the tags recursively.
|
||||
if field.IsEmbedded() && field.OriginalKind() == reflect.Struct {
|
||||
if subTagFields, err := getFieldValuesByTagPriority(field.Value, priority, tagMap); err != nil {
|
||||
subTagFields, err := getFieldValuesByTagPriority(field.Value, priority, repeatedTagFilteringMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
tagFields = append(tagFields, subTagFields...)
|
||||
|
||||
@ -192,11 +192,11 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
// 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.
|
||||
var (
|
||||
tempName string
|
||||
elemFieldType reflect.StructField
|
||||
elemFieldValue reflect.Value
|
||||
elemType = pointerElemReflectValue.Type()
|
||||
attrMap = make(map[string]string) // Attribute name to its check name which has no symbols.
|
||||
tempName string
|
||||
elemFieldType reflect.StructField
|
||||
elemFieldValue reflect.Value
|
||||
elemType = pointerElemReflectValue.Type()
|
||||
attrToCheckNameMap = make(map[string]string)
|
||||
)
|
||||
for i := 0; i < pointerElemReflectValue.NumField(); i++ {
|
||||
elemFieldType = elemType.Field(i)
|
||||
@ -219,35 +219,35 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
}
|
||||
} else {
|
||||
tempName = elemFieldType.Name
|
||||
attrMap[tempName] = utils.RemoveSymbols(tempName)
|
||||
attrToCheckNameMap[tempName] = utils.RemoveSymbols(tempName)
|
||||
}
|
||||
}
|
||||
if len(attrMap) == 0 {
|
||||
if len(attrToCheckNameMap) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The key of the tagMap is the attribute name of the struct,
|
||||
// and the value is its replaced tag name for later comparison to improve performance.
|
||||
var (
|
||||
tagMap = make(map[string]string) // Tag name to its check name which has no symbols.
|
||||
priorityTagArray []string
|
||||
attrToTagCheckNameMap = make(map[string]string)
|
||||
priorityTagArray []string
|
||||
)
|
||||
if priorityTag != "" {
|
||||
priorityTagArray = append(utils.SplitAndTrim(priorityTag, ","), StructTagPriority...)
|
||||
} else {
|
||||
priorityTagArray = StructTagPriority
|
||||
}
|
||||
tagToNameMap, err := gstructs.TagMapName(pointerElemReflectValue, priorityTagArray)
|
||||
tagToAttrNameMap, err := gstructs.TagMapName(pointerElemReflectValue, priorityTagArray)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for tagName, attributeName := range tagToNameMap {
|
||||
for tagName, attributeName := range tagToAttrNameMap {
|
||||
// If there's something else in the tag string,
|
||||
// it uses the first part which is split using char ','.
|
||||
// Eg:
|
||||
// orm:"id, priority"
|
||||
// orm:"name, with:uid=id"
|
||||
tagMap[attributeName] = utils.RemoveSymbols(strings.Split(tagName, ",")[0])
|
||||
attrToTagCheckNameMap[attributeName] = utils.RemoveSymbols(strings.Split(tagName, ",")[0])
|
||||
// If tag and attribute values both exist in `paramsMap`,
|
||||
// it then uses the tag value overwriting the attribute value in `paramsMap`.
|
||||
if paramsMap[tagName] != nil && paramsMap[attributeName] != nil {
|
||||
@ -259,26 +259,27 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
attrName string
|
||||
checkName string
|
||||
)
|
||||
for mapK, mapV := range paramsMap {
|
||||
for paramName, paramValue := range paramsMap {
|
||||
attrName = ""
|
||||
// It firstly checks the passed mapping rules.
|
||||
if len(mapping) > 0 {
|
||||
if passedAttrKey, ok := mapping[mapK]; ok {
|
||||
if passedAttrKey, ok := mapping[paramName]; ok {
|
||||
attrName = passedAttrKey
|
||||
}
|
||||
}
|
||||
// It secondly checks the predefined tags and matching rules.
|
||||
if attrName == "" {
|
||||
// It firstly considers `mapK` as accurate tag name, and retrieve attribute name from `tagToNameMap` .
|
||||
attrName = tagToNameMap[mapK]
|
||||
// It firstly considers `paramName` as accurate tag name,
|
||||
// and retrieve attribute name from `tagToAttrNameMap` .
|
||||
attrName = tagToAttrNameMap[paramName]
|
||||
if attrName == "" {
|
||||
checkName = utils.RemoveSymbols(mapK)
|
||||
checkName = utils.RemoveSymbols(paramName)
|
||||
// Loop to find the matched attribute name with or without
|
||||
// string cases and chars like '-'/'_'/'.'/' '.
|
||||
|
||||
// Matching the parameters to struct tag names.
|
||||
// The `attrKey` is the attribute name of the struct.
|
||||
for attrKey, cmpKey := range tagMap {
|
||||
for attrKey, cmpKey := range attrToTagCheckNameMap {
|
||||
if strings.EqualFold(checkName, cmpKey) {
|
||||
attrName = attrKey
|
||||
break
|
||||
@ -288,7 +289,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
|
||||
// Matching the parameters to struct attributes.
|
||||
if attrName == "" {
|
||||
for attrKey, cmpKey := range attrMap {
|
||||
for attrKey, cmpKey := range attrToCheckNameMap {
|
||||
// Eg:
|
||||
// UserName eq user_name
|
||||
// User-Name eq username
|
||||
@ -312,7 +313,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
}
|
||||
// Mark it done.
|
||||
doneMap[attrName] = struct{}{}
|
||||
if err = bindVarToStructAttr(pointerElemReflectValue, attrName, mapV, mapping); err != nil {
|
||||
if err = bindVarToStructAttr(pointerElemReflectValue, attrName, paramValue, mapping); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -1270,8 +1270,8 @@ func Test_Struct_Issue1563(t *testing.T) {
|
||||
user := new(User)
|
||||
params2 := g.Map{
|
||||
"password1": "111",
|
||||
"PASS1": "222",
|
||||
"Pass1": "333",
|
||||
//"PASS1": "222",
|
||||
"Pass1": "333",
|
||||
}
|
||||
if err := gconv.Struct(params2, user); err == nil {
|
||||
t.Assert(user.Pass1, `111`)
|
||||
|
||||
Reference in New Issue
Block a user