Skip to content

Commit 9aa872e

Browse files
authored
improve map converting feature using MapOption for package gconv (gogf#3170)
1 parent ea5d52c commit 9aa872e

File tree

7 files changed

+139
-50
lines changed

7 files changed

+139
-50
lines changed

container/gvar/gvar_map.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,27 @@ package gvar
88

99
import "github.com/gogf/gf/v2/util/gconv"
1010

11+
// MapOption specifies the option for map converting.
12+
type MapOption = gconv.MapOption
13+
1114
// Map converts and returns `v` as map[string]interface{}.
12-
func (v *Var) Map(tags ...string) map[string]interface{} {
13-
return gconv.Map(v.Val(), tags...)
15+
func (v *Var) Map(option ...MapOption) map[string]interface{} {
16+
return gconv.Map(v.Val(), option...)
1417
}
1518

1619
// MapStrAny is like function Map, but implements the interface of MapStrAny.
17-
func (v *Var) MapStrAny() map[string]interface{} {
18-
return v.Map()
20+
func (v *Var) MapStrAny(option ...MapOption) map[string]interface{} {
21+
return v.Map(option...)
1922
}
2023

2124
// MapStrStr converts and returns `v` as map[string]string.
22-
func (v *Var) MapStrStr(tags ...string) map[string]string {
23-
return gconv.MapStrStr(v.Val(), tags...)
25+
func (v *Var) MapStrStr(option ...MapOption) map[string]string {
26+
return gconv.MapStrStr(v.Val(), option...)
2427
}
2528

2629
// MapStrVar converts and returns `v` as map[string]Var.
27-
func (v *Var) MapStrVar(tags ...string) map[string]*Var {
28-
m := v.Map(tags...)
30+
func (v *Var) MapStrVar(option ...MapOption) map[string]*Var {
31+
m := v.Map(option...)
2932
if len(m) > 0 {
3033
vMap := make(map[string]*Var, len(m))
3134
for k, v := range m {
@@ -37,16 +40,19 @@ func (v *Var) MapStrVar(tags ...string) map[string]*Var {
3740
}
3841

3942
// MapDeep converts and returns `v` as map[string]interface{} recursively.
43+
// Deprecated: used Map instead.
4044
func (v *Var) MapDeep(tags ...string) map[string]interface{} {
4145
return gconv.MapDeep(v.Val(), tags...)
4246
}
4347

4448
// MapStrStrDeep converts and returns `v` as map[string]string recursively.
49+
// Deprecated: used MapStrStr instead.
4550
func (v *Var) MapStrStrDeep(tags ...string) map[string]string {
4651
return gconv.MapStrStrDeep(v.Val(), tags...)
4752
}
4853

4954
// MapStrVarDeep converts and returns `v` as map[string]*Var recursively.
55+
// Deprecated: used MapStrVar instead.
5056
func (v *Var) MapStrVarDeep(tags ...string) map[string]*Var {
5157
m := v.MapDeep(tags...)
5258
if len(m) > 0 {
@@ -61,12 +67,12 @@ func (v *Var) MapStrVarDeep(tags ...string) map[string]*Var {
6167

6268
// Maps converts and returns `v` as map[string]string.
6369
// See gconv.Maps.
64-
func (v *Var) Maps(tags ...string) []map[string]interface{} {
65-
return gconv.Maps(v.Val(), tags...)
70+
func (v *Var) Maps(option ...MapOption) []map[string]interface{} {
71+
return gconv.Maps(v.Val(), option...)
6672
}
6773

6874
// MapsDeep converts `value` to []map[string]interface{} recursively.
69-
// See gconv.MapsDeep.
75+
// Deprecated: used Maps instead.
7076
func (v *Var) MapsDeep(tags ...string) []map[string]interface{} {
7177
return gconv.MapsDeep(v.Val(), tags...)
7278
}

database/gdb/gdb_func.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,14 @@ func GetInsertOperationByOption(option InsertOption) string {
210210
}
211211

212212
func anyValueToMapBeforeToRecord(value interface{}) map[string]interface{} {
213-
return gconv.Map(value, structTagPriority...)
213+
return gconv.Map(value, gconv.MapOption{Tags: structTagPriority})
214214
}
215215

216216
// DataToMapDeep converts `value` to map type recursively(if attribute struct is embedded).
217217
// The parameter `value` should be type of *map/map/*struct/struct.
218218
// It supports embedded struct definition for struct.
219219
func DataToMapDeep(value interface{}) map[string]interface{} {
220-
m := gconv.Map(value, structTagPriority...)
220+
m := gconv.Map(value, gconv.MapOption{Tags: structTagPriority})
221221
for k, v := range m {
222222
switch v.(type) {
223223
case time.Time, *time.Time, gtime.Time, *gtime.Time, gjson.Json, *gjson.Json:

util/gconv/gconv_map.go

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,40 +22,57 @@ const (
2222
recursiveTypeTrue recursiveType = "true"
2323
)
2424

25+
// MapOption specifies the option for map converting.
26+
type MapOption struct {
27+
// Deep marks doing Map function recursively, which means if the attribute of given converting value
28+
// is also a struct/*struct, it automatically calls Map function on this attribute converting it to
29+
// a map[string]interface{} type variable.
30+
Deep bool
31+
32+
// OmitEmpty ignores the attributes that has json omitempty tag.
33+
OmitEmpty bool
34+
35+
// Tags specifies the converted map key name by struct tag name.
36+
Tags []string
37+
}
38+
2539
// Map converts any variable `value` to map[string]interface{}. If the parameter `value` is not a
2640
// map/struct/*struct type, then the conversion will fail and returns nil.
2741
//
2842
// If `value` is a struct/*struct object, the second parameter `tags` specifies the most priority
2943
// tags that will be detected, otherwise it detects the tags in order of:
3044
// gconv, json, field name.
31-
func Map(value interface{}, tags ...string) map[string]interface{} {
32-
return doMapConvert(value, recursiveTypeAuto, false, tags...)
45+
func Map(value interface{}, option ...MapOption) map[string]interface{} {
46+
return doMapConvert(value, recursiveTypeAuto, false, option...)
3347
}
3448

3549
// MapDeep does Map function recursively, which means if the attribute of `value`
3650
// is also a struct/*struct, calls Map function on this attribute converting it to
3751
// a map[string]interface{} type variable.
38-
// Also see Map.
52+
// Deprecated: used Map instead.
3953
func MapDeep(value interface{}, tags ...string) map[string]interface{} {
40-
return doMapConvert(value, recursiveTypeTrue, false, tags...)
54+
return doMapConvert(value, recursiveTypeTrue, false, MapOption{
55+
Tags: tags,
56+
})
4157
}
4258

4359
// doMapConvert implements the map converting.
4460
// It automatically checks and converts json string to map if `value` is string/[]byte.
4561
//
4662
// TODO completely implement the recursive converting for all types, especially the map.
47-
func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, tags ...string) map[string]interface{} {
63+
func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} {
4864
if value == nil {
4965
return nil
5066
}
67+
var usedOption = getUsedMapOption(option...)
5168
newTags := StructTagPriority
52-
switch len(tags) {
69+
switch len(usedOption.Tags) {
5370
case 0:
5471
// No need handling.
5572
case 1:
56-
newTags = append(strings.Split(tags[0], ","), StructTagPriority...)
73+
newTags = append(strings.Split(usedOption.Tags[0], ","), StructTagPriority...)
5774
default:
58-
newTags = append(tags, StructTagPriority...)
75+
newTags = append(usedOption.Tags, StructTagPriority...)
5976
}
6077
// Assert the common combination of types, and finally it uses reflection.
6178
dataMap := make(map[string]interface{})
@@ -79,14 +96,16 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
7996
return nil
8097
}
8198
case map[interface{}]interface{}:
99+
recursiveOption := usedOption
100+
recursiveOption.Tags = newTags
82101
for k, v := range r {
83102
dataMap[String(k)] = doMapConvertForMapOrStructValue(
84103
doMapConvertForMapOrStructValueInput{
85104
IsRoot: false,
86105
Value: v,
87106
RecursiveType: recursive,
88107
RecursiveOption: recursive == recursiveTypeTrue,
89-
Tags: newTags,
108+
Option: recursiveOption,
90109
},
91110
)
92111
}
@@ -136,6 +155,8 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
136155
}
137156
case map[string]interface{}:
138157
if recursive == recursiveTypeTrue {
158+
recursiveOption := usedOption
159+
recursiveOption.Tags = newTags
139160
// A copy of current map.
140161
for k, v := range r {
141162
dataMap[k] = doMapConvertForMapOrStructValue(
@@ -144,7 +165,7 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
144165
Value: v,
145166
RecursiveType: recursive,
146167
RecursiveOption: recursive == recursiveTypeTrue,
147-
Tags: newTags,
168+
Option: recursiveOption,
148169
},
149170
)
150171
}
@@ -153,14 +174,16 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
153174
return r
154175
}
155176
case map[int]interface{}:
177+
recursiveOption := usedOption
178+
recursiveOption.Tags = newTags
156179
for k, v := range r {
157180
dataMap[String(k)] = doMapConvertForMapOrStructValue(
158181
doMapConvertForMapOrStructValueInput{
159182
IsRoot: false,
160183
Value: v,
161184
RecursiveType: recursive,
162185
RecursiveOption: recursive == recursiveTypeTrue,
163-
Tags: newTags,
186+
Option: recursiveOption,
164187
},
165188
)
166189
}
@@ -202,13 +225,15 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
202225
}
203226
}
204227
case reflect.Map, reflect.Struct, reflect.Interface:
228+
recursiveOption := usedOption
229+
recursiveOption.Tags = newTags
205230
convertedValue := doMapConvertForMapOrStructValue(
206231
doMapConvertForMapOrStructValueInput{
207232
IsRoot: true,
208233
Value: value,
209234
RecursiveType: recursive,
210235
RecursiveOption: recursive == recursiveTypeTrue,
211-
Tags: newTags,
236+
Option: recursiveOption,
212237
MustMapReturn: mustMapReturn,
213238
},
214239
)
@@ -223,12 +248,20 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
223248
return dataMap
224249
}
225250

251+
func getUsedMapOption(option ...MapOption) MapOption {
252+
var usedOption MapOption
253+
if len(option) > 0 {
254+
usedOption = option[0]
255+
}
256+
return usedOption
257+
}
258+
226259
type doMapConvertForMapOrStructValueInput struct {
227260
IsRoot bool // It returns directly if it is not root and with no recursive converting.
228261
Value interface{} // Current operation value.
229262
RecursiveType recursiveType // The type from top function entry.
230263
RecursiveOption bool // Whether convert recursively for `current` operation.
231-
Tags []string // Map key mapping.
264+
Option MapOption // Map converting option.
232265
MustMapReturn bool // Must return map instead of Value when empty.
233266
}
234267

@@ -280,7 +313,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
280313
Value: mapValue,
281314
RecursiveType: in.RecursiveType,
282315
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
283-
Tags: in.Tags,
316+
Option: in.Option,
284317
},
285318
)
286319
}
@@ -299,7 +332,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
299332
Value: mapV,
300333
RecursiveType: in.RecursiveType,
301334
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
302-
Tags: in.Tags,
335+
Option: in.Option,
303336
},
304337
)
305338
} else {
@@ -327,7 +360,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
327360
}
328361
mapKey = ""
329362
fieldTag := rtField.Tag
330-
for _, tag := range in.Tags {
363+
for _, tag := range in.Option.Tags {
331364
if mapKey = fieldTag.Get(tag); mapKey != "" {
332365
break
333366
}
@@ -344,7 +377,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
344377
if len(array) > 1 {
345378
switch strings.TrimSpace(array[1]) {
346379
case "omitempty":
347-
if empty.IsEmpty(rvField.Interface()) {
380+
if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) {
348381
continue
349382
} else {
350383
mapKey = strings.TrimSpace(array[0])
@@ -389,7 +422,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
389422
Value: rvInterface,
390423
RecursiveType: in.RecursiveType,
391424
RecursiveOption: true,
392-
Tags: in.Tags,
425+
Option: in.Option,
393426
})
394427
if m, ok := anonymousValue.(map[string]interface{}); ok {
395428
for k, v := range m {
@@ -406,7 +439,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
406439
Value: rvInterface,
407440
RecursiveType: in.RecursiveType,
408441
RecursiveOption: true,
409-
Tags: in.Tags,
442+
Option: in.Option,
410443
})
411444

412445
default:
@@ -415,7 +448,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
415448
Value: rvInterface,
416449
RecursiveType: in.RecursiveType,
417450
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
418-
Tags: in.Tags,
451+
Option: in.Option,
419452
})
420453
}
421454

@@ -434,7 +467,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
434467
Value: rvAttrField.Index(arrayIndex).Interface(),
435468
RecursiveType: in.RecursiveType,
436469
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
437-
Tags: in.Tags,
470+
Option: in.Option,
438471
},
439472
)
440473
}
@@ -451,7 +484,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
451484
Value: rvAttrField.MapIndex(k).Interface(),
452485
RecursiveType: in.RecursiveType,
453486
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
454-
Tags: in.Tags,
487+
Option: in.Option,
455488
},
456489
)
457490
}
@@ -490,7 +523,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
490523
Value: reflectValue.Index(i).Interface(),
491524
RecursiveType: in.RecursiveType,
492525
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
493-
Tags: in.Tags,
526+
Option: in.Option,
494527
})
495528
}
496529
return array
@@ -500,11 +533,11 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
500533

501534
// MapStrStr converts `value` to map[string]string.
502535
// Note that there might be data copy for this map type converting.
503-
func MapStrStr(value interface{}, tags ...string) map[string]string {
536+
func MapStrStr(value interface{}, option ...MapOption) map[string]string {
504537
if r, ok := value.(map[string]string); ok {
505538
return r
506539
}
507-
m := Map(value, tags...)
540+
m := Map(value, option...)
508541
if len(m) > 0 {
509542
vMap := make(map[string]string, len(m))
510543
for k, v := range m {
@@ -517,6 +550,7 @@ func MapStrStr(value interface{}, tags ...string) map[string]string {
517550

518551
// MapStrStrDeep converts `value` to map[string]string recursively.
519552
// Note that there might be data copy for this map type converting.
553+
// Deprecated: used MapStrStr instead.
520554
func MapStrStrDeep(value interface{}, tags ...string) map[string]string {
521555
if r, ok := value.(map[string]string); ok {
522556
return r

0 commit comments

Comments
 (0)