mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
improve package internal/structs
This commit is contained in:
@ -314,7 +314,7 @@ func doQuoteString(s, charLeft, charRight string) string {
|
||||
// This function automatically retrieves primary or unique field and its attribute value as condition.
|
||||
func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interface{}) {
|
||||
array := ([]string)(nil)
|
||||
for _, field := range structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT}, true) {
|
||||
for _, field := range structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT}) {
|
||||
array = strings.Split(field.Tag, ",")
|
||||
if len(array) > 1 && gstr.InArray([]string{ORM_TAG_FOR_UNIQUE, ORM_TAG_FOR_PRIMARY}, array[1]) {
|
||||
return array[0], []interface{}{field.Value()}
|
||||
@ -331,7 +331,7 @@ func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interf
|
||||
// GetPrimaryKey retrieves and returns primary key field name from given struct.
|
||||
func GetPrimaryKey(pointer interface{}) string {
|
||||
array := ([]string)(nil)
|
||||
for _, field := range structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT}, true) {
|
||||
for _, field := range structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT}) {
|
||||
array = strings.Split(field.Tag, ",")
|
||||
if len(array) > 1 && array[1] == ORM_TAG_FOR_PRIMARY {
|
||||
return array[0]
|
||||
@ -723,7 +723,7 @@ func FormatSqlWithArgs(sql string, args []interface{}) string {
|
||||
func mapToStruct(data map[string]interface{}, pointer interface{}) error {
|
||||
// It retrieves and returns the mapping between orm tag and the struct attribute name.
|
||||
mapping := make(map[string]string)
|
||||
for tag, attr := range structs.TagMapName(pointer, []string{ORM_TAG_FOR_STRUCT}, true) {
|
||||
for tag, attr := range structs.TagMapName(pointer, []string{ORM_TAG_FOR_STRUCT}) {
|
||||
mapping[strings.Split(tag, ",")[0]] = attr
|
||||
}
|
||||
return gconv.StructDeep(data, pointer, mapping)
|
||||
|
||||
@ -16,17 +16,15 @@ import (
|
||||
//
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
//
|
||||
// The parameter <recursive> specifies whether retrieving the struct field recursively.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter up-case from struct.
|
||||
func TagFields(pointer interface{}, priority []string, recursive bool) []*Field {
|
||||
return doTagFields(pointer, priority, recursive, map[string]struct{}{})
|
||||
func TagFields(pointer interface{}, priority []string) []*Field {
|
||||
return doTagFields(pointer, priority, map[string]struct{}{})
|
||||
}
|
||||
|
||||
// doTagFields retrieves the tag and corresponding attribute name from <pointer>. It also filters repeated
|
||||
// tag internally.
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
func doTagFields(pointer interface{}, priority []string, recursive bool, tagMap map[string]struct{}) []*Field {
|
||||
func doTagFields(pointer interface{}, priority []string, tagMap map[string]struct{}) []*Field {
|
||||
// If <pointer> points to an invalid address, for example a nil variable,
|
||||
// it here creates an empty struct using reflect feature.
|
||||
var (
|
||||
@ -90,7 +88,8 @@ func doTagFields(pointer interface{}, priority []string, recursive bool, tagMap
|
||||
Tag: tag,
|
||||
})
|
||||
}
|
||||
if recursive {
|
||||
// If this is an embedded attribute, it retrieves the tags recursively.
|
||||
if field.IsEmbedded() {
|
||||
var (
|
||||
rv = reflect.ValueOf(field.Value())
|
||||
kind = rv.Kind()
|
||||
@ -100,7 +99,7 @@ func doTagFields(pointer interface{}, priority []string, recursive bool, tagMap
|
||||
kind = rv.Kind()
|
||||
}
|
||||
if kind == reflect.Struct {
|
||||
tagFields = append(tagFields, doTagFields(rv, priority, recursive, tagMap)...)
|
||||
tagFields = append(tagFields, doTagFields(rv, priority, tagMap)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,11 +110,9 @@ func doTagFields(pointer interface{}, priority []string, recursive bool, tagMap
|
||||
//
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
//
|
||||
// The parameter <recursive> specifies whether retrieving the struct field recursively.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter up-case from struct.
|
||||
func TagMapName(pointer interface{}, priority []string, recursive bool) map[string]string {
|
||||
fields := TagFields(pointer, priority, recursive)
|
||||
func TagMapName(pointer interface{}, priority []string) map[string]string {
|
||||
fields := TagFields(pointer, priority)
|
||||
tagMap := make(map[string]string, len(fields))
|
||||
for _, v := range fields {
|
||||
tagMap[v.Tag] = v.Name()
|
||||
@ -127,11 +124,9 @@ func TagMapName(pointer interface{}, priority []string, recursive bool) map[stri
|
||||
//
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
//
|
||||
// The parameter <recursive> specifies whether retrieving the struct field recursively.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter up-case from struct.
|
||||
func TagMapField(pointer interface{}, priority []string, recursive bool) map[string]*Field {
|
||||
fields := TagFields(pointer, priority, recursive)
|
||||
func TagMapField(pointer interface{}, priority []string) map[string]*Field {
|
||||
fields := TagFields(pointer, priority)
|
||||
tagMap := make(map[string]*Field, len(fields))
|
||||
for _, v := range fields {
|
||||
tagMap[v.Tag] = v
|
||||
|
||||
@ -24,12 +24,12 @@ func Test_Basic(t *testing.T) {
|
||||
Pass string `my-tag1:"pass1" my-tag2:"pass2" params:"pass"`
|
||||
}
|
||||
var user User
|
||||
t.Assert(structs.TagMapName(user, []string{"params"}, true), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"params"}, true), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(user, []string{"params"}), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"params"}), g.Map{"name": "Name", "pass": "Pass"})
|
||||
|
||||
t.Assert(structs.TagMapName(&user, []string{"params", "my-tag1"}, true), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"my-tag1", "params"}, true), g.Map{"name": "Name", "pass1": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"my-tag2", "params"}, true), g.Map{"name": "Name", "pass2": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"params", "my-tag1"}), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"my-tag1", "params"}), g.Map{"name": "Name", "pass1": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"my-tag2", "params"}), g.Map{"name": "Name", "pass2": "Pass"})
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
@ -43,7 +43,7 @@ func Test_Basic(t *testing.T) {
|
||||
Base `params:"base"`
|
||||
}
|
||||
user := new(UserWithBase)
|
||||
t.Assert(structs.TagMapName(user, []string{"params"}, true), g.Map{
|
||||
t.Assert(structs.TagMapName(user, []string{"params"}), g.Map{
|
||||
"base": "Base",
|
||||
"password1": "Pass1",
|
||||
"password2": "Pass2",
|
||||
@ -55,20 +55,20 @@ func Test_Basic(t *testing.T) {
|
||||
Pass1 string `params:"password1"`
|
||||
Pass2 string `params:"password2"`
|
||||
}
|
||||
type UserWithBase1 struct {
|
||||
type UserWithEmbeddedAttribute struct {
|
||||
Id int
|
||||
Name string
|
||||
Base
|
||||
}
|
||||
type UserWithBase2 struct {
|
||||
type UserWithoutEmbeddedAttribute struct {
|
||||
Id int
|
||||
Name string
|
||||
Pass Base
|
||||
}
|
||||
user1 := new(UserWithBase1)
|
||||
user2 := new(UserWithBase2)
|
||||
t.Assert(structs.TagMapName(user1, []string{"params"}, true), g.Map{"password1": "Pass1", "password2": "Pass2"})
|
||||
t.Assert(structs.TagMapName(user2, []string{"params"}, true), g.Map{"password1": "Pass1", "password2": "Pass2"})
|
||||
user1 := new(UserWithEmbeddedAttribute)
|
||||
user2 := new(UserWithoutEmbeddedAttribute)
|
||||
t.Assert(structs.TagMapName(user1, []string{"params"}), g.Map{"password1": "Pass1", "password2": "Pass2"})
|
||||
t.Assert(structs.TagMapName(user2, []string{"params"}), g.Map{})
|
||||
})
|
||||
}
|
||||
|
||||
@ -80,11 +80,11 @@ func Test_StructOfNilPointer(t *testing.T) {
|
||||
Pass string `my-tag1:"pass1" my-tag2:"pass2" params:"pass"`
|
||||
}
|
||||
var user *User
|
||||
t.Assert(structs.TagMapName(user, []string{"params"}, true), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"params"}, true), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(user, []string{"params"}), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"params"}), g.Map{"name": "Name", "pass": "Pass"})
|
||||
|
||||
t.Assert(structs.TagMapName(&user, []string{"params", "my-tag1"}, true), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"my-tag1", "params"}, true), g.Map{"name": "Name", "pass1": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"my-tag2", "params"}, true), g.Map{"name": "Name", "pass2": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"params", "my-tag1"}), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"my-tag1", "params"}), g.Map{"name": "Name", "pass1": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"my-tag2", "params"}), g.Map{"name": "Name", "pass2": "Pass"})
|
||||
})
|
||||
}
|
||||
|
||||
@ -191,7 +191,7 @@ func doStruct(params interface{}, pointer interface{}, recursive bool, mapping .
|
||||
// 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.
|
||||
tagMap := make(map[string]string)
|
||||
for k, v := range structs.TagMapName(pointer, StructTagPriority, true) {
|
||||
for k, v := range structs.TagMapName(pointer, StructTagPriority) {
|
||||
tagMap[v] = replaceCharReg.ReplaceAllString(k, "")
|
||||
}
|
||||
|
||||
|
||||
@ -1001,3 +1001,31 @@ func Test_Struct_WithJson(t *testing.T) {
|
||||
t.Assert(b2, b1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Struct_AttrStructHasTheSameTag(t *testing.T) {
|
||||
type Product struct {
|
||||
Id int `json:"id"`
|
||||
UpdatedAt time.Time `json:"-" `
|
||||
UpdatedAtFormat string `json:"updated_at" `
|
||||
}
|
||||
|
||||
type Order struct {
|
||||
Id int `json:"id"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Product Product `json:"products"`
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
data := g.Map{
|
||||
"id": 1,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
order := new(Order)
|
||||
err := gconv.Struct(data, order)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(order.Id, data["id"])
|
||||
t.Assert(order.UpdatedAt, data["updated_at"])
|
||||
t.Assert(order.Product.Id, 0)
|
||||
t.Assert(order.Product.UpdatedAt.IsZero(), true)
|
||||
t.Assert(order.Product.UpdatedAtFormat, "")
|
||||
})
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ func CheckStruct(object interface{}, rules interface{}, messages ...CustomMsg) *
|
||||
params[field.Name()] = field.Value()
|
||||
}
|
||||
// It here must use structs.TagFields not structs.MapField to ensure error sequence.
|
||||
for _, field := range structs.TagFields(object, structTagPriority, true) {
|
||||
for _, field := range structs.TagFields(object, structTagPriority) {
|
||||
fieldName := field.Name()
|
||||
// sequence tag == struct tag
|
||||
// The name here is alias of field name.
|
||||
|
||||
Reference in New Issue
Block a user