mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 04:07:47 +08:00
remove third party package 'structs'; improve performance for package internal/structs
This commit is contained in:
parent
e1dd5cce7d
commit
d178102f82
@ -312,32 +312,40 @@ func doQuoteString(s, charLeft, charRight string) string {
|
||||
|
||||
// GetWhereConditionOfStruct returns the where condition sql and arguments by given struct pointer.
|
||||
// This function automatically retrieves primary or unique field and its attribute value as condition.
|
||||
func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interface{}) {
|
||||
func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interface{}, err error) {
|
||||
tagField, err := structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT})
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
array := ([]string)(nil)
|
||||
for _, field := range structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT}) {
|
||||
array = strings.Split(field.Tag, ",")
|
||||
for _, field := range tagField {
|
||||
array = strings.Split(field.CurrentTag, ",")
|
||||
if len(array) > 1 && gstr.InArray([]string{ORM_TAG_FOR_UNIQUE, ORM_TAG_FOR_PRIMARY}, array[1]) {
|
||||
return array[0], []interface{}{field.Value()}
|
||||
return array[0], []interface{}{field.Value()}, nil
|
||||
}
|
||||
if len(where) > 0 {
|
||||
where += " "
|
||||
}
|
||||
where += field.Tag + "=?"
|
||||
where += field.CurrentTag + "=?"
|
||||
args = append(args, field.Value())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetPrimaryKey retrieves and returns primary key field name from given struct.
|
||||
func GetPrimaryKey(pointer interface{}) string {
|
||||
func GetPrimaryKey(pointer interface{}) (string, error) {
|
||||
tagField, err := structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
array := ([]string)(nil)
|
||||
for _, field := range structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT}) {
|
||||
array = strings.Split(field.Tag, ",")
|
||||
for _, field := range tagField {
|
||||
array = strings.Split(field.CurrentTag, ",")
|
||||
if len(array) > 1 && array[1] == ORM_TAG_FOR_PRIMARY {
|
||||
return array[0]
|
||||
return array[0], nil
|
||||
}
|
||||
}
|
||||
return ""
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// GetPrimaryKeyCondition returns a new where condition by primary field name.
|
||||
@ -721,9 +729,13 @@ func FormatSqlWithArgs(sql string, args []interface{}) string {
|
||||
// mapToStruct maps the <data> to given struct.
|
||||
// Note that the given parameter <pointer> should be a pointer to s struct.
|
||||
func mapToStruct(data map[string]interface{}, pointer interface{}) error {
|
||||
tagNameMap, err := structs.TagMapName(pointer, []string{ORM_TAG_FOR_STRUCT})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 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}) {
|
||||
for tag, attr := range tagNameMap {
|
||||
mapping[strings.Split(tag, ",")[0]] = attr
|
||||
}
|
||||
return gconv.Struct(data, pointer, mapping)
|
||||
|
@ -14,27 +14,27 @@ import (
|
||||
strip "github.com/grokify/html-strip-tags-go"
|
||||
)
|
||||
|
||||
// 过滤掉HTML标签,只返回text内容
|
||||
// 参考:http://php.net/manual/zh/function.strip-tags.php
|
||||
// StripTags strips HTML tags from content, and returns only text.
|
||||
// Referer: http://php.net/manual/zh/function.strip-tags.php
|
||||
func StripTags(s string) string {
|
||||
return strip.StripTags(s)
|
||||
}
|
||||
|
||||
// 本函数各方面都和SpecialChars一样,
|
||||
// 除了Entities会转换所有具有 HTML 实体的字符。
|
||||
// 参考:http://php.net/manual/zh/function.htmlentities.php
|
||||
// Entities encodes all HTML chars for content.
|
||||
// Referer: http://php.net/manual/zh/function.htmlentities.php
|
||||
func Entities(s string) string {
|
||||
return html.EscapeString(s)
|
||||
}
|
||||
|
||||
// Entities 的相反操作
|
||||
// 参考:http://php.net/manual/zh/function.html-entity-decode.php
|
||||
// EntitiesDecode decodes all HTML chars for content.
|
||||
// Referer: http://php.net/manual/zh/function.html-entity-decode.php
|
||||
func EntitiesDecode(s string) string {
|
||||
return html.UnescapeString(s)
|
||||
}
|
||||
|
||||
// 将html中的部分特殊标签转换为html转义标签
|
||||
// 参考:http://php.net/manual/zh/function.htmlspecialchars.php
|
||||
// SpecialChars encodes some special chars for content, these special chars are:
|
||||
// "&", "<", ">", `"`, "'".
|
||||
// Referer: http://php.net/manual/zh/function.htmlspecialchars.php
|
||||
func SpecialChars(s string) string {
|
||||
return strings.NewReplacer(
|
||||
"&", "&",
|
||||
@ -45,8 +45,9 @@ func SpecialChars(s string) string {
|
||||
).Replace(s)
|
||||
}
|
||||
|
||||
// 将html部分转义标签还原为html特殊标签
|
||||
// 参考:http://php.net/manual/zh/function.htmlspecialchars-decode.php
|
||||
// SpecialCharsDecode decodes some special chars for content, these special chars are:
|
||||
// "&", "<", ">", `"`, "'".
|
||||
// Referer: http://php.net/manual/zh/function.htmlspecialchars-decode.php
|
||||
func SpecialCharsDecode(s string) string {
|
||||
return strings.NewReplacer(
|
||||
"&", "&",
|
||||
|
@ -3,6 +3,7 @@
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package ghtml_test
|
||||
|
||||
import (
|
||||
|
1
go.mod
1
go.mod
@ -9,7 +9,6 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/gomodule/redigo v2.0.0+incompatible
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/gqcn/structs v1.1.1
|
||||
github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf
|
||||
github.com/json-iterator/go v1.1.10
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
|
@ -5,14 +5,46 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package structs provides functions for struct conversion.
|
||||
//
|
||||
// Inspired and improved from: https://github.com/fatih/structs
|
||||
package structs
|
||||
|
||||
import "github.com/gqcn/structs"
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Field is alias of structs.Field.
|
||||
// Field contains information of a struct field .
|
||||
type Field struct {
|
||||
*structs.Field
|
||||
value reflect.Value
|
||||
field reflect.StructField
|
||||
// Retrieved tag name. There might be more than one tags in the field,
|
||||
// but only one can be retrieved according to calling function rules.
|
||||
Tag string
|
||||
CurrentTag string
|
||||
}
|
||||
|
||||
// Tag returns the value associated with key in the tag string. If there is no
|
||||
// such key in the tag, Tag returns the empty string.
|
||||
func (f *Field) Tag(key string) string {
|
||||
return f.field.Tag.Get(key)
|
||||
}
|
||||
|
||||
// Value returns the underlying value of the field. It panics if the field
|
||||
// is not exported.
|
||||
func (f *Field) Value() interface{} {
|
||||
return f.value.Interface()
|
||||
}
|
||||
|
||||
// IsEmbedded returns true if the given field is an anonymous field (embedded)
|
||||
func (f *Field) IsEmbedded() bool {
|
||||
return f.field.Anonymous
|
||||
}
|
||||
|
||||
// IsExported returns true if the given field is exported.
|
||||
func (f *Field) IsExported() bool {
|
||||
return f.field.PkgPath == ""
|
||||
}
|
||||
|
||||
// Name returns the name of the given field
|
||||
func (f *Field) Name() string {
|
||||
return f.field.Name
|
||||
}
|
||||
|
@ -6,12 +6,6 @@
|
||||
|
||||
package structs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/gqcn/structs"
|
||||
)
|
||||
|
||||
// MapField retrieves struct field as map[name/tag]*Field from <pointer>, and returns the map.
|
||||
//
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
@ -21,75 +15,18 @@ import (
|
||||
// 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 MapField(pointer interface{}, priority []string, recursive bool) map[string]*Field {
|
||||
// If <pointer> points to an invalid address, for example a nil variable,
|
||||
// it here creates an empty struct using reflect feature.
|
||||
var (
|
||||
tempValue reflect.Value
|
||||
pointerValue = reflect.ValueOf(pointer)
|
||||
)
|
||||
for pointerValue.Kind() == reflect.Ptr {
|
||||
tempValue = pointerValue.Elem()
|
||||
if !tempValue.IsValid() {
|
||||
pointer = reflect.New(pointerValue.Type().Elem()).Elem()
|
||||
break
|
||||
} else {
|
||||
pointerValue = tempValue
|
||||
func MapField(pointer interface{}, priority []string) (map[string]*Field, error) {
|
||||
tagFields, err := getFieldValuesByTagPriority(pointer, priority, map[string]struct{}{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tagFieldMap := make(map[string]*Field, len(tagFields))
|
||||
for _, field := range tagFields {
|
||||
tagField := field
|
||||
tagFieldMap[field.Name()] = tagField
|
||||
if tagField.CurrentTag != "" {
|
||||
tagFieldMap[tagField.CurrentTag] = tagField
|
||||
}
|
||||
}
|
||||
var (
|
||||
fields []*structs.Field
|
||||
fieldMap = make(map[string]*Field)
|
||||
)
|
||||
if v, ok := pointer.(reflect.Value); ok {
|
||||
fields = structs.Fields(v.Interface())
|
||||
} else {
|
||||
fields = structs.Fields(pointer)
|
||||
}
|
||||
var (
|
||||
tag = ""
|
||||
name = ""
|
||||
)
|
||||
for _, field := range fields {
|
||||
name = field.Name()
|
||||
// Only retrieve exported attributes.
|
||||
if name[0] < byte('A') || name[0] > byte('Z') {
|
||||
continue
|
||||
}
|
||||
fieldMap[name] = &Field{
|
||||
Field: field,
|
||||
Tag: tag,
|
||||
}
|
||||
tag = ""
|
||||
for _, p := range priority {
|
||||
tag = field.Tag(p)
|
||||
if tag != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
if tag != "" {
|
||||
fieldMap[tag] = &Field{
|
||||
Field: field,
|
||||
Tag: tag,
|
||||
}
|
||||
}
|
||||
if recursive {
|
||||
var (
|
||||
rv = reflect.ValueOf(field.Value())
|
||||
kind = rv.Kind()
|
||||
)
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
if kind == reflect.Struct {
|
||||
for k, v := range MapField(rv, priority, true) {
|
||||
if _, ok := fieldMap[k]; !ok {
|
||||
fieldMap[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fieldMap
|
||||
return tagFieldMap, nil
|
||||
}
|
||||
|
@ -7,9 +7,8 @@
|
||||
package structs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
|
||||
"github.com/gqcn/structs"
|
||||
)
|
||||
|
||||
// TagFields retrieves struct tags as []*Field from <pointer>, and returns it.
|
||||
@ -17,94 +16,105 @@ import (
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter up-case from struct.
|
||||
func TagFields(pointer interface{}, priority []string) []*Field {
|
||||
return doTagFields(pointer, priority, map[string]struct{}{})
|
||||
func TagFields(pointer interface{}, priority []string) ([]*Field, error) {
|
||||
return getFieldValuesByTagPriority(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.
|
||||
// TODO remove third-party package "structs" by reducing the reflect usage to improve the performance.
|
||||
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.
|
||||
func getFieldValues(value interface{}) ([]*Field, error) {
|
||||
var (
|
||||
tempValue reflect.Value
|
||||
pointerValue = reflect.ValueOf(pointer)
|
||||
reflectValue reflect.Value
|
||||
reflectKind reflect.Kind
|
||||
)
|
||||
for pointerValue.Kind() == reflect.Ptr {
|
||||
tempValue = pointerValue.Elem()
|
||||
if !tempValue.IsValid() {
|
||||
pointer = reflect.New(pointerValue.Type().Elem()).Elem()
|
||||
break
|
||||
} else {
|
||||
pointerValue = tempValue
|
||||
}
|
||||
}
|
||||
var fields []*structs.Field
|
||||
if v, ok := pointer.(reflect.Value); ok {
|
||||
fields = structs.Fields(v.Interface())
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
reflectValue = v
|
||||
reflectKind = reflectValue.Kind()
|
||||
} else {
|
||||
var (
|
||||
rv = reflect.ValueOf(pointer)
|
||||
kind = rv.Kind()
|
||||
)
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
// If pointer is type of **struct and nil, then automatically create a temporary struct,
|
||||
// which is used for structs.Fields.
|
||||
if kind == reflect.Ptr && (!rv.IsValid() || rv.IsNil()) {
|
||||
fields = structs.Fields(reflect.New(rv.Type().Elem()).Elem().Interface())
|
||||
reflectValue = reflect.ValueOf(value)
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
|
||||
if reflectKind == reflect.Ptr {
|
||||
if !reflectValue.IsValid() || reflectValue.IsNil() {
|
||||
// If pointer is type of *struct and nil, then automatically create a temporary struct.
|
||||
reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
} else {
|
||||
fields = structs.Fields(pointer)
|
||||
// If pointer is type of **struct and nil, then automatically create a temporary struct.
|
||||
var (
|
||||
pointedValue = reflectValue.Elem()
|
||||
pointedValueKind = pointedValue.Kind()
|
||||
)
|
||||
if pointedValueKind == reflect.Ptr && (!pointedValue.IsValid() || pointedValue.IsNil()) {
|
||||
reflectValue = reflect.New(pointedValue.Type().Elem()).Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
} else {
|
||||
reflectValue = pointedValue
|
||||
reflectKind = pointedValueKind
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for reflectKind == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
if reflectKind != reflect.Struct {
|
||||
return nil, errors.New("given value should be type of struct/*struct")
|
||||
}
|
||||
var (
|
||||
tag = ""
|
||||
name = ""
|
||||
structType = reflectValue.Type()
|
||||
length = reflectValue.NumField()
|
||||
fields = make([]*Field, length)
|
||||
)
|
||||
for i := 0; i < length; i++ {
|
||||
fields[i] = &Field{
|
||||
value: reflectValue.Field(i),
|
||||
field: structType.Field(i),
|
||||
}
|
||||
}
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
func getFieldValuesByTagPriority(pointer interface{}, priority []string, tagMap map[string]struct{}) ([]*Field, error) {
|
||||
fields, err := getFieldValues(pointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
tagName = ""
|
||||
tagFields = make([]*Field, 0)
|
||||
)
|
||||
tagFields := make([]*Field, 0)
|
||||
for _, field := range fields {
|
||||
name = field.Name()
|
||||
// Only retrieve exported attributes.
|
||||
if name[0] < byte('A') || name[0] > byte('Z') {
|
||||
if !field.IsExported() {
|
||||
continue
|
||||
}
|
||||
tag = ""
|
||||
tagName = ""
|
||||
for _, p := range priority {
|
||||
tag = field.Tag(p)
|
||||
if tag != "" {
|
||||
tagName = field.Tag(p)
|
||||
if tagName != "" && tagName != "-" {
|
||||
break
|
||||
}
|
||||
}
|
||||
if tag != "" {
|
||||
if tagName != "" {
|
||||
// Filter repeated tag.
|
||||
if _, ok := tagMap[tag]; ok {
|
||||
if _, ok := tagMap[tagName]; ok {
|
||||
continue
|
||||
}
|
||||
tagFields = append(tagFields, &Field{
|
||||
Field: field,
|
||||
Tag: tag,
|
||||
})
|
||||
tagField := field
|
||||
tagField.CurrentTag = tagName
|
||||
tagFields = append(tagFields, tagField)
|
||||
}
|
||||
// If this is an embedded attribute, it retrieves the tags recursively.
|
||||
if field.IsEmbedded() {
|
||||
var (
|
||||
rv = reflect.ValueOf(field.Value())
|
||||
kind = rv.Kind()
|
||||
)
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
if kind == reflect.Struct {
|
||||
tagFields = append(tagFields, doTagFields(rv, priority, tagMap)...)
|
||||
if subTagFields, err := getFieldValuesByTagPriority(field.value, priority, tagMap); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
tagFields = append(tagFields, subTagFields...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return tagFields
|
||||
return tagFields, nil
|
||||
}
|
||||
|
||||
// TagMapName retrieves struct tags as map[tag]attribute from <pointer>, and returns it.
|
||||
@ -112,13 +122,16 @@ func doTagFields(pointer interface{}, priority []string, tagMap map[string]struc
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter up-case from struct.
|
||||
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()
|
||||
func TagMapName(pointer interface{}, priority []string) (map[string]string, error) {
|
||||
fields, err := TagFields(pointer, priority)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tagMap
|
||||
tagMap := make(map[string]string, len(fields))
|
||||
for _, field := range fields {
|
||||
tagMap[field.CurrentTag] = field.Name()
|
||||
}
|
||||
return tagMap, nil
|
||||
}
|
||||
|
||||
// TagMapField retrieves struct tags as map[tag]*Field from <pointer>, and returns it.
|
||||
@ -126,11 +139,15 @@ func TagMapName(pointer interface{}, priority []string) map[string]string {
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter up-case from struct.
|
||||
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
|
||||
func TagMapField(pointer interface{}, priority []string) (map[string]*Field, error) {
|
||||
fields, err := TagFields(pointer, priority)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tagMap
|
||||
tagMap := make(map[string]*Field, len(fields))
|
||||
for _, field := range fields {
|
||||
tagField := field
|
||||
tagMap[field.CurrentTag] = tagField
|
||||
}
|
||||
return tagMap, nil
|
||||
}
|
||||
|
@ -24,12 +24,17 @@ 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"}), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"params"}), g.Map{"name": "Name", "pass": "Pass"})
|
||||
m, _ := structs.TagMapName(user, []string{"params"})
|
||||
t.Assert(m, g.Map{"name": "Name", "pass": "Pass"})
|
||||
m, _ = structs.TagMapName(&user, []string{"params"})
|
||||
t.Assert(m, g.Map{"name": "Name", "pass": "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"})
|
||||
m, _ = structs.TagMapName(&user, []string{"params", "my-tag1"})
|
||||
t.Assert(m, g.Map{"name": "Name", "pass": "Pass"})
|
||||
m, _ = structs.TagMapName(&user, []string{"my-tag1", "params"})
|
||||
t.Assert(m, g.Map{"name": "Name", "pass1": "Pass"})
|
||||
m, _ = structs.TagMapName(&user, []string{"my-tag2", "params"})
|
||||
t.Assert(m, g.Map{"name": "Name", "pass2": "Pass"})
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
@ -43,7 +48,8 @@ func Test_Basic(t *testing.T) {
|
||||
Base `params:"base"`
|
||||
}
|
||||
user := new(UserWithBase)
|
||||
t.Assert(structs.TagMapName(user, []string{"params"}), g.Map{
|
||||
m, _ := structs.TagMapName(user, []string{"params"})
|
||||
t.Assert(m, g.Map{
|
||||
"base": "Base",
|
||||
"password1": "Pass1",
|
||||
"password2": "Pass2",
|
||||
@ -67,8 +73,10 @@ func Test_Basic(t *testing.T) {
|
||||
}
|
||||
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{})
|
||||
m, _ := structs.TagMapName(user1, []string{"params"})
|
||||
t.Assert(m, g.Map{"password1": "Pass1", "password2": "Pass2"})
|
||||
m, _ = structs.TagMapName(user2, []string{"params"})
|
||||
t.Assert(m, g.Map{})
|
||||
})
|
||||
}
|
||||
|
||||
@ -80,11 +88,16 @@ 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"}), g.Map{"name": "Name", "pass": "Pass"})
|
||||
t.Assert(structs.TagMapName(&user, []string{"params"}), g.Map{"name": "Name", "pass": "Pass"})
|
||||
m, _ := structs.TagMapName(user, []string{"params"})
|
||||
t.Assert(m, g.Map{"name": "Name", "pass": "Pass"})
|
||||
m, _ = structs.TagMapName(&user, []string{"params"})
|
||||
t.Assert(m, g.Map{"name": "Name", "pass": "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"})
|
||||
m, _ = structs.TagMapName(&user, []string{"params", "my-tag1"})
|
||||
t.Assert(m, g.Map{"name": "Name", "pass": "Pass"})
|
||||
m, _ = structs.TagMapName(&user, []string{"my-tag1", "params"})
|
||||
t.Assert(m, g.Map{"name": "Name", "pass1": "Pass"})
|
||||
m, _ = structs.TagMapName(&user, []string{"my-tag2", "params"})
|
||||
t.Assert(m, g.Map{"name": "Name", "pass2": "Pass"})
|
||||
})
|
||||
}
|
||||
|
@ -11,10 +11,10 @@ import (
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
"github.com/gogf/gf/internal/json"
|
||||
"github.com/gogf/gf/internal/structs"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/internal/structs"
|
||||
"github.com/gogf/gf/internal/utils"
|
||||
)
|
||||
|
||||
@ -196,7 +196,11 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
|
||||
// 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) {
|
||||
tagToNameMap, err := structs.TagMapName(elem, StructTagPriority)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range tagToNameMap {
|
||||
tagMap[v] = utils.RemoveSymbols(k)
|
||||
}
|
||||
|
||||
@ -263,8 +267,7 @@ func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, map
|
||||
}
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = bindVarToReflectValue(structFieldValue, value, mapping...)
|
||||
if err != nil {
|
||||
if err = bindVarToReflectValue(structFieldValue, value, mapping...); err != nil {
|
||||
err = gerror.Wrapf(err, `error binding value to attribute "%s"`, name)
|
||||
}
|
||||
}
|
||||
|
@ -73,16 +73,24 @@ func CheckStruct(object interface{}, rules interface{}, messages ...CustomMsg) *
|
||||
checkRules = v
|
||||
}
|
||||
// Checks and extends the parameters map with struct alias tag.
|
||||
for nameOrTag, field := range structs.MapField(object, aliasNameTagPriority, true) {
|
||||
mapField, err := structs.MapField(object, aliasNameTagPriority)
|
||||
if err != nil {
|
||||
return newErrorStr("invalid_object", err.Error())
|
||||
}
|
||||
for nameOrTag, field := range mapField {
|
||||
params[nameOrTag] = field.Value()
|
||||
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) {
|
||||
tagField, err := structs.TagFields(object, structTagPriority)
|
||||
if err != nil {
|
||||
return newErrorStr("invalid_object", err.Error())
|
||||
}
|
||||
for _, field := range tagField {
|
||||
fieldName := field.Name()
|
||||
// sequence tag == struct tag
|
||||
// The name here is alias of field name.
|
||||
name, rule, msg := parseSequenceTag(field.Tag)
|
||||
name, rule, msg := parseSequenceTag(field.CurrentTag)
|
||||
if len(name) == 0 {
|
||||
name = fieldName
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user