@@ -22,40 +22,57 @@ const (
22
22
recursiveTypeTrue recursiveType = "true"
23
23
)
24
24
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
+
25
39
// Map converts any variable `value` to map[string]interface{}. If the parameter `value` is not a
26
40
// map/struct/*struct type, then the conversion will fail and returns nil.
27
41
//
28
42
// If `value` is a struct/*struct object, the second parameter `tags` specifies the most priority
29
43
// tags that will be detected, otherwise it detects the tags in order of:
30
44
// 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 ... )
33
47
}
34
48
35
49
// MapDeep does Map function recursively, which means if the attribute of `value`
36
50
// is also a struct/*struct, calls Map function on this attribute converting it to
37
51
// a map[string]interface{} type variable.
38
- // Also see Map.
52
+ // Deprecated: used Map instead .
39
53
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
+ })
41
57
}
42
58
43
59
// doMapConvert implements the map converting.
44
60
// It automatically checks and converts json string to map if `value` is string/[]byte.
45
61
//
46
62
// 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 {} {
48
64
if value == nil {
49
65
return nil
50
66
}
67
+ var usedOption = getUsedMapOption (option ... )
51
68
newTags := StructTagPriority
52
- switch len (tags ) {
69
+ switch len (usedOption . Tags ) {
53
70
case 0 :
54
71
// No need handling.
55
72
case 1 :
56
- newTags = append (strings .Split (tags [0 ], "," ), StructTagPriority ... )
73
+ newTags = append (strings .Split (usedOption . Tags [0 ], "," ), StructTagPriority ... )
57
74
default :
58
- newTags = append (tags , StructTagPriority ... )
75
+ newTags = append (usedOption . Tags , StructTagPriority ... )
59
76
}
60
77
// Assert the common combination of types, and finally it uses reflection.
61
78
dataMap := make (map [string ]interface {})
@@ -79,14 +96,16 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
79
96
return nil
80
97
}
81
98
case map [interface {}]interface {}:
99
+ recursiveOption := usedOption
100
+ recursiveOption .Tags = newTags
82
101
for k , v := range r {
83
102
dataMap [String (k )] = doMapConvertForMapOrStructValue (
84
103
doMapConvertForMapOrStructValueInput {
85
104
IsRoot : false ,
86
105
Value : v ,
87
106
RecursiveType : recursive ,
88
107
RecursiveOption : recursive == recursiveTypeTrue ,
89
- Tags : newTags ,
108
+ Option : recursiveOption ,
90
109
},
91
110
)
92
111
}
@@ -136,6 +155,8 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
136
155
}
137
156
case map [string ]interface {}:
138
157
if recursive == recursiveTypeTrue {
158
+ recursiveOption := usedOption
159
+ recursiveOption .Tags = newTags
139
160
// A copy of current map.
140
161
for k , v := range r {
141
162
dataMap [k ] = doMapConvertForMapOrStructValue (
@@ -144,7 +165,7 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
144
165
Value : v ,
145
166
RecursiveType : recursive ,
146
167
RecursiveOption : recursive == recursiveTypeTrue ,
147
- Tags : newTags ,
168
+ Option : recursiveOption ,
148
169
},
149
170
)
150
171
}
@@ -153,14 +174,16 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
153
174
return r
154
175
}
155
176
case map [int ]interface {}:
177
+ recursiveOption := usedOption
178
+ recursiveOption .Tags = newTags
156
179
for k , v := range r {
157
180
dataMap [String (k )] = doMapConvertForMapOrStructValue (
158
181
doMapConvertForMapOrStructValueInput {
159
182
IsRoot : false ,
160
183
Value : v ,
161
184
RecursiveType : recursive ,
162
185
RecursiveOption : recursive == recursiveTypeTrue ,
163
- Tags : newTags ,
186
+ Option : recursiveOption ,
164
187
},
165
188
)
166
189
}
@@ -202,13 +225,15 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
202
225
}
203
226
}
204
227
case reflect .Map , reflect .Struct , reflect .Interface :
228
+ recursiveOption := usedOption
229
+ recursiveOption .Tags = newTags
205
230
convertedValue := doMapConvertForMapOrStructValue (
206
231
doMapConvertForMapOrStructValueInput {
207
232
IsRoot : true ,
208
233
Value : value ,
209
234
RecursiveType : recursive ,
210
235
RecursiveOption : recursive == recursiveTypeTrue ,
211
- Tags : newTags ,
236
+ Option : recursiveOption ,
212
237
MustMapReturn : mustMapReturn ,
213
238
},
214
239
)
@@ -223,12 +248,20 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
223
248
return dataMap
224
249
}
225
250
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
+
226
259
type doMapConvertForMapOrStructValueInput struct {
227
260
IsRoot bool // It returns directly if it is not root and with no recursive converting.
228
261
Value interface {} // Current operation value.
229
262
RecursiveType recursiveType // The type from top function entry.
230
263
RecursiveOption bool // Whether convert recursively for `current` operation.
231
- Tags [] string // Map key mapping .
264
+ Option MapOption // Map converting option .
232
265
MustMapReturn bool // Must return map instead of Value when empty.
233
266
}
234
267
@@ -280,7 +313,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
280
313
Value : mapValue ,
281
314
RecursiveType : in .RecursiveType ,
282
315
RecursiveOption : in .RecursiveType == recursiveTypeTrue ,
283
- Tags : in .Tags ,
316
+ Option : in .Option ,
284
317
},
285
318
)
286
319
}
@@ -299,7 +332,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
299
332
Value : mapV ,
300
333
RecursiveType : in .RecursiveType ,
301
334
RecursiveOption : in .RecursiveType == recursiveTypeTrue ,
302
- Tags : in .Tags ,
335
+ Option : in .Option ,
303
336
},
304
337
)
305
338
} else {
@@ -327,7 +360,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
327
360
}
328
361
mapKey = ""
329
362
fieldTag := rtField .Tag
330
- for _ , tag := range in .Tags {
363
+ for _ , tag := range in .Option . Tags {
331
364
if mapKey = fieldTag .Get (tag ); mapKey != "" {
332
365
break
333
366
}
@@ -344,7 +377,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
344
377
if len (array ) > 1 {
345
378
switch strings .TrimSpace (array [1 ]) {
346
379
case "omitempty" :
347
- if empty .IsEmpty (rvField .Interface ()) {
380
+ if in . Option . OmitEmpty && empty .IsEmpty (rvField .Interface ()) {
348
381
continue
349
382
} else {
350
383
mapKey = strings .TrimSpace (array [0 ])
@@ -389,7 +422,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
389
422
Value : rvInterface ,
390
423
RecursiveType : in .RecursiveType ,
391
424
RecursiveOption : true ,
392
- Tags : in .Tags ,
425
+ Option : in .Option ,
393
426
})
394
427
if m , ok := anonymousValue .(map [string ]interface {}); ok {
395
428
for k , v := range m {
@@ -406,7 +439,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
406
439
Value : rvInterface ,
407
440
RecursiveType : in .RecursiveType ,
408
441
RecursiveOption : true ,
409
- Tags : in .Tags ,
442
+ Option : in .Option ,
410
443
})
411
444
412
445
default :
@@ -415,7 +448,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
415
448
Value : rvInterface ,
416
449
RecursiveType : in .RecursiveType ,
417
450
RecursiveOption : in .RecursiveType == recursiveTypeTrue ,
418
- Tags : in .Tags ,
451
+ Option : in .Option ,
419
452
})
420
453
}
421
454
@@ -434,7 +467,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
434
467
Value : rvAttrField .Index (arrayIndex ).Interface (),
435
468
RecursiveType : in .RecursiveType ,
436
469
RecursiveOption : in .RecursiveType == recursiveTypeTrue ,
437
- Tags : in .Tags ,
470
+ Option : in .Option ,
438
471
},
439
472
)
440
473
}
@@ -451,7 +484,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
451
484
Value : rvAttrField .MapIndex (k ).Interface (),
452
485
RecursiveType : in .RecursiveType ,
453
486
RecursiveOption : in .RecursiveType == recursiveTypeTrue ,
454
- Tags : in .Tags ,
487
+ Option : in .Option ,
455
488
},
456
489
)
457
490
}
@@ -490,7 +523,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
490
523
Value : reflectValue .Index (i ).Interface (),
491
524
RecursiveType : in .RecursiveType ,
492
525
RecursiveOption : in .RecursiveType == recursiveTypeTrue ,
493
- Tags : in .Tags ,
526
+ Option : in .Option ,
494
527
})
495
528
}
496
529
return array
@@ -500,11 +533,11 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
500
533
501
534
// MapStrStr converts `value` to map[string]string.
502
535
// 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 {
504
537
if r , ok := value .(map [string ]string ); ok {
505
538
return r
506
539
}
507
- m := Map (value , tags ... )
540
+ m := Map (value , option ... )
508
541
if len (m ) > 0 {
509
542
vMap := make (map [string ]string , len (m ))
510
543
for k , v := range m {
@@ -517,6 +550,7 @@ func MapStrStr(value interface{}, tags ...string) map[string]string {
517
550
518
551
// MapStrStrDeep converts `value` to map[string]string recursively.
519
552
// Note that there might be data copy for this map type converting.
553
+ // Deprecated: used MapStrStr instead.
520
554
func MapStrStrDeep (value interface {}, tags ... string ) map [string ]string {
521
555
if r , ok := value .(map [string ]string ); ok {
522
556
return r
0 commit comments