2021-01-17 21:46:25 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
2018-11-30 09:48:57 +08:00
|
|
|
//
|
|
|
|
// 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,
|
2019-02-02 16:18:25 +08:00
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-11-30 09:48:57 +08:00
|
|
|
|
|
|
|
package gconv
|
|
|
|
|
|
|
|
import (
|
2019-05-28 21:41:00 +08:00
|
|
|
"reflect"
|
|
|
|
"strings"
|
2018-11-30 09:48:57 +08:00
|
|
|
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/internal/empty"
|
2021-11-13 23:30:31 +08:00
|
|
|
"github.com/gogf/gf/v2/internal/json"
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/internal/utils"
|
2019-05-16 13:56:49 +08:00
|
|
|
)
|
2019-05-28 21:41:00 +08:00
|
|
|
|
2023-01-03 11:00:23 +08:00
|
|
|
type recursiveType string
|
|
|
|
|
|
|
|
const (
|
|
|
|
recursiveTypeAuto recursiveType = "auto"
|
|
|
|
recursiveTypeTrue recursiveType = "true"
|
|
|
|
)
|
|
|
|
|
2021-03-23 17:53:20 +08:00
|
|
|
// Map converts any variable `value` to map[string]interface{}. If the parameter `value` is not a
|
2019-12-10 21:14:15 +08:00
|
|
|
// map/struct/*struct type, then the conversion will fail and returns nil.
|
2019-07-04 11:11:41 +08:00
|
|
|
//
|
2021-03-23 17:53:20 +08:00
|
|
|
// If `value` is a struct/*struct object, the second parameter `tags` specifies the most priority
|
2020-02-08 14:07:32 +08:00
|
|
|
// tags that will be detected, otherwise it detects the tags in order of:
|
|
|
|
// gconv, json, field name.
|
2019-06-19 09:06:52 +08:00
|
|
|
func Map(value interface{}, tags ...string) map[string]interface{} {
|
2023-01-03 11:00:23 +08:00
|
|
|
return doMapConvert(value, recursiveTypeAuto, tags...)
|
2020-01-02 19:45:41 +08:00
|
|
|
}
|
|
|
|
|
2021-03-23 17:53:20 +08:00
|
|
|
// MapDeep does Map function recursively, which means if the attribute of `value`
|
2020-01-02 19:45:41 +08:00
|
|
|
// is also a struct/*struct, calls Map function on this attribute converting it to
|
|
|
|
// a map[string]interface{} type variable.
|
|
|
|
// Also see Map.
|
|
|
|
func MapDeep(value interface{}, tags ...string) map[string]interface{} {
|
2023-01-03 11:00:23 +08:00
|
|
|
return doMapConvert(value, recursiveTypeTrue, tags...)
|
2020-01-02 19:45:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// doMapConvert implements the map converting.
|
2021-03-23 17:53:20 +08:00
|
|
|
// It automatically checks and converts json string to map if `value` is string/[]byte.
|
2020-06-15 18:59:18 +08:00
|
|
|
//
|
2020-09-07 19:44:11 +08:00
|
|
|
// TODO completely implement the recursive converting for all types, especially the map.
|
2023-01-03 11:00:23 +08:00
|
|
|
func doMapConvert(value interface{}, recursive recursiveType, tags ...string) map[string]interface{} {
|
2019-06-19 09:06:52 +08:00
|
|
|
if value == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2020-10-25 10:47:47 +08:00
|
|
|
newTags := StructTagPriority
|
|
|
|
switch len(tags) {
|
|
|
|
case 0:
|
2021-08-19 14:09:31 +08:00
|
|
|
// No need handling.
|
2020-10-25 10:47:47 +08:00
|
|
|
case 1:
|
|
|
|
newTags = append(strings.Split(tags[0], ","), StructTagPriority...)
|
|
|
|
default:
|
|
|
|
newTags = append(tags, StructTagPriority...)
|
|
|
|
}
|
2020-04-07 21:29:41 +08:00
|
|
|
// Assert the common combination of types, and finally it uses reflection.
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap := make(map[string]interface{})
|
2020-04-07 21:29:41 +08:00
|
|
|
switch r := value.(type) {
|
|
|
|
case string:
|
2020-07-08 10:52:45 +08:00
|
|
|
// If it is a JSON string, automatically unmarshal it!
|
2020-04-07 21:29:41 +08:00
|
|
|
if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
|
2021-05-15 22:38:07 +08:00
|
|
|
if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil {
|
2020-01-20 21:25:55 +08:00
|
|
|
return nil
|
2020-01-20 19:56:42 +08:00
|
|
|
}
|
2020-04-07 21:29:41 +08:00
|
|
|
} else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
case []byte:
|
2020-07-08 10:52:45 +08:00
|
|
|
// If it is a JSON string, automatically unmarshal it!
|
2020-04-07 21:29:41 +08:00
|
|
|
if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
|
2021-05-15 22:38:07 +08:00
|
|
|
if err := json.UnmarshalUseNumber(r, &dataMap); err != nil {
|
2020-01-20 21:25:55 +08:00
|
|
|
return nil
|
2020-01-20 19:56:42 +08:00
|
|
|
}
|
2020-04-07 21:29:41 +08:00
|
|
|
} else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
case map[interface{}]interface{}:
|
|
|
|
for k, v := range r {
|
2023-01-03 11:00:23 +08:00
|
|
|
dataMap[String(k)] = doMapConvertForMapOrStructValue(
|
|
|
|
doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
|
|
|
Value: v,
|
|
|
|
RecursiveType: recursive,
|
|
|
|
RecursiveOption: recursive == recursiveTypeTrue,
|
|
|
|
Tags: newTags,
|
|
|
|
},
|
|
|
|
)
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[interface{}]string:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[String(k)] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[interface{}]int:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[String(k)] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[interface{}]uint:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[String(k)] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[interface{}]float32:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[String(k)] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[interface{}]float64:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[String(k)] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[string]bool:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[k] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[string]int:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[k] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[string]uint:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[k] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[string]float32:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[k] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[string]float64:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[k] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
2021-12-17 17:22:55 +08:00
|
|
|
case map[string]string:
|
|
|
|
for k, v := range r {
|
|
|
|
dataMap[k] = v
|
|
|
|
}
|
2020-04-07 21:29:41 +08:00
|
|
|
case map[string]interface{}:
|
2023-01-03 11:00:23 +08:00
|
|
|
if recursive == recursiveTypeTrue {
|
2020-10-25 11:33:30 +08:00
|
|
|
// A copy of current map.
|
|
|
|
for k, v := range r {
|
2023-01-03 11:00:23 +08:00
|
|
|
dataMap[k] = doMapConvertForMapOrStructValue(
|
|
|
|
doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
|
|
|
Value: v,
|
|
|
|
RecursiveType: recursive,
|
|
|
|
RecursiveOption: recursive == recursiveTypeTrue,
|
|
|
|
Tags: newTags,
|
|
|
|
},
|
|
|
|
)
|
2020-10-25 11:33:30 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// It returns the map directly without any changing.
|
|
|
|
return r
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
2020-04-07 21:29:41 +08:00
|
|
|
case map[int]interface{}:
|
|
|
|
for k, v := range r {
|
2023-01-03 11:00:23 +08:00
|
|
|
dataMap[String(k)] = doMapConvertForMapOrStructValue(
|
|
|
|
doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
|
|
|
Value: v,
|
|
|
|
RecursiveType: recursive,
|
|
|
|
RecursiveOption: recursive == recursiveTypeTrue,
|
|
|
|
Tags: newTags,
|
|
|
|
},
|
|
|
|
)
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[int]string:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[String(k)] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
|
|
|
case map[uint]string:
|
|
|
|
for k, v := range r {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[String(k)] = v
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
2020-07-08 10:52:45 +08:00
|
|
|
|
2020-04-07 21:29:41 +08:00
|
|
|
default:
|
2020-07-08 10:52:45 +08:00
|
|
|
// Not a common type, it then uses reflection for conversion.
|
2020-11-29 21:34:28 +08:00
|
|
|
var reflectValue reflect.Value
|
2020-04-30 16:53:47 +08:00
|
|
|
if v, ok := value.(reflect.Value); ok {
|
2020-11-29 21:34:28 +08:00
|
|
|
reflectValue = v
|
2020-04-30 16:53:47 +08:00
|
|
|
} else {
|
2020-11-29 21:34:28 +08:00
|
|
|
reflectValue = reflect.ValueOf(value)
|
2020-04-30 16:53:47 +08:00
|
|
|
}
|
2020-11-29 21:34:28 +08:00
|
|
|
reflectKind := reflectValue.Kind()
|
2020-04-07 21:29:41 +08:00
|
|
|
// If it is a pointer, we should find its real data type.
|
2020-11-29 21:34:28 +08:00
|
|
|
for reflectKind == reflect.Ptr {
|
|
|
|
reflectValue = reflectValue.Elem()
|
|
|
|
reflectKind = reflectValue.Kind()
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
2020-11-29 21:34:28 +08:00
|
|
|
switch reflectKind {
|
2021-03-23 17:53:20 +08:00
|
|
|
// If `value` is type of array, it converts the value of even number index as its key and
|
2020-07-08 10:52:45 +08:00
|
|
|
// the value of odd number index as its corresponding value, for example:
|
2020-04-07 21:29:41 +08:00
|
|
|
// []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"}
|
2020-07-08 10:52:45 +08:00
|
|
|
// []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil}
|
2020-04-07 21:29:41 +08:00
|
|
|
case reflect.Slice, reflect.Array:
|
2020-11-29 21:34:28 +08:00
|
|
|
length := reflectValue.Len()
|
2020-04-07 21:29:41 +08:00
|
|
|
for i := 0; i < length; i += 2 {
|
|
|
|
if i+1 < length {
|
2020-11-29 21:34:28 +08:00
|
|
|
dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface()
|
2020-04-07 21:29:41 +08:00
|
|
|
} else {
|
2020-11-29 21:34:28 +08:00
|
|
|
dataMap[String(reflectValue.Index(i).Interface())] = nil
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2021-06-26 16:23:54 +08:00
|
|
|
case reflect.Map, reflect.Struct, reflect.Interface:
|
2023-01-03 11:00:23 +08:00
|
|
|
convertedValue := doMapConvertForMapOrStructValue(
|
|
|
|
doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: true,
|
|
|
|
Value: value,
|
|
|
|
RecursiveType: recursive,
|
|
|
|
RecursiveOption: recursive == recursiveTypeTrue,
|
|
|
|
Tags: newTags,
|
|
|
|
},
|
|
|
|
)
|
2020-10-25 10:47:47 +08:00
|
|
|
if m, ok := convertedValue.(map[string]interface{}); ok {
|
|
|
|
return m
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2020-10-25 10:47:47 +08:00
|
|
|
return nil
|
|
|
|
default:
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dataMap
|
|
|
|
}
|
|
|
|
|
2023-01-03 11:00:23 +08:00
|
|
|
type doMapConvertForMapOrStructValueInput struct {
|
|
|
|
IsRoot bool // It returns directly if it is not root and with no recursive converting.
|
|
|
|
Value interface{} // Current operation value.
|
|
|
|
RecursiveType recursiveType // The type from top function entry.
|
|
|
|
RecursiveOption bool // Whether convert recursively for `current` operation.
|
|
|
|
Tags []string // Map key mapping.
|
|
|
|
}
|
|
|
|
|
|
|
|
func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} {
|
2023-05-25 21:58:11 +08:00
|
|
|
if !in.IsRoot && !in.RecursiveOption {
|
2023-01-03 11:00:23 +08:00
|
|
|
return in.Value
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
2023-01-03 11:00:23 +08:00
|
|
|
|
2020-11-29 21:34:28 +08:00
|
|
|
var reflectValue reflect.Value
|
2023-01-03 11:00:23 +08:00
|
|
|
if v, ok := in.Value.(reflect.Value); ok {
|
2020-11-29 21:34:28 +08:00
|
|
|
reflectValue = v
|
2023-01-03 11:00:23 +08:00
|
|
|
in.Value = v.Interface()
|
2020-10-25 10:47:47 +08:00
|
|
|
} else {
|
2023-01-03 11:00:23 +08:00
|
|
|
reflectValue = reflect.ValueOf(in.Value)
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
2020-11-29 21:34:28 +08:00
|
|
|
reflectKind := reflectValue.Kind()
|
2020-10-25 10:47:47 +08:00
|
|
|
// If it is a pointer, we should find its real data type.
|
2020-11-29 21:34:28 +08:00
|
|
|
for reflectKind == reflect.Ptr {
|
|
|
|
reflectValue = reflectValue.Elem()
|
|
|
|
reflectKind = reflectValue.Kind()
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
2020-11-29 21:34:28 +08:00
|
|
|
switch reflectKind {
|
2020-10-25 10:47:47 +08:00
|
|
|
case reflect.Map:
|
|
|
|
var (
|
2020-11-29 21:34:28 +08:00
|
|
|
mapKeys = reflectValue.MapKeys()
|
2020-10-25 10:47:47 +08:00
|
|
|
dataMap = make(map[string]interface{})
|
|
|
|
)
|
|
|
|
for _, k := range mapKeys {
|
2023-07-13 21:15:07 +08:00
|
|
|
var (
|
|
|
|
mapKeyValue = reflectValue.MapIndex(k)
|
|
|
|
mapValue interface{}
|
|
|
|
)
|
2023-08-10 21:59:21 +08:00
|
|
|
switch {
|
|
|
|
case mapKeyValue.IsZero():
|
|
|
|
if mapKeyValue.IsNil() {
|
|
|
|
// quick check for nil value.
|
|
|
|
mapValue = nil
|
|
|
|
} else {
|
|
|
|
// in case of:
|
|
|
|
// exception recovered: reflect: call of reflect.Value.Interface on zero Value
|
|
|
|
mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface()
|
|
|
|
}
|
|
|
|
default:
|
2023-07-13 21:15:07 +08:00
|
|
|
mapValue = mapKeyValue.Interface()
|
|
|
|
}
|
2020-10-25 10:47:47 +08:00
|
|
|
dataMap[String(k.Interface())] = doMapConvertForMapOrStructValue(
|
2023-01-03 11:00:23 +08:00
|
|
|
doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
2023-07-13 21:15:07 +08:00
|
|
|
Value: mapValue,
|
2023-01-03 11:00:23 +08:00
|
|
|
RecursiveType: in.RecursiveType,
|
|
|
|
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
|
|
|
Tags: in.Tags,
|
|
|
|
},
|
2020-04-09 13:37:27 +08:00
|
|
|
)
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
|
|
|
return dataMap
|
2021-12-17 17:22:55 +08:00
|
|
|
|
2020-10-25 10:47:47 +08:00
|
|
|
case reflect.Struct:
|
2022-01-13 20:49:26 +08:00
|
|
|
var dataMap = make(map[string]interface{})
|
2020-10-25 10:47:47 +08:00
|
|
|
// Map converting interface check.
|
2023-01-03 11:00:23 +08:00
|
|
|
if v, ok := in.Value.(iMapStrAny); ok {
|
2022-01-13 20:49:26 +08:00
|
|
|
// Value copy, in case of concurrent safety.
|
|
|
|
for mapK, mapV := range v.MapStrAny() {
|
2023-01-03 11:00:23 +08:00
|
|
|
if in.RecursiveOption {
|
|
|
|
dataMap[mapK] = doMapConvertForMapOrStructValue(
|
|
|
|
doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
|
|
|
Value: mapV,
|
|
|
|
RecursiveType: in.RecursiveType,
|
|
|
|
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
|
|
|
Tags: in.Tags,
|
|
|
|
},
|
|
|
|
)
|
2022-01-13 20:49:26 +08:00
|
|
|
} else {
|
|
|
|
dataMap[mapK] = mapV
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2022-01-13 20:49:26 +08:00
|
|
|
return dataMap
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
|
|
|
// Using reflect for converting.
|
|
|
|
var (
|
2020-11-29 21:34:28 +08:00
|
|
|
rtField reflect.StructField
|
|
|
|
rvField reflect.Value
|
2022-01-13 20:49:26 +08:00
|
|
|
reflectType = reflectValue.Type() // attribute value type.
|
|
|
|
mapKey = "" // mapKey may be the tag name or the struct attribute name.
|
2020-10-25 10:47:47 +08:00
|
|
|
)
|
2020-11-29 21:34:28 +08:00
|
|
|
for i := 0; i < reflectValue.NumField(); i++ {
|
|
|
|
rtField = reflectType.Field(i)
|
|
|
|
rvField = reflectValue.Field(i)
|
2020-10-25 10:47:47 +08:00
|
|
|
// Only convert the public attributes.
|
|
|
|
fieldName := rtField.Name
|
|
|
|
if !utils.IsLetterUpper(fieldName[0]) {
|
|
|
|
continue
|
|
|
|
}
|
2021-02-09 18:00:43 +08:00
|
|
|
mapKey = ""
|
2020-10-25 10:47:47 +08:00
|
|
|
fieldTag := rtField.Tag
|
2023-01-03 11:00:23 +08:00
|
|
|
for _, tag := range in.Tags {
|
2021-02-09 18:00:43 +08:00
|
|
|
if mapKey = fieldTag.Get(tag); mapKey != "" {
|
2020-10-25 10:47:47 +08:00
|
|
|
break
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
2021-02-09 18:00:43 +08:00
|
|
|
if mapKey == "" {
|
|
|
|
mapKey = fieldName
|
2020-10-25 10:47:47 +08:00
|
|
|
} else {
|
|
|
|
// Support json tag feature: -, omitempty
|
2021-02-09 18:00:43 +08:00
|
|
|
mapKey = strings.TrimSpace(mapKey)
|
|
|
|
if mapKey == "-" {
|
2020-10-25 10:47:47 +08:00
|
|
|
continue
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2021-02-09 18:00:43 +08:00
|
|
|
array := strings.Split(mapKey, ",")
|
2020-10-25 10:47:47 +08:00
|
|
|
if len(array) > 1 {
|
|
|
|
switch strings.TrimSpace(array[1]) {
|
|
|
|
case "omitempty":
|
|
|
|
if empty.IsEmpty(rvField.Interface()) {
|
|
|
|
continue
|
|
|
|
} else {
|
2021-02-09 18:00:43 +08:00
|
|
|
mapKey = strings.TrimSpace(array[0])
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2020-10-25 10:47:47 +08:00
|
|
|
default:
|
2021-02-09 18:00:43 +08:00
|
|
|
mapKey = strings.TrimSpace(array[0])
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2020-04-07 21:29:41 +08:00
|
|
|
}
|
2023-03-07 21:26:32 +08:00
|
|
|
if mapKey == "" {
|
|
|
|
mapKey = fieldName
|
|
|
|
}
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
2023-01-03 11:00:23 +08:00
|
|
|
if in.RecursiveOption || rtField.Anonymous {
|
2020-10-25 10:47:47 +08:00
|
|
|
// Do map converting recursively.
|
|
|
|
var (
|
|
|
|
rvAttrField = rvField
|
|
|
|
rvAttrKind = rvField.Kind()
|
|
|
|
)
|
|
|
|
if rvAttrKind == reflect.Ptr {
|
|
|
|
rvAttrField = rvField.Elem()
|
|
|
|
rvAttrKind = rvAttrField.Kind()
|
|
|
|
}
|
|
|
|
switch rvAttrKind {
|
|
|
|
case reflect.Struct:
|
2021-10-12 17:52:31 +08:00
|
|
|
// Embedded struct and has no fields, just ignores it.
|
|
|
|
// Eg: gmeta.Meta
|
|
|
|
if rvAttrField.Type().NumField() == 0 {
|
|
|
|
continue
|
|
|
|
}
|
2020-08-11 20:13:47 +08:00
|
|
|
var (
|
2023-01-03 11:00:23 +08:00
|
|
|
hasNoTag = mapKey == fieldName
|
|
|
|
// DO NOT use rvAttrField.Interface() here,
|
|
|
|
// as it might be changed from pointer to struct.
|
|
|
|
rvInterface = rvField.Interface()
|
2020-08-11 20:13:47 +08:00
|
|
|
)
|
2023-01-03 11:00:23 +08:00
|
|
|
switch {
|
|
|
|
case hasNoTag && rtField.Anonymous:
|
2020-10-25 10:47:47 +08:00
|
|
|
// It means this attribute field has no tag.
|
|
|
|
// Overwrite the attribute with sub-struct attribute fields.
|
2023-01-03 11:00:23 +08:00
|
|
|
anonymousValue := doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
|
|
|
Value: rvInterface,
|
|
|
|
RecursiveType: in.RecursiveType,
|
|
|
|
RecursiveOption: true,
|
|
|
|
Tags: in.Tags,
|
|
|
|
})
|
2020-10-25 10:47:47 +08:00
|
|
|
if m, ok := anonymousValue.(map[string]interface{}); ok {
|
|
|
|
for k, v := range m {
|
2020-08-11 20:13:47 +08:00
|
|
|
dataMap[k] = v
|
2020-04-09 13:37:27 +08:00
|
|
|
}
|
|
|
|
} else {
|
2023-01-03 11:00:23 +08:00
|
|
|
dataMap[mapKey] = rvInterface
|
2020-01-02 19:45:41 +08:00
|
|
|
}
|
2023-01-03 11:00:23 +08:00
|
|
|
|
|
|
|
// It means this attribute field has desired tag.
|
|
|
|
case !hasNoTag && rtField.Anonymous:
|
|
|
|
dataMap[mapKey] = doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
|
|
|
Value: rvInterface,
|
|
|
|
RecursiveType: in.RecursiveType,
|
|
|
|
RecursiveOption: true,
|
|
|
|
Tags: in.Tags,
|
|
|
|
})
|
|
|
|
|
|
|
|
default:
|
|
|
|
dataMap[mapKey] = doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
|
|
|
Value: rvInterface,
|
|
|
|
RecursiveType: in.RecursiveType,
|
|
|
|
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
|
|
|
Tags: in.Tags,
|
|
|
|
})
|
2020-01-02 19:45:41 +08:00
|
|
|
}
|
2020-10-25 10:47:47 +08:00
|
|
|
|
|
|
|
// The struct attribute is type of slice.
|
|
|
|
case reflect.Array, reflect.Slice:
|
2021-10-02 14:52:28 +08:00
|
|
|
length := rvAttrField.Len()
|
2020-10-25 10:47:47 +08:00
|
|
|
if length == 0 {
|
2021-10-02 14:52:28 +08:00
|
|
|
dataMap[mapKey] = rvAttrField.Interface()
|
2020-10-25 10:47:47 +08:00
|
|
|
break
|
|
|
|
}
|
|
|
|
array := make([]interface{}, length)
|
2022-01-13 20:49:26 +08:00
|
|
|
for arrayIndex := 0; arrayIndex < length; arrayIndex++ {
|
|
|
|
array[arrayIndex] = doMapConvertForMapOrStructValue(
|
2023-01-03 11:00:23 +08:00
|
|
|
doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
2023-01-16 16:00:18 +08:00
|
|
|
Value: rvAttrField.Index(arrayIndex).Interface(),
|
2023-01-03 11:00:23 +08:00
|
|
|
RecursiveType: in.RecursiveType,
|
|
|
|
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
|
|
|
Tags: in.Tags,
|
|
|
|
},
|
2022-01-13 20:49:26 +08:00
|
|
|
)
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
2021-02-09 18:00:43 +08:00
|
|
|
dataMap[mapKey] = array
|
2022-01-05 02:01:54 +08:00
|
|
|
case reflect.Map:
|
|
|
|
var (
|
|
|
|
mapKeys = rvAttrField.MapKeys()
|
|
|
|
nestedMap = make(map[string]interface{})
|
|
|
|
)
|
|
|
|
for _, k := range mapKeys {
|
|
|
|
nestedMap[String(k.Interface())] = doMapConvertForMapOrStructValue(
|
2023-01-03 11:00:23 +08:00
|
|
|
doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
|
|
|
Value: rvAttrField.MapIndex(k).Interface(),
|
|
|
|
RecursiveType: in.RecursiveType,
|
|
|
|
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
|
|
|
Tags: in.Tags,
|
|
|
|
},
|
2022-01-05 02:01:54 +08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
dataMap[mapKey] = nestedMap
|
2020-10-25 10:47:47 +08:00
|
|
|
default:
|
2020-04-20 22:36:28 +08:00
|
|
|
if rvField.IsValid() {
|
2021-02-09 18:00:43 +08:00
|
|
|
dataMap[mapKey] = reflectValue.Field(i).Interface()
|
2020-04-20 22:36:28 +08:00
|
|
|
} else {
|
2021-02-09 18:00:43 +08:00
|
|
|
dataMap[mapKey] = nil
|
2020-04-20 22:36:28 +08:00
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2020-10-25 10:47:47 +08:00
|
|
|
} else {
|
|
|
|
// No recursive map value converting
|
|
|
|
if rvField.IsValid() {
|
2021-02-09 18:00:43 +08:00
|
|
|
dataMap[mapKey] = reflectValue.Field(i).Interface()
|
2020-10-25 10:47:47 +08:00
|
|
|
} else {
|
2021-02-09 18:00:43 +08:00
|
|
|
dataMap[mapKey] = nil
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
}
|
2020-10-25 10:47:47 +08:00
|
|
|
if len(dataMap) == 0 {
|
2023-01-03 11:00:23 +08:00
|
|
|
return in.Value
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
|
|
|
return dataMap
|
|
|
|
|
|
|
|
// The given value is type of slice.
|
|
|
|
case reflect.Array, reflect.Slice:
|
2020-11-29 21:34:28 +08:00
|
|
|
length := reflectValue.Len()
|
2020-10-25 10:47:47 +08:00
|
|
|
if length == 0 {
|
|
|
|
break
|
|
|
|
}
|
2020-11-29 21:34:28 +08:00
|
|
|
array := make([]interface{}, reflectValue.Len())
|
2020-10-25 10:47:47 +08:00
|
|
|
for i := 0; i < length; i++ {
|
2023-01-03 11:00:23 +08:00
|
|
|
array[i] = doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
|
|
|
|
IsRoot: false,
|
2023-01-16 16:00:18 +08:00
|
|
|
Value: reflectValue.Index(i).Interface(),
|
2023-01-03 11:00:23 +08:00
|
|
|
RecursiveType: in.RecursiveType,
|
|
|
|
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
|
|
|
Tags: in.Tags,
|
|
|
|
})
|
2020-10-25 10:47:47 +08:00
|
|
|
}
|
|
|
|
return array
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2023-01-03 11:00:23 +08:00
|
|
|
return in.Value
|
2018-11-30 09:48:57 +08:00
|
|
|
}
|
2019-05-28 21:41:00 +08:00
|
|
|
|
2021-03-23 17:53:20 +08:00
|
|
|
// MapStrStr converts `value` to map[string]string.
|
2019-12-14 17:01:27 +08:00
|
|
|
// Note that there might be data copy for this map type converting.
|
|
|
|
func MapStrStr(value interface{}, tags ...string) map[string]string {
|
|
|
|
if r, ok := value.(map[string]string); ok {
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
m := Map(value, tags...)
|
|
|
|
if len(m) > 0 {
|
2020-06-03 23:44:21 +08:00
|
|
|
vMap := make(map[string]string, len(m))
|
2019-12-14 17:01:27 +08:00
|
|
|
for k, v := range m {
|
|
|
|
vMap[k] = String(v)
|
|
|
|
}
|
|
|
|
return vMap
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-03-23 17:53:20 +08:00
|
|
|
// MapStrStrDeep converts `value` to map[string]string recursively.
|
2019-12-14 17:01:27 +08:00
|
|
|
// Note that there might be data copy for this map type converting.
|
|
|
|
func MapStrStrDeep(value interface{}, tags ...string) map[string]string {
|
|
|
|
if r, ok := value.(map[string]string); ok {
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
m := MapDeep(value, tags...)
|
|
|
|
if len(m) > 0 {
|
2020-06-03 23:44:21 +08:00
|
|
|
vMap := make(map[string]string, len(m))
|
2019-12-14 17:01:27 +08:00
|
|
|
for k, v := range m {
|
|
|
|
vMap[k] = String(v)
|
|
|
|
}
|
|
|
|
return vMap
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|