mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
improve MapDeep function for package gconv; improve gjson.New function for loading struct parameter
This commit is contained in:
@ -3,21 +3,29 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gopkg.in/yaml.v3"
|
||||
"github.com/gogf/gf/encoding/gjson"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte(`
|
||||
m:
|
||||
k: v
|
||||
`)
|
||||
var result map[string]interface{}
|
||||
if err := yaml.Unmarshal(data, &result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
type A struct {
|
||||
D string
|
||||
E string
|
||||
}
|
||||
type B struct {
|
||||
A `json:"a"`
|
||||
F string
|
||||
}
|
||||
|
||||
func SystemJsonEncode(a interface{}) string {
|
||||
js, err := json.Marshal(a)
|
||||
if err != nil {
|
||||
return "{}"
|
||||
} else {
|
||||
return fmt.Sprintf("%s", js)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var b B
|
||||
fmt.Println(SystemJsonEncode(b))
|
||||
fmt.Println(gjson.New(b).MustToJsonString())
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ func NewWithTag(data interface{}, tags string, safe ...bool) *Json {
|
||||
i := interface{}(nil)
|
||||
// Note that it uses Map function implementing the converting.
|
||||
// Note that it here should not use MapDeep function if you really know what it means.
|
||||
i = gconv.Map(data, tags)
|
||||
i = gconv.MapDeep(data, tags)
|
||||
j = &Json{
|
||||
p: &i,
|
||||
c: byte(gDEFAULT_SPLIT_CHAR),
|
||||
|
||||
@ -14,6 +14,8 @@ import (
|
||||
|
||||
// MapField retrieves struct field as map[name/tag]*Field from <pointer>, and returns the map.
|
||||
//
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
//
|
||||
// The parameter <priority> specifies the priority tag array for retrieving from high to low.
|
||||
//
|
||||
// The parameter <recursive> specifies whether retrieving the struct field recursively.
|
||||
|
||||
@ -14,6 +14,8 @@ import (
|
||||
|
||||
// TagFields retrieves struct tags as []*Field from <pointer>, and returns it.
|
||||
//
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
//
|
||||
// The parameter <recursive> specifies whether retrieving the struct field recursively.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter up-case from struct.
|
||||
@ -23,6 +25,7 @@ func TagFields(pointer interface{}, priority []string, recursive bool) []*Field
|
||||
|
||||
// doTagFields retrieves the tag and corresponding attribute name from <pointer>. It also filters repeated
|
||||
// tag internally.
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
func doTagFields(pointer interface{}, priority []string, recursive bool, tagMap map[string]struct{}) []*Field {
|
||||
var fields []*structs.Field
|
||||
if v, ok := pointer.(reflect.Value); ok {
|
||||
@ -85,6 +88,8 @@ func doTagFields(pointer interface{}, priority []string, recursive bool, tagMap
|
||||
|
||||
// TagMapName retrieves struct tags as map[tag]attribute from <pointer>, and returns it.
|
||||
//
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
//
|
||||
// The parameter <recursive> specifies whether retrieving the struct field recursively.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter up-case from struct.
|
||||
@ -99,6 +104,8 @@ func TagMapName(pointer interface{}, priority []string, recursive bool) map[stri
|
||||
|
||||
// TagMapField retrieves struct tags as map[tag]*Field from <pointer>, and returns it.
|
||||
//
|
||||
// The parameter <pointer> should be type of struct/*struct.
|
||||
//
|
||||
// The parameter <recursive> specifies whether retrieving the struct field recursively.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter up-case from struct.
|
||||
|
||||
@ -158,9 +158,14 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string]
|
||||
return v.MapStrAny()
|
||||
}
|
||||
// Using reflect for converting.
|
||||
rt := rv.Type()
|
||||
name := ""
|
||||
tagArray := structTagPriority
|
||||
var (
|
||||
rtField reflect.StructField
|
||||
rvField reflect.Value
|
||||
rvKind reflect.Kind
|
||||
rt = rv.Type()
|
||||
name = ""
|
||||
tagArray = structTagPriority
|
||||
)
|
||||
switch len(tags) {
|
||||
case 0:
|
||||
// No need handle.
|
||||
@ -169,9 +174,6 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string]
|
||||
default:
|
||||
tagArray = append(tags, structTagPriority...)
|
||||
}
|
||||
var rtField reflect.StructField
|
||||
var rvField reflect.Value
|
||||
var rvKind reflect.Kind
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
rtField = rt.Field(i)
|
||||
rvField = rv.Field(i)
|
||||
@ -188,7 +190,7 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string]
|
||||
}
|
||||
}
|
||||
if name == "" {
|
||||
name = strings.TrimSpace(fieldName)
|
||||
name = fieldName
|
||||
} else {
|
||||
// Support json tag feature: -, omitempty
|
||||
name = strings.TrimSpace(name)
|
||||
@ -216,9 +218,17 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string]
|
||||
rvKind = rvField.Kind()
|
||||
}
|
||||
if rvKind == reflect.Struct {
|
||||
for k, v := range doMapConvert(rvField.Interface(), recursive, tags...) {
|
||||
m[k] = v
|
||||
if name == fieldName {
|
||||
// It means this attribute field has no tag.
|
||||
// Overwrite the attribute with sub-struct attribute fields.
|
||||
for k, v := range doMapConvert(rvField.Interface(), recursive, tags...) {
|
||||
m[k] = v
|
||||
}
|
||||
} else {
|
||||
// It means this attribute field has desired tag.
|
||||
m[name] = doMapConvert(rvField.Interface(), recursive, tags...)
|
||||
}
|
||||
|
||||
} else {
|
||||
m[name] = rvField.Interface()
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ func Test_Map_Slice(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Map_StructWithGconvTag(t *testing.T) {
|
||||
func Test_Map_StructWithGConvTag(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
Uid int
|
||||
@ -179,7 +179,7 @@ func Test_Map_PrivateAttribute(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Map_StructInherit(t *testing.T) {
|
||||
func Test_MapDeep(t *testing.T) {
|
||||
type Ids struct {
|
||||
Id int `c:"id"`
|
||||
Uid int `c:"uid"`
|
||||
@ -216,6 +216,43 @@ func Test_Map_StructInherit(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_MapDeepWithAttributeTag(t *testing.T) {
|
||||
type Ids struct {
|
||||
Id int `c:"id"`
|
||||
Uid int `c:"uid"`
|
||||
}
|
||||
type Base struct {
|
||||
Ids `json:"ids"`
|
||||
CreateTime string `c:"create_time"`
|
||||
}
|
||||
type User struct {
|
||||
Base `json:"base"`
|
||||
Passport string `c:"passport"`
|
||||
Password string `c:"password"`
|
||||
Nickname string `c:"nickname"`
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
user := new(User)
|
||||
user.Id = 100
|
||||
user.Nickname = "john"
|
||||
user.CreateTime = "2019"
|
||||
m := gconv.Map(user)
|
||||
t.Assert(m["id"], "")
|
||||
t.Assert(m["nickname"], user.Nickname)
|
||||
t.Assert(m["create_time"], "")
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
user := new(User)
|
||||
user.Id = 100
|
||||
user.Nickname = "john"
|
||||
user.CreateTime = "2019"
|
||||
m := gconv.MapDeep(user)
|
||||
t.Assert(m["base"].(map[string]interface{})["ids"].(map[string]interface{})["id"], user.Id)
|
||||
t.Assert(m["nickname"], user.Nickname)
|
||||
t.Assert(m["base"].(map[string]interface{})["create_time"], user.CreateTime)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_MapToMap(t *testing.T) {
|
||||
type User struct {
|
||||
Id int
|
||||
@ -454,3 +491,56 @@ func Test_MapToMapsDeep(t *testing.T) {
|
||||
t.Assert(m["200"][1].Name, "jim")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_MapToMapsDeepWithTag(t *testing.T) {
|
||||
type Ids struct {
|
||||
Id int
|
||||
Uid int
|
||||
}
|
||||
type Base struct {
|
||||
Ids `json:"ids"`
|
||||
Time string
|
||||
}
|
||||
type User struct {
|
||||
Base `json:"base"`
|
||||
Name string
|
||||
}
|
||||
params := g.MapIntAny{
|
||||
100: g.Slice{
|
||||
g.Map{"id": 1, "name": "john"},
|
||||
g.Map{"id": 2, "name": "smith"},
|
||||
},
|
||||
200: g.Slice{
|
||||
g.Map{"id": 3, "name": "green"},
|
||||
g.Map{"id": 4, "name": "jim"},
|
||||
},
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := make(map[string][]*User)
|
||||
err := gconv.MapToMaps(params, &m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(len(m), 2)
|
||||
t.Assert(m["100"][0].Id, 0)
|
||||
t.Assert(m["100"][1].Id, 0)
|
||||
t.Assert(m["100"][0].Name, "john")
|
||||
t.Assert(m["100"][1].Name, "smith")
|
||||
t.Assert(m["200"][0].Id, 0)
|
||||
t.Assert(m["200"][1].Id, 0)
|
||||
t.Assert(m["200"][0].Name, "green")
|
||||
t.Assert(m["200"][1].Name, "jim")
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := make(map[string][]*User)
|
||||
err := gconv.MapToMapsDeep(params, &m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(len(m), 2)
|
||||
t.Assert(m["100"][0].Id, 1)
|
||||
t.Assert(m["100"][1].Id, 2)
|
||||
t.Assert(m["100"][0].Name, "john")
|
||||
t.Assert(m["100"][1].Name, "smith")
|
||||
t.Assert(m["200"][0].Id, 3)
|
||||
t.Assert(m["200"][1].Id, 4)
|
||||
t.Assert(m["200"][0].Name, "green")
|
||||
t.Assert(m["200"][1].Name, "jim")
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user