object feature for package gcmd

This commit is contained in:
John Guo
2021-11-23 14:08:37 +08:00
parent dc1ad3dda4
commit 9e21052a3c
5 changed files with 108 additions and 60 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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
}

View File

@ -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{}

View File

@ -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{