mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
object feature for package gcmd
This commit is contained in:
@ -123,7 +123,7 @@ type FieldMapInput 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.
|
||||
// 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
|
||||
@ -132,12 +132,12 @@ type FieldMapInput struct {
|
||||
}
|
||||
|
||||
// Fields retrieves and returns the fields of `pointer` as slice.
|
||||
func Fields(in FieldsInput) ([]*Field, error) {
|
||||
func Fields(in FieldsInput) ([]Field, error) {
|
||||
var (
|
||||
ok bool
|
||||
fieldFilterMap = make(map[string]struct{})
|
||||
retrievedFields = make([]*Field, 0)
|
||||
currentLevelFieldMap = make(map[string]*Field)
|
||||
retrievedFields = make([]Field, 0)
|
||||
currentLevelFieldMap = make(map[string]Field)
|
||||
)
|
||||
rangeFields, err := getFieldValues(in.Pointer)
|
||||
if err != nil {
|
||||
@ -187,7 +187,7 @@ func Fields(in FieldsInput) ([]*Field, error) {
|
||||
continue
|
||||
}
|
||||
fieldFilterMap[fieldName] = struct{}{}
|
||||
if v := currentLevelFieldMap[fieldName]; v == nil {
|
||||
if v, ok := currentLevelFieldMap[fieldName]; !ok {
|
||||
retrievedFields = append(retrievedFields, structField)
|
||||
} else {
|
||||
retrievedFields = append(retrievedFields, v)
|
||||
@ -204,25 +204,25 @@ func Fields(in FieldsInput) ([]*Field, error) {
|
||||
return retrievedFields, nil
|
||||
}
|
||||
|
||||
// FieldMap retrieves and returns struct field as map[name/tag]*Field from `pointer`.
|
||||
// FieldMap retrieves and returns struct field as map[name/tag]Field from `pointer`.
|
||||
//
|
||||
// The parameter `pointer` should be type of struct/*struct.
|
||||
//
|
||||
// The parameter `priority` 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.
|
||||
// If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.
|
||||
//
|
||||
// The parameter `recursive` specifies the whether retrieving the fields recursively if the attribute
|
||||
// is an embedded struct.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter up-case from struct.
|
||||
func FieldMap(in FieldMapInput) (map[string]*Field, error) {
|
||||
func FieldMap(in FieldMapInput) (map[string]Field, error) {
|
||||
fields, err := getFieldValues(in.Pointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
tagValue = ""
|
||||
mapField = make(map[string]*Field)
|
||||
mapField = make(map[string]Field)
|
||||
)
|
||||
for _, field := range fields {
|
||||
// Only retrieve exported attributes.
|
||||
|
||||
@ -65,14 +65,14 @@ func ParseTag(tag string) map[string]string {
|
||||
return data
|
||||
}
|
||||
|
||||
// TagFields retrieves and returns struct tags as []*Field from `pointer`.
|
||||
// TagFields retrieves and returns struct tags as []Field from `pointer`.
|
||||
//
|
||||
// The parameter `pointer` should be type of struct/*struct.
|
||||
//
|
||||
// Note that,
|
||||
// 1. It only retrieves the exported attributes with first letter up-case from struct.
|
||||
// 2. The parameter `priority` should be given, it only retrieves fields that has given tag.
|
||||
func TagFields(pointer interface{}, priority []string) ([]*Field, error) {
|
||||
func TagFields(pointer interface{}, priority []string) ([]Field, error) {
|
||||
return getFieldValuesByTagPriority(pointer, priority, map[string]struct{}{})
|
||||
}
|
||||
|
||||
@ -95,18 +95,18 @@ func TagMapName(pointer interface{}, priority []string) (map[string]string, erro
|
||||
return tagMap, nil
|
||||
}
|
||||
|
||||
// TagMapField retrieves struct tags as map[tag]*Field from `pointer`, and returns it.
|
||||
// TagMapField retrieves struct tags as map[tag]Field from `pointer`, and returns it.
|
||||
// The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.
|
||||
//
|
||||
// Note that,
|
||||
// 1. It only retrieves the exported attributes with first letter up-case from struct.
|
||||
// 2. The parameter `priority` should be given, it only retrieves fields that has given tag.
|
||||
func TagMapField(object interface{}, priority []string) (map[string]*Field, error) {
|
||||
func TagMapField(object interface{}, priority []string) (map[string]Field, error) {
|
||||
fields, err := TagFields(object, priority)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tagMap := make(map[string]*Field, len(fields))
|
||||
tagMap := make(map[string]Field, len(fields))
|
||||
for _, field := range fields {
|
||||
tagField := field
|
||||
tagMap[field.TagValue] = tagField
|
||||
@ -114,7 +114,7 @@ func TagMapField(object interface{}, priority []string) (map[string]*Field, erro
|
||||
return tagMap, nil
|
||||
}
|
||||
|
||||
func getFieldValues(value interface{}) ([]*Field, error) {
|
||||
func getFieldValues(value interface{}) ([]Field, error) {
|
||||
var (
|
||||
reflectValue reflect.Value
|
||||
reflectKind reflect.Kind
|
||||
@ -156,10 +156,10 @@ exitLoop:
|
||||
var (
|
||||
structType = reflectValue.Type()
|
||||
length = reflectValue.NumField()
|
||||
fields = make([]*Field, length)
|
||||
fields = make([]Field, length)
|
||||
)
|
||||
for i := 0; i < length; i++ {
|
||||
fields[i] = &Field{
|
||||
fields[i] = Field{
|
||||
Value: reflectValue.Field(i),
|
||||
Field: structType.Field(i),
|
||||
}
|
||||
@ -167,14 +167,14 @@ exitLoop:
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
func getFieldValuesByTagPriority(pointer interface{}, priority []string, tagMap map[string]struct{}) ([]*Field, error) {
|
||||
func getFieldValuesByTagPriority(pointer interface{}, priority []string, tagMap map[string]struct{}) ([]Field, error) {
|
||||
fields, err := getFieldValues(pointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
tagValue = ""
|
||||
tagFields = make([]*Field, 0)
|
||||
tagFields = make([]Field, 0)
|
||||
)
|
||||
for _, field := range fields {
|
||||
// Only retrieve exported attributes.
|
||||
|
||||
@ -12,53 +12,42 @@ 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/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gmeta"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
|
||||
const (
|
||||
tagNameName = `name`
|
||||
tagNameUsage = `usage`
|
||||
tagNameBrief = `brief`
|
||||
tagNameShort = `short`
|
||||
tagNameOrphan = `orphan`
|
||||
tagNameDescription = `description`
|
||||
tagNameDc = `dc`
|
||||
tagNameAddition = `additional`
|
||||
tagNameAd = `ad`
|
||||
tagNameDc = `dc`
|
||||
tagNameAd = `ad`
|
||||
)
|
||||
|
||||
func (c *Command) AddObject(objects ...interface{}) (err error) {
|
||||
for _, object := range objects {
|
||||
if err = c.doAddObject(object); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Command) doAddObject(object interface{}) error {
|
||||
func CommandsFromObject(object interface{}) (commands []Command, err error) {
|
||||
originValueAndKind := utils.OriginValueAndKind(object)
|
||||
if originValueAndKind.OriginKind != reflect.Struct {
|
||||
return gerror.Newf(
|
||||
return nil, gerror.Newf(
|
||||
`input object should be type of struct, but got "%s"`,
|
||||
originValueAndKind.InputValue.Type().String(),
|
||||
)
|
||||
}
|
||||
for i := 0; i < originValueAndKind.InputValue.NumMethod(); i++ {
|
||||
method := originValueAndKind.InputValue.Method(i)
|
||||
}
|
||||
for _, field := range fields {
|
||||
|
||||
}
|
||||
return nil
|
||||
//for i := 0; i < originValueAndKind.InputValue.NumMethod(); i++ {
|
||||
// method := originValueAndKind.InputValue.Method(i)
|
||||
//}
|
||||
//for _, field := range fields {
|
||||
//
|
||||
//}
|
||||
return
|
||||
}
|
||||
|
||||
func newCommandFromMethod(object, method reflect.Value) (cmd *Command, err error) {
|
||||
func newCommandFromMethod(object, method reflect.Value) (*Command, error) {
|
||||
var (
|
||||
err error
|
||||
reflectType = method.Type()
|
||||
)
|
||||
// Necessary validation for input/output parameters and naming.
|
||||
if reflectType.NumIn() != 2 || reflectType.NumOut() != 2 {
|
||||
if reflectType.PkgPath() != "" {
|
||||
err = gerror.NewCodef(
|
||||
@ -73,27 +62,24 @@ func newCommandFromMethod(object, method reflect.Value) (cmd *Command, err error
|
||||
reflectType.String(),
|
||||
)
|
||||
}
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if reflectType.In(0).String() != "context.Context" {
|
||||
err = gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`invalid handler: defined as "%s", but the first input parameter should be type of "context.Context"`,
|
||||
reflectType.String(),
|
||||
)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if reflectType.Out(1).String() != "error" {
|
||||
err = gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`invalid handler: defined as "%s", but the last output parameter should be type of "error"`,
|
||||
reflectType.String(),
|
||||
)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The input struct should be named as `xxxInput`.
|
||||
if !gstr.HasSuffix(reflectType.In(1).String(), `Input`) {
|
||||
err = gerror.NewCodef(
|
||||
@ -101,9 +87,8 @@ func newCommandFromMethod(object, method reflect.Value) (cmd *Command, err error
|
||||
`invalid struct naming for input: defined as "%s", but it should be named with "Input" suffix like "xxxInput"`,
|
||||
reflectType.In(1).String(),
|
||||
)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The output struct should be named as `xxxOutput`.
|
||||
if !gstr.HasSuffix(reflectType.Out(0).String(), `Output`) {
|
||||
err = gerror.NewCodef(
|
||||
@ -111,9 +96,72 @@ func newCommandFromMethod(object, method reflect.Value) (cmd *Command, err error
|
||||
`invalid struct naming for output: defined as "%s", but it should be named with "Output" suffix like "xxxOutput"`,
|
||||
reflectType.Out(0).String(),
|
||||
)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
metaMap = gmeta.Data()
|
||||
inputObject reflect.Value
|
||||
outputObject reflect.Value
|
||||
)
|
||||
if method.Type().In(1).Kind() == reflect.Ptr {
|
||||
inputObject = reflect.New(method.Type().In(1).Elem()).Elem()
|
||||
} else {
|
||||
inputObject = reflect.New(method.Type().In(1)).Elem()
|
||||
}
|
||||
|
||||
if method.Type().Out(1).Kind() == reflect.Ptr {
|
||||
outputObject = reflect.New(method.Type().Out(0).Elem()).Elem()
|
||||
} else {
|
||||
outputObject = reflect.New(method.Type().Out(0)).Elem()
|
||||
}
|
||||
// Command creating.
|
||||
var (
|
||||
cmd = Command{}
|
||||
metaData = gmeta.Data(inputObject.Interface())
|
||||
)
|
||||
if err = gconv.Scan(metaData, &cmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Name filed is necessary.
|
||||
if cmd.Name == "" {
|
||||
return nil, gerror.Newf(
|
||||
`command name cannot be empty, "name" tag not found in struct "%s"`,
|
||||
inputObject.Type().String(),
|
||||
)
|
||||
}
|
||||
if cmd.Description == "" {
|
||||
cmd.Description = metaData[tagNameDc]
|
||||
}
|
||||
if cmd.Additional == "" {
|
||||
cmd.Additional = metaData[tagNameAd]
|
||||
}
|
||||
|
||||
if cmd.Options, err = newOptionsFromInput(inputObject.Interface()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cmd, nil
|
||||
}
|
||||
|
||||
func newOptionsFromInput(object interface{}) (options []Option, err error) {
|
||||
var (
|
||||
fields []structs.Field
|
||||
)
|
||||
fields, err = structs.Fields(structs.FieldsInput{
|
||||
Pointer: object,
|
||||
RecursiveOption: structs.RecursiveOptionEmbeddedNoTag,
|
||||
})
|
||||
for _, field := range fields {
|
||||
var (
|
||||
option = Option{}
|
||||
metaData = gmeta.Data(field.Value.Interface())
|
||||
)
|
||||
if err = gconv.Scan(metaData, &option); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if option.Name == "" {
|
||||
option.Name = field.Name()
|
||||
}
|
||||
options = append(options, option)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -28,13 +28,13 @@ type TestCmdObjectOutput struct{}
|
||||
|
||||
type TestCmdObjectEnvInput struct {
|
||||
g.Meta `name:"env" usage:"gf env/test" brief:"gf env command" dc:"description" ad:"ad"`
|
||||
Name string `v:"required" name:"name" short:"n" orphan:"false" brief:"name for command"`
|
||||
Name string `v:"required" short:"n" orphan:"false" brief:"name for command"`
|
||||
}
|
||||
type TestCmdObjectEnvOutput struct{}
|
||||
|
||||
type TestCmdObjectTestInput struct {
|
||||
g.Meta `name:"test" usage:"gf env/test" brief:"gf test command" dc:"description" ad:"ad"`
|
||||
Name string `v:"required" name:"name" short:"n" orphan:"false" brief:"name for command"`
|
||||
Name string `v:"required" short:"n" orphan:"false" brief:"name for command"`
|
||||
}
|
||||
type TestCmdObjectTestOutput struct{}
|
||||
|
||||
|
||||
@ -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 structs.Field, path, method string) (*ParameterRef, error) {
|
||||
var (
|
||||
tagMap = field.TagMap()
|
||||
parameter = &Parameter{
|
||||
|
||||
Reference in New Issue
Block a user