mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
@ -55,6 +55,7 @@ func (c cGF) Index(ctx context.Context, in cGFInput) (out *cGFOutput, err error)
|
||||
_, err = Version.Index(ctx, cVersionInput{})
|
||||
return
|
||||
}
|
||||
|
||||
answer := "n"
|
||||
// No argument or option, do installation checks.
|
||||
if data, isInstalled := service.Install.IsInstalled(); !isInstalled {
|
||||
@ -71,6 +72,7 @@ func (c cGF) Index(ctx context.Context, in cGFInput) (out *cGFOutput, err error)
|
||||
gcmd.Scan("press `Enter` to exit...")
|
||||
return
|
||||
}
|
||||
|
||||
// Print help content.
|
||||
gcmd.CommandFromCtx(ctx).Print()
|
||||
return
|
||||
|
||||
@ -28,6 +28,8 @@ const (
|
||||
helpOptionNameShort = "h"
|
||||
maxLineChars = 120
|
||||
tracingInstrumentName = "github.com/gogf/gf/v2/os/gcmd.Command"
|
||||
tagNameName = "name"
|
||||
tagNameShort = "short"
|
||||
)
|
||||
|
||||
// Init does custom initialization.
|
||||
|
||||
@ -42,12 +42,11 @@ type FuncWithValue func(ctx context.Context, parser *Parser) (out interface{}, e
|
||||
|
||||
// Argument is the command value that are used by certain command.
|
||||
type Argument struct {
|
||||
Name string // Option name.
|
||||
FieldName string // Option field name.
|
||||
Short string // Option short.
|
||||
Brief string // Brief info about this Option, which is used in help info.
|
||||
IsArg bool // IsArg marks this argument taking value from command line argument instead of option.
|
||||
Orphan bool // Whether this Option having or having no value bound to it.
|
||||
Name string // Option name.
|
||||
Short string // Option short.
|
||||
Brief string // Brief info about this Option, which is used in help info.
|
||||
IsArg bool // IsArg marks this argument taking value from command line argument instead of option.
|
||||
Orphan bool // Whether this Option having or having no value bound to it.
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@ -353,9 +353,6 @@ func newArgumentsFromInput(object interface{}) (args []Argument, err error) {
|
||||
}
|
||||
if arg.Name == "" {
|
||||
arg.Name = field.Name()
|
||||
} else if arg.Name != field.Name() {
|
||||
arg.FieldName = field.Name()
|
||||
nameSet.Add(arg.FieldName)
|
||||
}
|
||||
if arg.Name == helpOptionName {
|
||||
return nil, gerror.Newf(
|
||||
@ -411,14 +408,25 @@ func mergeDefaultStructValue(data map[string]interface{}, pointer interface{}) e
|
||||
foundValue interface{}
|
||||
)
|
||||
for _, field := range tagFields {
|
||||
var (
|
||||
nameValue = field.Tag(tagNameName)
|
||||
shortValue = field.Tag(tagNameShort)
|
||||
)
|
||||
// If it already has value, it then ignores the default value.
|
||||
if value, ok := data[nameValue]; ok {
|
||||
data[field.Name()] = value
|
||||
continue
|
||||
}
|
||||
if value, ok := data[shortValue]; ok {
|
||||
data[field.Name()] = value
|
||||
continue
|
||||
}
|
||||
foundKey, foundValue = gutil.MapPossibleItemByKey(data, field.Name())
|
||||
if foundKey == "" {
|
||||
data[field.Name()] = field.TagValue
|
||||
} else {
|
||||
if utils.IsEmpty(foundValue) {
|
||||
data[foundKey] = field.TagValue
|
||||
} else {
|
||||
data[field.Name()] = foundValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,12 +171,10 @@ func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error)
|
||||
if arg.IsArg {
|
||||
continue
|
||||
}
|
||||
optionKey = arg.Name
|
||||
if arg.FieldName != "" {
|
||||
optionKey += fmt.Sprintf(`,%s`, arg.FieldName)
|
||||
}
|
||||
if arg.Short != "" {
|
||||
optionKey += fmt.Sprintf(`,%s`, arg.Short)
|
||||
optionKey = fmt.Sprintf(`%s,%s`, arg.Name, arg.Short)
|
||||
} else {
|
||||
optionKey = arg.Name
|
||||
}
|
||||
supportedOptions[optionKey] = !arg.Orphan
|
||||
}
|
||||
|
||||
@ -30,12 +30,14 @@ type TestCmdObjectEnvInput struct {
|
||||
type TestCmdObjectEnvOutput struct{}
|
||||
|
||||
type TestCmdObjectTestInput struct {
|
||||
g.Meta `name:"test" usage:"root test" brief:"root test command" dc:"root test command description" ad:"root test command ad"`
|
||||
Name string `name:"yourname" v:"required" short:"n" orphan:"false" brief:"name for test command" d:"tom"`
|
||||
g.Meta `name:"test" usage:"root test" brief:"root test command" dc:"root test command description" ad:"root test command ad"`
|
||||
Name string `name:"yourname" v:"required" short:"n" orphan:"false" brief:"name for test command" d:"tom"`
|
||||
Version bool `name:"version" short:"v" orphan:"true" brief:"show version"`
|
||||
}
|
||||
|
||||
type TestCmdObjectTestOutput struct {
|
||||
Content string
|
||||
Name string
|
||||
Version bool
|
||||
}
|
||||
|
||||
func (TestCmdObject) Env(ctx context.Context, in TestCmdObjectEnvInput) (out *TestCmdObjectEnvOutput, err error) {
|
||||
@ -44,7 +46,8 @@ func (TestCmdObject) Env(ctx context.Context, in TestCmdObjectEnvInput) (out *Te
|
||||
|
||||
func (TestCmdObject) Test(ctx context.Context, in TestCmdObjectTestInput) (out *TestCmdObjectTestOutput, err error) {
|
||||
out = &TestCmdObjectTestOutput{
|
||||
Content: in.Name,
|
||||
Name: in.Name,
|
||||
Version: in.Version,
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -93,19 +96,25 @@ func Test_Command_NewFromObject_RunWithValue(t *testing.T) {
|
||||
os.Args = []string{"root", "test", "-n=john"}
|
||||
value, err := cmd.RunWithValueError(ctx)
|
||||
t.AssertNil(err)
|
||||
t.Assert(value, `{"Content":"john"}`)
|
||||
t.Assert(value, `{"Name":"john","Version":false}`)
|
||||
|
||||
// test name tag name
|
||||
os.Args = []string{"root", "test", "-yourname=hailaz"}
|
||||
value1, err1 := cmd.RunWithValueError(ctx)
|
||||
t.AssertNil(err1)
|
||||
t.Assert(value1, `{"Content":"hailaz"}`)
|
||||
t.Assert(value1, `{"Name":"hailaz","Version":false}`)
|
||||
|
||||
// test default tag value
|
||||
os.Args = []string{"root", "test"}
|
||||
value2, err2 := cmd.RunWithValueError(ctx)
|
||||
t.AssertNil(err2)
|
||||
t.Assert(value2, `{"Content":"tom"}`)
|
||||
t.Assert(value2, `{"Name":"tom","Version":false}`)
|
||||
|
||||
// test name tag and orphan tag true
|
||||
os.Args = []string{"root", "test", "-v"}
|
||||
value3, err3 := cmd.RunWithValueError(ctx)
|
||||
t.AssertNil(err3)
|
||||
t.Assert(value3, `{"Name":"tom","Version":true}`)
|
||||
})
|
||||
}
|
||||
|
||||
@ -123,7 +132,7 @@ func Test_Command_AddObject(t *testing.T) {
|
||||
os.Args = []string{"start", "root", "test", "-n=john"}
|
||||
value, err := command.RunWithValueError(ctx)
|
||||
t.AssertNil(err)
|
||||
t.Assert(value, `{"Content":"john"}`)
|
||||
t.Assert(value, `{"Name":"john","Version":false}`)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ func MapToMaps(params interface{}, pointer interface{}, mapping ...map[string]st
|
||||
//
|
||||
// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
|
||||
// sense only if the item of `params` is type struct.
|
||||
func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
func doMapToMaps(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) {
|
||||
// If given `params` is JSON, it then uses json.Unmarshal doing the converting.
|
||||
switch r := params.(type) {
|
||||
case []byte:
|
||||
@ -124,13 +124,13 @@ func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string]
|
||||
var item reflect.Value
|
||||
if pointerElemType.Kind() == reflect.Ptr {
|
||||
item = reflect.New(pointerElemType.Elem())
|
||||
if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil {
|
||||
if err = MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil {
|
||||
return err
|
||||
}
|
||||
pointerSlice.Index(i).Set(item)
|
||||
} else {
|
||||
item = reflect.New(pointerElemType)
|
||||
if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil {
|
||||
if err = MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil {
|
||||
return err
|
||||
}
|
||||
pointerSlice.Index(i).Set(item.Elem())
|
||||
|
||||
@ -23,7 +23,7 @@ import (
|
||||
// It calls function `doMapToMaps` internally if `pointer` is type of *[]map/*[]*map for converting.
|
||||
// It calls function `doStruct` internally if `pointer` is type of *struct/**struct for converting.
|
||||
// It calls function `doStructs` internally if `pointer` is type of *[]struct/*[]*struct for converting.
|
||||
func Scan(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
func Scan(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) {
|
||||
var (
|
||||
pointerType reflect.Type
|
||||
pointerKind reflect.Kind
|
||||
@ -82,12 +82,12 @@ func Scan(params interface{}, pointer interface{}, mapping ...map[string]string)
|
||||
pointerElemKind = pointerElem.Kind()
|
||||
keyToAttributeNameMapping map[string]string
|
||||
)
|
||||
if len(mapping) > 0 {
|
||||
keyToAttributeNameMapping = mapping[0]
|
||||
if len(paramKeyToAttrMap) > 0 {
|
||||
keyToAttributeNameMapping = paramKeyToAttrMap[0]
|
||||
}
|
||||
switch pointerElemKind {
|
||||
case reflect.Map:
|
||||
return doMapToMap(params, pointer, mapping...)
|
||||
return doMapToMap(params, pointer, paramKeyToAttrMap...)
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
var (
|
||||
@ -99,7 +99,7 @@ func Scan(params interface{}, pointer interface{}, mapping ...map[string]string)
|
||||
sliceElemKind = sliceElem.Kind()
|
||||
}
|
||||
if sliceElemKind == reflect.Map {
|
||||
return doMapToMaps(params, pointer, mapping...)
|
||||
return doMapToMaps(params, pointer, paramKeyToAttrMap...)
|
||||
}
|
||||
return doStructs(params, pointer, keyToAttributeNameMapping, "")
|
||||
|
||||
|
||||
@ -31,8 +31,8 @@ import (
|
||||
// It will automatically convert the first letter of the key to uppercase
|
||||
// in mapping procedure to do the matching.
|
||||
// It ignores the map key, if it does not match.
|
||||
func Struct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return Scan(params, pointer, mapping...)
|
||||
func Struct(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) {
|
||||
return Scan(params, pointer, paramKeyToAttrMap...)
|
||||
}
|
||||
|
||||
// StructTag acts as Struct but also with support for priority tag feature, which retrieves the
|
||||
@ -85,7 +85,7 @@ func doStructWithJsonCheck(params interface{}, pointer interface{}) (err error,
|
||||
}
|
||||
|
||||
// doStruct is the core internal converting function for any data to struct.
|
||||
func doStruct(params interface{}, pointer interface{}, mapping map[string]string, priorityTag string) (err error) {
|
||||
func doStruct(params interface{}, pointer interface{}, paramKeyToAttrMap map[string]string, priorityTag string) (err error) {
|
||||
if params == nil {
|
||||
// If `params` is nil, no conversion.
|
||||
return nil
|
||||
@ -252,7 +252,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
continue
|
||||
}
|
||||
}
|
||||
if err = doStruct(paramsMap, elemFieldValue, mapping, priorityTag); err != nil {
|
||||
if err = doStruct(paramsMap, elemFieldValue, paramKeyToAttrMap, priorityTag); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
@ -264,7 +264,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
return nil
|
||||
}
|
||||
|
||||
// The key of the tagMap is the attribute name of the struct,
|
||||
// The key of the `attrToTagCheckNameMap` is the attribute name of the struct,
|
||||
// and the value is its replaced tag name for later comparison to improve performance.
|
||||
var (
|
||||
attrToTagCheckNameMap = make(map[string]string)
|
||||
@ -292,11 +292,27 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
paramsMap[attributeName] = paramsMap[tagName]
|
||||
}
|
||||
}
|
||||
|
||||
// To convert value base on custom parameter key to attribute name map.
|
||||
err = doStructBaseOnParamKeyToAttrMap(
|
||||
pointerElemReflectValue,
|
||||
paramsMap,
|
||||
paramKeyToAttrMap,
|
||||
doneMap,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Already done all attributes value assignment nothing to do next.
|
||||
if len(doneMap) == len(attrToCheckNameMap) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// To convert value base on precise attribute name.
|
||||
err = doStructBaseOnAttribute(
|
||||
pointerElemReflectValue,
|
||||
paramsMap,
|
||||
mapping,
|
||||
paramKeyToAttrMap,
|
||||
doneMap,
|
||||
attrToCheckNameMap,
|
||||
)
|
||||
@ -307,11 +323,12 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
if len(doneMap) == len(attrToCheckNameMap) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// To convert value base on parameter map.
|
||||
err = doStructBaseOnParamMap(
|
||||
pointerElemReflectValue,
|
||||
paramsMap,
|
||||
mapping,
|
||||
paramKeyToAttrMap,
|
||||
doneMap,
|
||||
attrToCheckNameMap,
|
||||
attrToTagCheckNameMap,
|
||||
@ -323,17 +340,47 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
return nil
|
||||
}
|
||||
|
||||
func doStructBaseOnParamKeyToAttrMap(
|
||||
pointerElemReflectValue reflect.Value,
|
||||
paramsMap map[string]interface{},
|
||||
paramKeyToAttrMap map[string]string,
|
||||
doneAttrMap map[string]struct{},
|
||||
) error {
|
||||
if len(paramKeyToAttrMap) == 0 {
|
||||
return nil
|
||||
}
|
||||
for paramKey, attrName := range paramKeyToAttrMap {
|
||||
paramValue, ok := paramsMap[paramKey]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// If the attribute name is already checked converting, then skip it.
|
||||
if _, ok = doneAttrMap[attrName]; ok {
|
||||
continue
|
||||
}
|
||||
// Mark it done.
|
||||
doneAttrMap[attrName] = struct{}{}
|
||||
if err := bindVarToStructAttr(
|
||||
pointerElemReflectValue, attrName, paramValue, paramKeyToAttrMap,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func doStructBaseOnAttribute(
|
||||
pointerElemReflectValue reflect.Value,
|
||||
paramsMap map[string]interface{},
|
||||
mapping map[string]string,
|
||||
doneMap map[string]struct{},
|
||||
paramKeyToAttrMap map[string]string,
|
||||
doneAttrMap map[string]struct{},
|
||||
attrToCheckNameMap map[string]string,
|
||||
) error {
|
||||
var customMappingAttrMap = make(map[string]struct{})
|
||||
if len(mapping) > 0 {
|
||||
if len(paramKeyToAttrMap) > 0 {
|
||||
// It ignores the attribute names if it is specified in the `paramKeyToAttrMap`.
|
||||
for paramName := range paramsMap {
|
||||
if passedAttrKey, ok := mapping[paramName]; ok {
|
||||
if passedAttrKey, ok := paramKeyToAttrMap[paramName]; ok {
|
||||
customMappingAttrMap[passedAttrKey] = struct{}{}
|
||||
}
|
||||
}
|
||||
@ -344,17 +391,19 @@ func doStructBaseOnAttribute(
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// If the attribute name is in custom mapping, it then ignores this converting.
|
||||
// If the attribute name is in custom paramKeyToAttrMap, it then ignores this converting.
|
||||
if _, ok = customMappingAttrMap[attrName]; ok {
|
||||
continue
|
||||
}
|
||||
// If the attribute name is already checked converting, then skip it.
|
||||
if _, ok = doneMap[attrName]; ok {
|
||||
if _, ok = doneAttrMap[attrName]; ok {
|
||||
continue
|
||||
}
|
||||
// Mark it done.
|
||||
doneMap[attrName] = struct{}{}
|
||||
if err := bindVarToStructAttr(pointerElemReflectValue, attrName, paramValue, mapping); err != nil {
|
||||
doneAttrMap[attrName] = struct{}{}
|
||||
if err := bindVarToStructAttr(
|
||||
pointerElemReflectValue, attrName, paramValue, paramKeyToAttrMap,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -364,8 +413,8 @@ func doStructBaseOnAttribute(
|
||||
func doStructBaseOnParamMap(
|
||||
pointerElemReflectValue reflect.Value,
|
||||
paramsMap map[string]interface{},
|
||||
mapping map[string]string,
|
||||
doneMap map[string]struct{},
|
||||
paramKeyToAttrMap map[string]string,
|
||||
doneAttrMap map[string]struct{},
|
||||
attrToCheckNameMap map[string]string,
|
||||
attrToTagCheckNameMap map[string]string,
|
||||
tagToAttrNameMap map[string]string,
|
||||
@ -375,45 +424,35 @@ func doStructBaseOnParamMap(
|
||||
checkName string
|
||||
)
|
||||
for paramName, paramValue := range paramsMap {
|
||||
attrName = ""
|
||||
// It firstly checks the passed mapping rules.
|
||||
if len(mapping) > 0 {
|
||||
if passedAttrKey, ok := mapping[paramName]; ok {
|
||||
attrName = passedAttrKey
|
||||
}
|
||||
}
|
||||
// It secondly checks the predefined tags and matching rules.
|
||||
// It firstly considers `paramName` as accurate tag name,
|
||||
// and retrieve attribute name from `tagToAttrNameMap` .
|
||||
attrName = tagToAttrNameMap[paramName]
|
||||
if attrName == "" {
|
||||
// It firstly considers `paramName` as accurate tag name,
|
||||
// and retrieve attribute name from `tagToAttrNameMap` .
|
||||
attrName = tagToAttrNameMap[paramName]
|
||||
if attrName == "" {
|
||||
checkName = utils.RemoveSymbols(paramName)
|
||||
// Loop to find the matched attribute name with or without
|
||||
// string cases and chars like '-'/'_'/'.'/' '.
|
||||
checkName = utils.RemoveSymbols(paramName)
|
||||
// Loop to find the matched attribute name with or without
|
||||
// string cases and chars like '-'/'_'/'.'/' '.
|
||||
|
||||
// Matching the parameters to struct tag names.
|
||||
// The `attrKey` is the attribute name of the struct.
|
||||
for attrKey, cmpKey := range attrToTagCheckNameMap {
|
||||
if strings.EqualFold(checkName, cmpKey) {
|
||||
attrName = attrKey
|
||||
break
|
||||
}
|
||||
// Matching the parameters to struct tag names.
|
||||
// The `attrKey` is the attribute name of the struct.
|
||||
for attrKey, cmpKey := range attrToTagCheckNameMap {
|
||||
if strings.EqualFold(checkName, cmpKey) {
|
||||
attrName = attrKey
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Matching the parameters to struct attributes.
|
||||
if attrName == "" {
|
||||
for attrKey, cmpKey := range attrToCheckNameMap {
|
||||
// Eg:
|
||||
// UserName eq user_name
|
||||
// User-Name eq username
|
||||
// username eq userName
|
||||
// etc.
|
||||
if strings.EqualFold(checkName, cmpKey) {
|
||||
attrName = attrKey
|
||||
break
|
||||
}
|
||||
// Matching the parameters to struct attributes.
|
||||
if attrName == "" {
|
||||
for attrKey, cmpKey := range attrToCheckNameMap {
|
||||
// Eg:
|
||||
// UserName eq user_name
|
||||
// User-Name eq username
|
||||
// username eq userName
|
||||
// etc.
|
||||
if strings.EqualFold(checkName, cmpKey) {
|
||||
attrName = attrKey
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -423,12 +462,14 @@ func doStructBaseOnParamMap(
|
||||
continue
|
||||
}
|
||||
// If the attribute name is already checked converting, then skip it.
|
||||
if _, ok := doneMap[attrName]; ok {
|
||||
if _, ok := doneAttrMap[attrName]; ok {
|
||||
continue
|
||||
}
|
||||
// Mark it done.
|
||||
doneMap[attrName] = struct{}{}
|
||||
if err := bindVarToStructAttr(pointerElemReflectValue, attrName, paramValue, mapping); err != nil {
|
||||
doneAttrMap[attrName] = struct{}{}
|
||||
if err := bindVarToStructAttr(
|
||||
pointerElemReflectValue, attrName, paramValue, paramKeyToAttrMap,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -438,7 +479,7 @@ func doStructBaseOnParamMap(
|
||||
// bindVarToStructAttr sets value to struct object attribute by name.
|
||||
func bindVarToStructAttr(
|
||||
structReflectValue reflect.Value,
|
||||
attrName string, value interface{}, mapping map[string]string,
|
||||
attrName string, value interface{}, paramKeyToAttrMap map[string]string,
|
||||
) (err error) {
|
||||
structFieldValue := structReflectValue.FieldByName(attrName)
|
||||
if !structFieldValue.IsValid() {
|
||||
@ -450,7 +491,7 @@ func bindVarToStructAttr(
|
||||
}
|
||||
defer func() {
|
||||
if exception := recover(); exception != nil {
|
||||
if err = bindVarToReflectValue(structFieldValue, value, mapping); err != nil {
|
||||
if err = bindVarToReflectValue(structFieldValue, value, paramKeyToAttrMap); err != nil {
|
||||
err = gerror.Wrapf(err, `error binding value to attribute "%s"`, attrName)
|
||||
}
|
||||
}
|
||||
@ -575,7 +616,9 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value i
|
||||
}
|
||||
|
||||
// bindVarToReflectValue sets `value` to reflect value object `structFieldValue`.
|
||||
func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, mapping map[string]string) (err error) {
|
||||
func bindVarToReflectValue(
|
||||
structFieldValue reflect.Value, value interface{}, paramKeyToAttrMap map[string]string,
|
||||
) (err error) {
|
||||
// JSON content converting.
|
||||
err, ok := doStructWithJsonCheck(value, structFieldValue)
|
||||
if err != nil {
|
||||
@ -600,7 +643,7 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
|
||||
// Converting using reflection by kind.
|
||||
switch kind {
|
||||
case reflect.Map:
|
||||
return doMapToMap(value, structFieldValue, mapping)
|
||||
return doMapToMap(value, structFieldValue, paramKeyToAttrMap)
|
||||
|
||||
case reflect.Struct:
|
||||
// Recursively converting for struct attribute.
|
||||
@ -716,12 +759,12 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
|
||||
return err
|
||||
}
|
||||
elem := item.Elem()
|
||||
if err = bindVarToReflectValue(elem, value, mapping); err == nil {
|
||||
if err = bindVarToReflectValue(elem, value, paramKeyToAttrMap); err == nil {
|
||||
structFieldValue.Set(elem.Addr())
|
||||
}
|
||||
} else {
|
||||
// Not empty pointer, it assigns values to it.
|
||||
return bindVarToReflectValue(structFieldValue.Elem(), value, mapping)
|
||||
return bindVarToReflectValue(structFieldValue.Elem(), value, paramKeyToAttrMap)
|
||||
}
|
||||
|
||||
// It mainly and specially handles the interface of nil value.
|
||||
|
||||
@ -16,8 +16,8 @@ import (
|
||||
|
||||
// Structs converts any slice to given struct slice.
|
||||
// Also see Scan, Struct.
|
||||
func Structs(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return Scan(params, pointer, mapping...)
|
||||
func Structs(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) {
|
||||
return Scan(params, pointer, paramKeyToAttrMap...)
|
||||
}
|
||||
|
||||
// StructsTag acts as Structs but also with support for priority tag feature, which retrieves the
|
||||
@ -34,7 +34,9 @@ func StructsTag(params interface{}, pointer interface{}, priorityTag string) (er
|
||||
// The parameter `pointer` should be type of pointer to slice of struct.
|
||||
// Note that if `pointer` is a pointer to another pointer of type of slice of struct,
|
||||
// it will create the struct/pointer internally.
|
||||
func doStructs(params interface{}, pointer interface{}, mapping map[string]string, priorityTag string) (err error) {
|
||||
func doStructs(
|
||||
params interface{}, pointer interface{}, paramKeyToAttrMap map[string]string, priorityTag string,
|
||||
) (err error) {
|
||||
if params == nil {
|
||||
// If `params` is nil, no conversion.
|
||||
return nil
|
||||
@ -133,7 +135,7 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin
|
||||
if !tempReflectValue.IsValid() {
|
||||
tempReflectValue = reflect.New(itemType.Elem()).Elem()
|
||||
}
|
||||
if err = doStruct(paramsList[i], tempReflectValue, mapping, priorityTag); err != nil {
|
||||
if err = doStruct(paramsList[i], tempReflectValue, paramKeyToAttrMap, priorityTag); err != nil {
|
||||
return err
|
||||
}
|
||||
reflectElemArray.Index(i).Set(tempReflectValue.Addr())
|
||||
@ -147,7 +149,7 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin
|
||||
} else {
|
||||
tempReflectValue = reflect.New(itemType).Elem()
|
||||
}
|
||||
if err = doStruct(paramsList[i], tempReflectValue, mapping, priorityTag); err != nil {
|
||||
if err = doStruct(paramsList[i], tempReflectValue, paramKeyToAttrMap, priorityTag); err != nil {
|
||||
return err
|
||||
}
|
||||
reflectElemArray.Index(i).Set(tempReflectValue)
|
||||
|
||||
@ -17,6 +17,33 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func Test_Scan_WithMapParameter(t *testing.T) {
|
||||
type User struct {
|
||||
Uid int
|
||||
Name string
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
var (
|
||||
user = new(User)
|
||||
params = g.Map{
|
||||
"uid": 1,
|
||||
"myname": "john",
|
||||
"name": "smith",
|
||||
}
|
||||
)
|
||||
err := gconv.Scan(params, user, g.MapStrStr{
|
||||
"myname": "Name",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(user, &User{
|
||||
Uid: 1,
|
||||
Name: "john",
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Scan_StructStructs(t *testing.T) {
|
||||
type User struct {
|
||||
Uid int
|
||||
|
||||
Reference in New Issue
Block a user