diff --git a/database/gdb/gdb_func.go b/database/gdb/gdb_func.go index 8c69f2762..6d8154429 100644 --- a/database/gdb/gdb_func.go +++ b/database/gdb/gdb_func.go @@ -19,8 +19,8 @@ import ( "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/structs" "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/text/gregex" "github.com/gogf/gf/v2/text/gstr" @@ -96,7 +96,7 @@ func getTableNameFromOrmTag(object interface{}) string { } // Use the struct name of snake case. if tableName == "" { - if t, err := structs.StructType(object); err != nil { + if t, err := gstructs.StructType(object); err != nil { panic(err) } else { tableName = gstr.CaseSnakeFirstUpper( @@ -306,9 +306,9 @@ func doQuoteString(s, charLeft, charRight string) string { func getFieldsFromStructOrMap(structOrMap interface{}) (fields []string) { fields = []string{} if utils.IsStruct(structOrMap) { - structFields, _ := structs.Fields(structs.FieldsInput{ + structFields, _ := gstructs.Fields(gstructs.FieldsInput{ Pointer: structOrMap, - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) for _, structField := range structFields { if tag := structField.Tag(OrmTagForStruct); tag != "" && gregex.IsMatchString(regularFieldNameRegPattern, tag) { diff --git a/database/gdb/gdb_model_with.go b/database/gdb/gdb_model_with.go index 458c12a47..7390230b8 100644 --- a/database/gdb/gdb_model_with.go +++ b/database/gdb/gdb_model_with.go @@ -13,8 +13,8 @@ import ( "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/structs" "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/text/gregex" "github.com/gogf/gf/v2/text/gstr" ) @@ -65,10 +65,10 @@ func (m *Model) doWithScanStruct(pointer interface{}) error { err error allowedTypeStrArray = make([]string, 0) ) - currentStructFieldMap, err := structs.FieldMap(structs.FieldMapInput{ + currentStructFieldMap, err := gstructs.FieldMap(gstructs.FieldMapInput{ Pointer: pointer, PriorityTagArray: nil, - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) if err != nil { return err @@ -77,7 +77,7 @@ func (m *Model) doWithScanStruct(pointer interface{}) error { if !m.withAll { for _, field := range currentStructFieldMap { for _, withItem := range m.withArray { - withItemReflectValueType, err := structs.StructType(withItem) + withItemReflectValueType, err := gstructs.StructType(withItem) if err != nil { return err } @@ -137,7 +137,7 @@ func (m *Model) doWithScanStruct(pointer interface{}) error { } // It automatically retrieves struct field names from current attribute struct/slice. - if structType, err := structs.StructType(field.Value); err != nil { + if structType, err := gstructs.StructType(field.Value); err != nil { return err } else { fieldKeys = structType.FieldKeys() @@ -176,10 +176,10 @@ func (m *Model) doWithScanStructs(pointer interface{}) error { err error allowedTypeStrArray = make([]string, 0) ) - currentStructFieldMap, err := structs.FieldMap(structs.FieldMapInput{ + currentStructFieldMap, err := gstructs.FieldMap(gstructs.FieldMapInput{ Pointer: pointer, PriorityTagArray: nil, - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) if err != nil { return err @@ -188,7 +188,7 @@ func (m *Model) doWithScanStructs(pointer interface{}) error { if !m.withAll { for _, field := range currentStructFieldMap { for _, withItem := range m.withArray { - withItemReflectValueType, err := structs.StructType(withItem) + withItemReflectValueType, err := gstructs.StructType(withItem) if err != nil { return err } @@ -244,7 +244,7 @@ func (m *Model) doWithScanStructs(pointer interface{}) error { } // It automatically retrieves struct field names from current attribute struct/slice. - if structType, err := structs.StructType(field.Value); err != nil { + if structType, err := gstructs.StructType(field.Value); err != nil { return err } else { fieldKeys = structType.FieldKeys() @@ -281,7 +281,7 @@ type parseWithTagInFieldStructOutput struct { Order string } -func (m *Model) parseWithTagInFieldStruct(field structs.Field) (output parseWithTagInFieldStructOutput) { +func (m *Model) parseWithTagInFieldStruct(field gstructs.Field) (output parseWithTagInFieldStructOutput) { var ( match []string ormTag = field.Tag(OrmTagForStruct) diff --git a/database/gdb/gdb_type_result_scanlist.go b/database/gdb/gdb_type_result_scanlist.go index 238f30bc7..0824f5894 100644 --- a/database/gdb/gdb_type_result_scanlist.go +++ b/database/gdb/gdb_type_result_scanlist.go @@ -12,7 +12,7 @@ import ( "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gutil" @@ -356,9 +356,9 @@ func doScanList(in doScanListInput) (err error) { if in.RelationFields != "" && !relationBindToFieldNameChecked { relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName) if !relationFromAttrField.IsValid() { - filedMap, _ := structs.FieldMap(structs.FieldMapInput{ + filedMap, _ := gstructs.FieldMap(gstructs.FieldMapInput{ Pointer: relationFromAttrValue, - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) if key, _ := gutil.MapPossibleItemByKey(gconv.Map(filedMap), relationBindToFieldName); key == "" { return gerror.NewCodef( diff --git a/internal/structs/structs.go b/internal/structs/structs.go deleted file mode 100644 index d9dbfa83c..000000000 --- a/internal/structs/structs.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// 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 structs provides functions for struct information retrieving and struct conversion. -// -// Inspired and improved from: https://github.com/fatih/structs -package structs - -import ( - "reflect" -) - -// Type wraps reflect.Type for additional features. -type Type struct { - reflect.Type -} - -// Field contains information of a struct field . -type Field struct { - Value reflect.Value // The underlying value of the field. - Field reflect.StructField // The underlying field of the field. - TagValue string // Retrieved tag value. There might be more than one tags in the field, but only one can be retrieved according to calling function rules. -} diff --git a/net/ghttp/ghttp_request_param_request.go b/net/ghttp/ghttp_request_param_request.go index bb6a21c87..035ba2c72 100644 --- a/net/ghttp/ghttp_request_param_request.go +++ b/net/ghttp/ghttp_request_param_request.go @@ -9,7 +9,7 @@ package ghttp import ( "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gutil" ) @@ -179,7 +179,7 @@ func (r *Request) doGetRequestStruct(pointer interface{}, mapping ...map[string] // mergeDefaultStructValue merges the request parameters with default values from struct tag definition. func (r *Request) mergeDefaultStructValue(data map[string]interface{}, pointer interface{}) error { - tagFields, err := structs.TagFields(pointer, defaultValueTags) + tagFields, err := gstructs.TagFields(pointer, defaultValueTags) if err != nil { return err } diff --git a/os/gcmd/gcmd_command.go b/os/gcmd/gcmd_command.go index 90517a633..234e30b2e 100644 --- a/os/gcmd/gcmd_command.go +++ b/os/gcmd/gcmd_command.go @@ -25,7 +25,7 @@ type Command struct { FuncWithValue FuncWithValue // Custom function with output parameters that can interact with command caller. HelpFunc Function // Custom help function Examples string // Usage examples. - Additional string // Additional custom info about this command. + Additional string // Additional info about this command, which will be appended to the end of help info. parent *Command // Parent command for internal usage. commands []Command // Sub commands of this command. } @@ -62,9 +62,6 @@ func (c *Command) AddCommand(commands ...Command) error { if cmd.Name == "" { return gerror.New("command name should not be empty") } - if cmd.Func == nil && cmd.FuncWithValue == nil { - return gerror.New("command function should not be empty") - } cmd.parent = c c.commands = append(c.commands, cmd) } @@ -77,11 +74,11 @@ func (c *Command) AddObject(objects ...interface{}) error { commands []Command ) for _, object := range objects { - tempCommand, err := NewFromObject(object) + rootCommand, err := NewFromObject(object) if err != nil { return err } - commands = append(commands, *tempCommand) + commands = append(commands, rootCommand) } return c.AddCommand(commands...) } diff --git a/os/gcmd/gcmd_command_object.go b/os/gcmd/gcmd_command_object.go index 40a580c83..9b819065b 100644 --- a/os/gcmd/gcmd_command_object.go +++ b/os/gcmd/gcmd_command_object.go @@ -14,8 +14,8 @@ import ( "github.com/gogf/gf/v2/container/gset" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/structs" "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gmeta" @@ -24,9 +24,8 @@ import ( ) const ( - tagNameDc = `dc` - tagNameAd = `ad` - tagNameRoot = `root` + tagNameDc = `dc` + tagNameAd = `ad` ) var ( @@ -35,51 +34,42 @@ var ( ) // NewFromObject creates and returns a root command object using given object. -func NewFromObject(object interface{}) (rootCmd *Command, err error) { +func NewFromObject(object interface{}) (rootCmd Command, err error) { originValueAndKind := utils.OriginValueAndKind(object) if originValueAndKind.OriginKind != reflect.Struct { - return nil, gerror.Newf( + err = gerror.Newf( `input object should be type of struct, but got "%s"`, originValueAndKind.InputValue.Type().String(), ) + return } + // Root command creating. + rootCmd, err = newCommandFromObjectMeta(object) + if err != nil { + return + } + // Sub command creating. var ( nameSet = gset.NewStrSet() subCommands []Command ) for i := 0; i < originValueAndKind.InputValue.NumMethod(); i++ { var ( - root bool method = originValueAndKind.InputValue.Method(i) methodCommand Command ) - methodCommand, root, err = newCommandFromMethod(object, method) + methodCommand, err = newCommandFromMethod(object, method) if err != nil { - return nil, err + return } if nameSet.Contains(methodCommand.Name) { - return nil, gerror.Newf( + err = gerror.Newf( `command name should be unique, found duplicated command name in method "%s"`, method.Type().String(), ) + return } - if root { - if rootCmd != nil { - return nil, gerror.Newf( - `there should be only one root command in object, found duplicated in method "%s"`, - method.Type().String(), - ) - } - rootCmd = &methodCommand - } else { - subCommands = append(subCommands, methodCommand) - } - } - if rootCmd == nil { - return nil, gerror.Newf( - `there should be one root command in object when creating command from object, but found none in object "%s"`, - originValueAndKind.InputValue.Type().String(), - ) + subCommands = append(subCommands, methodCommand) } if len(subCommands) > 0 { err = rootCmd.AddCommand(subCommands...) @@ -87,7 +77,38 @@ func NewFromObject(object interface{}) (rootCmd *Command, err error) { return } -func newCommandFromMethod(object interface{}, method reflect.Value) (command Command, root bool, err error) { +func newCommandFromObjectMeta(object interface{}) (command Command, err error) { + var ( + metaData = gmeta.Data(object) + ) + if len(metaData) == 0 { + err = gerror.Newf( + `no meta data found in struct "%s"`, + reflect.TypeOf(object).String(), + ) + return + } + if err = gconv.Scan(metaData, &command); err != nil { + return + } + // Name filed is necessary. + if command.Name == "" { + err = gerror.Newf( + `command name cannot be empty, "name" tag not found in meta of struct "%s"`, + reflect.TypeOf(object).String(), + ) + return + } + if command.Description == "" { + command.Description = metaData[tagNameDc] + } + if command.Additional == "" { + command.Additional = metaData[tagNameAd] + } + return +} + +func newCommandFromMethod(object interface{}, method reflect.Value) (command Command, err error) { var ( reflectType = method.Type() ) @@ -153,28 +174,11 @@ func newCommandFromMethod(object interface{}, method reflect.Value) (command Com } // Command creating. - var ( - metaData = gmeta.Data(inputObject.Interface()) - ) - if err = gconv.Scan(metaData, &command); err != nil { + if command, err = newCommandFromObjectMeta(inputObject.Interface()); err != nil { return } - root = gconv.Bool(metaData[tagNameRoot]) - // Name filed is necessary. - if command.Name == "" { - err = gerror.Newf( - `command name cannot be empty, "name" tag not found in struct "%s"`, - inputObject.Type().String(), - ) - return - } - if command.Description == "" { - command.Description = metaData[tagNameDc] - } - if command.Additional == "" { - command.Additional = metaData[tagNameAd] - } + // Options creating. if command.Options, err = newOptionsFromInput(inputObject.Interface()); err != nil { return } @@ -237,7 +241,7 @@ func newCommandFromMethod(object interface{}, method reflect.Value) (command Com // mergeDefaultStructValue merges the request parameters with default values from struct tag definition. func mergeDefaultStructValue(data map[string]interface{}, pointer interface{}) error { - tagFields, err := structs.TagFields(pointer, defaultValueTags) + tagFields, err := gstructs.TagFields(pointer, defaultValueTags) if err != nil { return err } @@ -262,11 +266,11 @@ func mergeDefaultStructValue(data map[string]interface{}, pointer interface{}) e func newOptionsFromInput(object interface{}) (options []Option, err error) { var ( - fields []structs.Field + fields []gstructs.Field ) - fields, err = structs.Fields(structs.FieldsInput{ + fields, err = gstructs.Fields(gstructs.FieldsInput{ Pointer: object, - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) for _, field := range fields { var ( diff --git a/os/gcmd/gcmd_command_run.go b/os/gcmd/gcmd_command_run.go index 1b1ba3452..d0efb1b59 100644 --- a/os/gcmd/gcmd_command_run.go +++ b/os/gcmd/gcmd_command_run.go @@ -12,7 +12,6 @@ import ( "fmt" "os" - "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/text/gstr" ) @@ -31,6 +30,7 @@ func (c *Command) RunWithValue(ctx context.Context) (value interface{}, err erro } args := parser.GetArgAll() if len(args) == 1 { + // If no arguments passed but binary name, it then prints help. if c.HelpFunc != nil { return nil, c.HelpFunc(ctx, parser) } @@ -78,7 +78,11 @@ func (c *Command) doRun(ctx context.Context, parser *Parser) (value interface{}, if c.FuncWithValue != nil { return c.FuncWithValue(ctx, parser) } - return nil, gerror.New(`no function registered for current command`) + // If no function defined in current command, it then prints help. + if c.HelpFunc != nil { + return nil, c.HelpFunc(ctx, parser) + } + return nil, c.defaultHelpFunc(ctx, parser) } // reParse re-parses the arguments using option configuration of current command. diff --git a/os/gcmd/gcmd_z_unit_feature_object_test.go b/os/gcmd/gcmd_z_unit_feature_object_test.go index d8d220860..a528b1703 100644 --- a/os/gcmd/gcmd_z_unit_feature_object_test.go +++ b/os/gcmd/gcmd_z_unit_feature_object_test.go @@ -19,12 +19,9 @@ import ( "github.com/gogf/gf/v2/test/gtest" ) -type TestCmdObject struct{} - -type TestCmdObjectInput struct { - g.Meta `root:"true" name:"root" usage:"root env/test" brief:"root env command" dc:"description" ad:"ad"` +type TestCmdObject struct { + g.Meta `name:"root" usage:"root env/test" brief:"root env command" dc:"description" ad:"ad"` } -type TestCmdObjectOutput struct{} type TestCmdObjectEnvInput struct { g.Meta `name:"env" usage:"root env" brief:"root env command" dc:"root env command description" ad:"root env command ad"` @@ -39,10 +36,6 @@ type TestCmdObjectTestOutput struct { Content string } -func (TestCmdObject) Root(ctx context.Context, in TestCmdObjectInput) (out *TestCmdObjectOutput, err error) { - return -} - func (TestCmdObject) Env(ctx context.Context, in TestCmdObjectEnvInput) (out *TestCmdObjectEnvOutput, err error) { return } @@ -54,7 +47,23 @@ func (TestCmdObject) Test(ctx context.Context, in TestCmdObjectTestInput) (out * return } -func Test_Command_NewFromObject(t *testing.T) { +func Test_Command_NewFromObject_Help(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + ctx = gctx.New() + cmd, err = gcmd.NewFromObject(&TestCmdObject{}) + ) + t.AssertNil(err) + t.Assert(cmd.Name, "root") + + os.Args = []string{"root"} + value, err := cmd.RunWithValue(ctx) + t.AssertNil(err) + t.Assert(value, nil) + }) +} + +func Test_Command_NewFromObject_RunWithValue(t *testing.T) { gtest.C(t, func(t *gtest.T) { var ( ctx = gctx.New() diff --git a/os/gstructs/gstructs.go b/os/gstructs/gstructs.go new file mode 100644 index 000000000..de1b40b46 --- /dev/null +++ b/os/gstructs/gstructs.go @@ -0,0 +1,54 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// 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 gstructs provides functions for struct information retrieving. +package gstructs + +import ( + "reflect" +) + +// Type wraps reflect.Type for additional features. +type Type struct { + reflect.Type +} + +// Field contains information of a struct field . +type Field struct { + Value reflect.Value // The underlying value of the field. + Field reflect.StructField // The underlying field of the field. + TagValue string // Retrieved tag value. There might be more than one tags in the field, but only one can be retrieved according to calling function rules. +} + +// FieldsInput is the input parameter struct type for function Fields. +type FieldsInput struct { + // Pointer should be type of struct/*struct. + Pointer interface{} + + // RecursiveOption specifies the way retrieving the fields recursively if the attribute + // is an embedded struct. It is RecursiveOptionNone in default. + RecursiveOption int +} + +// FieldMapInput is the input parameter struct type for function FieldMap. +type FieldMapInput struct { + // Pointer should be type of struct/*struct. + Pointer interface{} + + // PriorityTagArray specifies the priority tag array for retrieving from high to low. + // If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name. + PriorityTagArray []string + + // RecursiveOption specifies the way retrieving the fields recursively if the attribute + // is an embedded struct. It is RecursiveOptionNone in default. + RecursiveOption int +} + +const ( + RecursiveOptionNone = 0 // No recursively retrieving fields as map if the field is an embedded struct. + RecursiveOptionEmbedded = 1 // Recursively retrieving fields as map if the field is an embedded struct. + RecursiveOptionEmbeddedNoTag = 2 // Recursively retrieving fields as map if the field is an embedded struct and the field has no tag. +) diff --git a/internal/structs/structs_field.go b/os/gstructs/gstructs_field.go similarity index 82% rename from internal/structs/structs_field.go rename to os/gstructs/gstructs_field.go index e2317f09c..359a3a590 100644 --- a/internal/structs/structs_field.go +++ b/os/gstructs/gstructs_field.go @@ -4,12 +4,14 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package structs +package gstructs import ( "reflect" "regexp" "strings" + + "github.com/gogf/gf/v2/util/gtag" ) const ( @@ -17,13 +19,17 @@ const ( ) var ( - tagMapRegex, _ = regexp.Compile(`([\w\-]+):"(.+?)"`) + tagMapRegex = regexp.MustCompile(`([\w\-]+):"(.+?)"`) ) // 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) + s := f.Field.Tag.Get(key) + if s != "" { + s = gtag.Parse(s) + } + return s } // TagJsonName returns the `json` tag name string of the field. @@ -41,7 +47,11 @@ func (f *Field) TagJsonName() string { // the tag string. If the tag does not have the conventional format, // the value returned by Lookup is unspecified. func (f *Field) TagLookup(key string) (value string, ok bool) { - return f.Field.Tag.Lookup(key) + value, ok = f.Field.Tag.Lookup(key) + if ok && value != "" { + value = gtag.Parse(value) + } + return } // IsEmbedded returns true if the given field is an anonymous field (embedded) @@ -62,7 +72,7 @@ func (f *Field) TagMap() map[string]string { ) for _, m := range match { if len(m) == 3 { - data[m[1]] = m[2] + data[m[1]] = gtag.Parse(m[2]) } } return data @@ -73,12 +83,13 @@ func (f *Field) IsExported() bool { return f.Field.PkgPath == "" } -// Name returns the name of the given field +// Name returns the name of the given field. func (f *Field) Name() string { return f.Field.Name } -// Type returns the type of the given field +// Type returns the type of the given field. +// Note that this Type is not reflect.Type. If you need reflect.Type, please use Field.Type().Type. func (f *Field) Type() Type { return Type{ Type: f.Field.Type, @@ -103,34 +114,6 @@ func (f *Field) OriginalKind() reflect.Kind { return kind } -const ( - RecursiveOptionNone = 0 // No recursively retrieving fields as map if the field is an embedded struct. - RecursiveOptionEmbedded = 1 // Recursively retrieving fields as map if the field is an embedded struct. - RecursiveOptionEmbeddedNoTag = 2 // Recursively retrieving fields as map if the field is an embedded struct and the field has no tag. -) - -type FieldsInput struct { - // Pointer should be type of struct/*struct. - Pointer interface{} - - // RecursiveOption specifies the way retrieving the fields recursively if the attribute - // is an embedded struct. It is RecursiveOptionNone in default. - RecursiveOption int -} - -type FieldMapInput struct { - // Pointer should be type of struct/*struct. - Pointer interface{} - - // PriorityTagArray specifies the priority tag array for retrieving from high to low. - // If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name. - PriorityTagArray []string - - // RecursiveOption specifies the way retrieving the fields recursively if the attribute - // is an embedded struct. It is RecursiveOptionNone in default. - RecursiveOption int -} - // Fields retrieves and returns the fields of `pointer` as slice. func Fields(in FieldsInput) ([]Field, error) { var ( @@ -169,6 +152,7 @@ func Fields(in FieldsInput) ([]Field, error) { break } fallthrough + case RecursiveOptionEmbedded: structFields, err := Fields(FieldsInput{ Pointer: field.Value, @@ -249,6 +233,7 @@ func FieldMap(in FieldMapInput) (map[string]Field, error) { break } fallthrough + case RecursiveOptionEmbedded: m, err := FieldMap(FieldMapInput{ Pointer: field.Value, diff --git a/internal/structs/structs_tag.go b/os/gstructs/gstructs_tag.go similarity index 97% rename from internal/structs/structs_tag.go rename to os/gstructs/gstructs_tag.go index 299c3ba2c..8621ad9e0 100644 --- a/internal/structs/structs_tag.go +++ b/os/gstructs/gstructs_tag.go @@ -4,16 +4,19 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package structs +package gstructs import ( "errors" "reflect" "strconv" + + "github.com/gogf/gf/v2/util/gtag" ) // ParseTag parses tag string into map. -// For example, tag ParseTag(`v:"required" p:"id" d:"1"`) => map[v:required p:id d:1]. +// For example: +// ParseTag(`v:"required" p:"id" d:"1"`) => map[v:required p:id d:1]. func ParseTag(tag string) map[string]string { var ( key string @@ -60,7 +63,7 @@ func ParseTag(tag string) map[string]string { if err != nil { panic(err) } - data[key] = value + data[key] = gtag.Parse(value) } return data } diff --git a/internal/structs/structs_type.go b/os/gstructs/gstructs_type.go similarity index 99% rename from internal/structs/structs_type.go rename to os/gstructs/gstructs_type.go index 40cb02050..b1ab79204 100644 --- a/internal/structs/structs_type.go +++ b/os/gstructs/gstructs_type.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package structs +package gstructs import ( "errors" diff --git a/internal/structs/structs_z_bench_test.go b/os/gstructs/gstructs_z_bench_test.go similarity index 76% rename from internal/structs/structs_z_bench_test.go rename to os/gstructs/gstructs_z_bench_test.go index 8ffa0d672..17ab8a854 100644 --- a/internal/structs/structs_z_bench_test.go +++ b/os/gstructs/gstructs_z_bench_test.go @@ -4,11 +4,12 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package structs_test +package gstructs_test import ( - "github.com/gogf/gf/v2/internal/structs" "testing" + + "github.com/gogf/gf/v2/os/gstructs" ) type User struct { @@ -24,12 +25,12 @@ var ( func Benchmark_TagFields(b *testing.B) { for i := 0; i < b.N; i++ { - structs.TagFields(user, []string{"params", "my-tag1"}) + gstructs.TagFields(user, []string{"params", "my-tag1"}) } } func Benchmark_TagFields_NilPointer(b *testing.B) { for i := 0; i < b.N; i++ { - structs.TagFields(&userNilPointer, []string{"params", "my-tag1"}) + gstructs.TagFields(&userNilPointer, []string{"params", "my-tag1"}) } } diff --git a/internal/structs/structs_z_unit_test.go b/os/gstructs/gstructs_z_unit_test.go similarity index 76% rename from internal/structs/structs_z_unit_test.go rename to os/gstructs/gstructs_z_unit_test.go index 1668e8b10..ab35666f6 100644 --- a/internal/structs/structs_z_unit_test.go +++ b/os/gstructs/gstructs_z_unit_test.go @@ -4,12 +4,12 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package structs_test +package gstructs_test import ( "testing" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/frame/g" @@ -24,16 +24,16 @@ func Test_Basic(t *testing.T) { Pass string `my-tag1:"pass1" my-tag2:"pass2" params:"pass"` } var user User - m, _ := structs.TagMapName(user, []string{"params"}) + m, _ := gstructs.TagMapName(user, []string{"params"}) t.Assert(m, g.Map{"name": "Name", "pass": "Pass"}) - m, _ = structs.TagMapName(&user, []string{"params"}) + m, _ = gstructs.TagMapName(&user, []string{"params"}) t.Assert(m, g.Map{"name": "Name", "pass": "Pass"}) - m, _ = structs.TagMapName(&user, []string{"params", "my-tag1"}) + m, _ = gstructs.TagMapName(&user, []string{"params", "my-tag1"}) t.Assert(m, g.Map{"name": "Name", "pass": "Pass"}) - m, _ = structs.TagMapName(&user, []string{"my-tag1", "params"}) + m, _ = gstructs.TagMapName(&user, []string{"my-tag1", "params"}) t.Assert(m, g.Map{"name": "Name", "pass1": "Pass"}) - m, _ = structs.TagMapName(&user, []string{"my-tag2", "params"}) + m, _ = gstructs.TagMapName(&user, []string{"my-tag2", "params"}) t.Assert(m, g.Map{"name": "Name", "pass2": "Pass"}) }) @@ -48,7 +48,7 @@ func Test_Basic(t *testing.T) { Base `params:"base"` } user := new(UserWithBase) - m, _ := structs.TagMapName(user, []string{"params"}) + m, _ := gstructs.TagMapName(user, []string{"params"}) t.Assert(m, g.Map{ "base": "Base", "password1": "Pass1", @@ -73,9 +73,9 @@ func Test_Basic(t *testing.T) { } user1 := new(UserWithEmbeddedAttribute) user2 := new(UserWithoutEmbeddedAttribute) - m, _ := structs.TagMapName(user1, []string{"params"}) + m, _ := gstructs.TagMapName(user1, []string{"params"}) t.Assert(m, g.Map{"password1": "Pass1", "password2": "Pass2"}) - m, _ = structs.TagMapName(user2, []string{"params"}) + m, _ = gstructs.TagMapName(user2, []string{"params"}) t.Assert(m, g.Map{}) }) } @@ -88,16 +88,16 @@ func Test_StructOfNilPointer(t *testing.T) { Pass string `my-tag1:"pass1" my-tag2:"pass2" params:"pass"` } var user *User - m, _ := structs.TagMapName(user, []string{"params"}) + m, _ := gstructs.TagMapName(user, []string{"params"}) t.Assert(m, g.Map{"name": "Name", "pass": "Pass"}) - m, _ = structs.TagMapName(&user, []string{"params"}) + m, _ = gstructs.TagMapName(&user, []string{"params"}) t.Assert(m, g.Map{"name": "Name", "pass": "Pass"}) - m, _ = structs.TagMapName(&user, []string{"params", "my-tag1"}) + m, _ = gstructs.TagMapName(&user, []string{"params", "my-tag1"}) t.Assert(m, g.Map{"name": "Name", "pass": "Pass"}) - m, _ = structs.TagMapName(&user, []string{"my-tag1", "params"}) + m, _ = gstructs.TagMapName(&user, []string{"my-tag1", "params"}) t.Assert(m, g.Map{"name": "Name", "pass1": "Pass"}) - m, _ = structs.TagMapName(&user, []string{"my-tag2", "params"}) + m, _ = gstructs.TagMapName(&user, []string{"my-tag2", "params"}) t.Assert(m, g.Map{"name": "Name", "pass2": "Pass"}) }) } @@ -110,7 +110,7 @@ func Test_Fields(t *testing.T) { Pass string `my-tag1:"pass1" my-tag2:"pass2" params:"pass"` } var user *User - fields, _ := structs.Fields(structs.FieldsInput{ + fields, _ := gstructs.Fields(gstructs.FieldsInput{ Pointer: user, RecursiveOption: 0, }) @@ -136,9 +136,9 @@ func Test_Fields_WithEmbedded1(t *testing.T) { B // Should be put here to validate its index. Score int64 } - r, err := structs.Fields(structs.FieldsInput{ + r, err := gstructs.Fields(gstructs.FieldsInput{ Pointer: new(A), - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) t.AssertNil(err) t.Assert(len(r), 4) @@ -172,9 +172,9 @@ func Test_Fields_WithEmbedded2(t *testing.T) { } gtest.C(t, func(t *gtest.T) { - r, err := structs.Fields(structs.FieldsInput{ + r, err := gstructs.Fields(gstructs.FieldsInput{ Pointer: new(MetaNodeItem), - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) t.AssertNil(err) t.Assert(len(r), 4) @@ -201,9 +201,9 @@ func Test_Fields_WithEmbedded_Filter(t *testing.T) { B // Should be put here to validate its index. Score int64 } - r, err := structs.Fields(structs.FieldsInput{ + r, err := gstructs.Fields(gstructs.FieldsInput{ Pointer: new(A), - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) t.AssertNil(err) t.Assert(len(r), 4) @@ -222,10 +222,10 @@ func Test_FieldMap(t *testing.T) { Pass string `my-tag1:"pass1" my-tag2:"pass2" params:"pass"` } var user *User - m, _ := structs.FieldMap(structs.FieldMapInput{ + m, _ := gstructs.FieldMap(gstructs.FieldMapInput{ Pointer: user, PriorityTagArray: []string{"params"}, - RecursiveOption: structs.RecursiveOptionEmbedded, + RecursiveOption: gstructs.RecursiveOptionEmbedded, }) t.Assert(len(m), 3) _, ok := m["Id"] @@ -246,10 +246,10 @@ func Test_FieldMap(t *testing.T) { Pass string `my-tag1:"pass1" my-tag2:"pass2" params:"pass"` } var user *User - m, _ := structs.FieldMap(structs.FieldMapInput{ + m, _ := gstructs.FieldMap(gstructs.FieldMapInput{ Pointer: user, PriorityTagArray: nil, - RecursiveOption: structs.RecursiveOptionEmbedded, + RecursiveOption: gstructs.RecursiveOptionEmbedded, }) t.Assert(len(m), 3) _, ok := m["Id"] @@ -273,9 +273,9 @@ func Test_StructType(t *testing.T) { type A struct { B } - r, err := structs.StructType(new(A)) + r, err := gstructs.StructType(new(A)) t.AssertNil(err) - t.Assert(r.Signature(), `github.com/gogf/gf/v2/internal/structs_test/structs_test.A`) + t.Assert(r.Signature(), `github.com/gogf/gf/v2/os/gstructs_test/gstructs_test.A`) }) gtest.C(t, func(t *gtest.T) { type B struct { @@ -284,9 +284,9 @@ func Test_StructType(t *testing.T) { type A struct { B } - r, err := structs.StructType(new(A).B) + r, err := gstructs.StructType(new(A).B) t.AssertNil(err) - t.Assert(r.Signature(), `github.com/gogf/gf/v2/internal/structs_test/structs_test.B`) + t.Assert(r.Signature(), `github.com/gogf/gf/v2/os/gstructs_test/gstructs_test.B`) }) gtest.C(t, func(t *gtest.T) { type B struct { @@ -295,9 +295,9 @@ func Test_StructType(t *testing.T) { type A struct { *B } - r, err := structs.StructType(new(A).B) + r, err := gstructs.StructType(new(A).B) t.AssertNil(err) - t.Assert(r.String(), `structs_test.B`) + t.Assert(r.String(), `gstructs_test.B`) }) // Error. gtest.C(t, func(t *gtest.T) { @@ -308,7 +308,7 @@ func Test_StructType(t *testing.T) { *B Id int } - _, err := structs.StructType(new(A).Id) + _, err := gstructs.StructType(new(A).Id) t.AssertNE(err, nil) }) } @@ -321,9 +321,9 @@ func Test_StructTypeBySlice(t *testing.T) { type A struct { Array []*B } - r, err := structs.StructType(new(A).Array) + r, err := gstructs.StructType(new(A).Array) t.AssertNil(err) - t.Assert(r.Signature(), `github.com/gogf/gf/v2/internal/structs_test/structs_test.B`) + t.Assert(r.Signature(), `github.com/gogf/gf/v2/os/gstructs_test/gstructs_test.B`) }) gtest.C(t, func(t *gtest.T) { type B struct { @@ -332,9 +332,9 @@ func Test_StructTypeBySlice(t *testing.T) { type A struct { Array []B } - r, err := structs.StructType(new(A).Array) + r, err := gstructs.StructType(new(A).Array) t.AssertNil(err) - t.Assert(r.Signature(), `github.com/gogf/gf/v2/internal/structs_test/structs_test.B`) + t.Assert(r.Signature(), `github.com/gogf/gf/v2/os/gstructs_test/gstructs_test.B`) }) gtest.C(t, func(t *gtest.T) { type B struct { @@ -343,9 +343,9 @@ func Test_StructTypeBySlice(t *testing.T) { type A struct { Array *[]B } - r, err := structs.StructType(new(A).Array) + r, err := gstructs.StructType(new(A).Array) t.AssertNil(err) - t.Assert(r.Signature(), `github.com/gogf/gf/v2/internal/structs_test/structs_test.B`) + t.Assert(r.Signature(), `github.com/gogf/gf/v2/os/gstructs_test/gstructs_test.B`) }) } @@ -358,7 +358,7 @@ func TestType_FieldKeys(t *testing.T) { type A struct { Array []*B } - r, err := structs.StructType(new(A).Array) + r, err := gstructs.StructType(new(A).Array) t.AssertNil(err) t.Assert(r.FieldKeys(), g.Slice{"Id", "Name"}) }) @@ -370,7 +370,7 @@ func TestType_TagMap(t *testing.T) { Id int `d:"123" description:"I love gf"` Name string `v:"required" description:"应用Id"` } - r, err := structs.Fields(structs.FieldsInput{ + r, err := gstructs.Fields(gstructs.FieldsInput{ Pointer: new(A), RecursiveOption: 0, }) diff --git a/protocol/goai/goai_parameter.go b/protocol/goai/goai_parameter.go index 0cd8e1a0b..5350e5830 100644 --- a/protocol/goai/goai_parameter.go +++ b/protocol/goai/goai_parameter.go @@ -12,7 +12,7 @@ import ( "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" ) @@ -43,7 +43,7 @@ type ParameterRef struct { Value *Parameter } -func (oai *OpenApiV3) newParameterRefWithStructMethod(field structs.Field, path, method string) (*ParameterRef, error) { +func (oai *OpenApiV3) newParameterRefWithStructMethod(field gstructs.Field, path, method string) (*ParameterRef, error) { var ( tagMap = field.TagMap() parameter = &Parameter{ diff --git a/protocol/goai/goai_path.go b/protocol/goai/goai_path.go index 85dbef284..9fd305a73 100644 --- a/protocol/goai/goai_path.go +++ b/protocol/goai/goai_path.go @@ -11,7 +11,7 @@ import ( "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gmeta" @@ -182,9 +182,9 @@ func (oai *OpenApiV3) addPath(in addPathInput) error { } } // It also sets request parameters. - structFields, _ := structs.Fields(structs.FieldsInput{ + structFields, _ := gstructs.Fields(gstructs.FieldsInput{ Pointer: inputObject.Interface(), - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) for _, structField := range structFields { if operation.Parameters == nil { diff --git a/protocol/goai/goai_requestbody.go b/protocol/goai/goai_requestbody.go index d159a6ed2..e3c47aa81 100644 --- a/protocol/goai/goai_requestbody.go +++ b/protocol/goai/goai_requestbody.go @@ -10,7 +10,7 @@ import ( "reflect" "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/text/gstr" ) @@ -59,9 +59,9 @@ func (oai *OpenApiV3) getRequestSchemaRef(in getRequestSchemaRefInput) (*SchemaR schema.Properties[k] = v } } else { - structFields, _ := structs.Fields(structs.FieldsInput{ + structFields, _ := gstructs.Fields(gstructs.FieldsInput{ Pointer: in.RequestObject, - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) for _, structField := range structFields { var ( diff --git a/protocol/goai/goai_response.go b/protocol/goai/goai_response.go index 5c9940158..e85b04254 100644 --- a/protocol/goai/goai_response.go +++ b/protocol/goai/goai_response.go @@ -10,7 +10,7 @@ import ( "reflect" "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/text/gstr" ) @@ -63,9 +63,9 @@ func (oai *OpenApiV3) getResponseSchemaRef(in getResponseSchemaRefInput) (*Schem schema.Properties[k] = v } } else { - structFields, _ := structs.Fields(structs.FieldsInput{ + structFields, _ := gstructs.Fields(gstructs.FieldsInput{ Pointer: in.ResponseObject, - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) for _, structField := range structFields { var ( diff --git a/protocol/goai/goai_shema.go b/protocol/goai/goai_shema.go index 1a6192750..1e0ef9e78 100644 --- a/protocol/goai/goai_shema.go +++ b/protocol/goai/goai_shema.go @@ -11,7 +11,7 @@ import ( "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gmeta" @@ -105,9 +105,9 @@ func (oai *OpenApiV3) doAddSchemaSingle(object interface{}) error { // structToSchema converts and returns given struct object as Schema. func (oai *OpenApiV3) structToSchema(object interface{}) (*Schema, error) { - structFields, _ := structs.Fields(structs.FieldsInput{ + structFields, _ := gstructs.Fields(gstructs.FieldsInput{ Pointer: object, - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) var ( tagMap = gmeta.Data(object) diff --git a/util/gconv/gconv_scan.go b/util/gconv/gconv_scan.go index 25555da65..4cfa30cb7 100644 --- a/util/gconv/gconv_scan.go +++ b/util/gconv/gconv_scan.go @@ -12,8 +12,8 @@ import ( "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/structs" "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/os/gstructs" ) // Scan automatically checks the type of `pointer` and converts `params` to `pointer`. It supports `pointer` @@ -384,9 +384,9 @@ func doScanList(structSlice interface{}, structSlicePointer interface{}, bindToA relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName) if !relationFromAttrField.IsValid() { var ( - filedMap, _ = structs.FieldMap(structs.FieldMapInput{ + filedMap, _ = gstructs.FieldMap(gstructs.FieldMapInput{ Pointer: relationFromAttrValue, - RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag, }) ) if key, _ := utils.MapPossibleItemByKey(Map(filedMap), relationBindToFieldName); key == "" { diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index 5526b34d8..b4c74755d 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -14,8 +14,8 @@ import ( "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/structs" "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/os/gstructs" ) // Struct maps the params key-value pairs to the corresponding struct object's attributes. @@ -237,7 +237,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string } else { priorityTagArray = StructTagPriority } - tagToNameMap, err := structs.TagMapName(pointerElemReflectValue, priorityTagArray) + tagToNameMap, err := gstructs.TagMapName(pointerElemReflectValue, priorityTagArray) if err != nil { return err } diff --git a/util/gmeta/gmeta.go b/util/gmeta/gmeta.go index d7419a10a..9ee4d8610 100644 --- a/util/gmeta/gmeta.go +++ b/util/gmeta/gmeta.go @@ -9,7 +9,7 @@ package gmeta import ( "github.com/gogf/gf/v2/container/gvar" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" ) // Meta is used as an embedded attribute for struct to enabled metadata feature. @@ -22,19 +22,12 @@ const ( // Data retrieves and returns all metadata from `object`. func Data(object interface{}) map[string]string { - reflectType, err := structs.StructType(object) + reflectType, err := gstructs.StructType(object) if err != nil { return nil } if field, ok := reflectType.FieldByName(metaAttributeName); ok { - var ( - tags = structs.ParseTag(string(field.Tag)) - data = make(map[string]string, len(tags)) - ) - for k, v := range tags { - data[k] = v - } - return data + return gstructs.ParseTag(string(field.Tag)) } return map[string]string{} } diff --git a/util/gtag/gtag.go b/util/gtag/gtag.go new file mode 100644 index 000000000..4dce4aab9 --- /dev/null +++ b/util/gtag/gtag.go @@ -0,0 +1,60 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// 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 gtag providing tag content storing for struct. +// +// Note that calling functions of this package is concurrently safe. +package gtag + +import ( + "regexp" + "sync" +) + +var ( + mu sync.RWMutex + data = make(map[string]string) + regex = regexp.MustCompile(`\{(.+?)\}`) +) + +// Set sets tag content for specified name. +func Set(name, value string) { + mu.Lock() + defer mu.Unlock() + data[name] = value +} + +// Sets sets multiple tag content by map. +func Sets(m map[string]string) { + mu.Lock() + defer mu.Unlock() + for k, v := range m { + data[k] = v + } +} + +// Get retrieves and returns the stored tag content for specified name. +func Get(name string) string { + mu.RLock() + defer mu.RUnlock() + return data[name] +} + +// Parse parses and returns the content by replacing all tag name variable to +// its content for given `content`. +// Eg: +// If "Demo:content" in tag mapping, +// Parse(`This is {Demo}`) -> `This is content`. +func Parse(content string) string { + mu.RLock() + defer mu.RUnlock() + return regex.ReplaceAllStringFunc(content, func(s string) string { + if v, ok := data[s[1:len(s)-1]]; ok { + return v + } + return s + }) +} diff --git a/util/gtag/gtag_z_unit_test.go b/util/gtag/gtag_z_unit_test.go new file mode 100644 index 000000000..d38c9cb81 --- /dev/null +++ b/util/gtag/gtag_z_unit_test.go @@ -0,0 +1,59 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// 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 gtag_test + +import ( + "fmt" + "testing" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/util/gtag" +) + +func Test_Set_Get(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + k := gtime.TimestampNanoStr() + v := gtime.TimestampNanoStr() + gtag.Set(k, v) + t.Assert(gtag.Get(k), v) + }) +} + +func Test_Sets_Get(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + k1 := gtime.TimestampNanoStr() + k2 := gtime.TimestampNanoStr() + v1 := gtime.TimestampNanoStr() + v2 := gtime.TimestampNanoStr() + gtag.Sets(g.MapStrStr{ + k1: v1, + k2: v2, + }) + t.Assert(gtag.Get(k1), v1) + t.Assert(gtag.Get(k2), v2) + }) +} + +func Test_Parse(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + k1 = gtime.TimestampNanoStr() + k2 = gtime.TimestampNanoStr() + v1 = gtime.TimestampNanoStr() + v2 = gtime.TimestampNanoStr() + content = fmt.Sprintf(`this is {%s} and {%s}`, k1, k2) + expect = fmt.Sprintf(`this is %s and %s`, v1, v2) + ) + gtag.Sets(g.MapStrStr{ + k1: v1, + k2: v2, + }) + t.Assert(gtag.Parse(content), expect) + }) +} diff --git a/util/gutil/gutil_dump.go b/util/gutil/gutil_dump.go index e5ee3f41b..f22ab31a3 100644 --- a/util/gutil/gutil_dump.go +++ b/util/gutil/gutil_dump.go @@ -13,7 +13,7 @@ import ( "reflect" "strings" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/text/gstr" ) @@ -261,9 +261,9 @@ func doDumpMap(in doDumpInternalInput) { } func doDumpStruct(in doDumpInternalInput) { - structFields, _ := structs.Fields(structs.FieldsInput{ + structFields, _ := gstructs.Fields(gstructs.FieldsInput{ Pointer: in.Value, - RecursiveOption: structs.RecursiveOptionEmbedded, + RecursiveOption: gstructs.RecursiveOptionEmbedded, }) if len(structFields) == 0 { var ( diff --git a/util/gvalid/gvalid_validator_check_struct.go b/util/gvalid/gvalid_validator_check_struct.go index c2a541ef5..6a43b2b11 100644 --- a/util/gvalid/gvalid_validator_check_struct.go +++ b/util/gvalid/gvalid_validator_check_struct.go @@ -12,7 +12,7 @@ import ( "strings" "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/internal/structs" + "github.com/gogf/gf/v2/os/gstructs" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gutil" ) @@ -23,17 +23,17 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error fieldToAliasNameMap = make(map[string]string) // Field names to alias name map. resultSequenceRules = make([]fieldRule, 0) ) - fieldMap, err := structs.FieldMap(structs.FieldMapInput{ + fieldMap, err := gstructs.FieldMap(gstructs.FieldMapInput{ Pointer: object, PriorityTagArray: aliasNameTagPriority, - RecursiveOption: structs.RecursiveOptionEmbedded, + RecursiveOption: gstructs.RecursiveOptionEmbedded, }) if err != nil { return newValidationErrorByStr(internalObjectErrRuleName, err) } - // It here must use structs.TagFields not structs.FieldMap to ensure error sequence. - tagFields, err := structs.TagFields(object, structTagPriority) + // It here must use gstructs.TagFields not gstructs.FieldMap to ensure error sequence. + tagFields, err := gstructs.TagFields(object, structTagPriority) if err != nil { return newValidationErrorByStr(internalObjectErrRuleName, err) }