mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
expose package internal/structs as os/gstructs; add package gtag for custom tag storage feature
This commit is contained in:
@ -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) {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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.
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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...)
|
||||
}
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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()
|
||||
|
||||
54
os/gstructs/gstructs.go
Normal file
54
os/gstructs/gstructs.go
Normal file
@ -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.
|
||||
)
|
||||
@ -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,
|
||||
@ -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
|
||||
}
|
||||
@ -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"
|
||||
@ -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"})
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
})
|
||||
@ -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{
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 == "" {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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{}
|
||||
}
|
||||
|
||||
60
util/gtag/gtag.go
Normal file
60
util/gtag/gtag.go
Normal file
@ -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
|
||||
})
|
||||
}
|
||||
59
util/gtag/gtag_z_unit_test.go
Normal file
59
util/gtag/gtag_z_unit_test.go
Normal file
@ -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)
|
||||
})
|
||||
}
|
||||
@ -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 (
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user