created flatnested tag to convert the anonymous field in a flat map (#46)
* flat fields with the new flatten tag * added flatten tag documentation
This commit is contained in:
parent
e5ca5fe90d
commit
24f3e1df2f
17
structs.go
17
structs.go
@ -52,6 +52,12 @@ func New(s interface{}) *Struct {
|
||||
// // Map will panic if Animal does not implement String().
|
||||
// Field *Animal `structs:"field,string"`
|
||||
//
|
||||
// A tag value with the option of "flatten" used in a struct field is to flatten its fields
|
||||
// in the output map. Example:
|
||||
//
|
||||
// // The FieldStruct's fields will be flattened into the output map.
|
||||
// FieldStruct time.Time `structs:"flatten"`
|
||||
//
|
||||
// A tag value with the option of "omitnested" stops iterating further if the type
|
||||
// is a struct. Example:
|
||||
//
|
||||
@ -90,7 +96,7 @@ func (s *Struct) FillMap(out map[string]interface{}) {
|
||||
for _, field := range fields {
|
||||
name := field.Name
|
||||
val := s.value.FieldByName(name)
|
||||
|
||||
isSubStruct := false
|
||||
var finalVal interface{}
|
||||
|
||||
tagName, tagOpts := parseTag(field.Tag.Get(s.TagName))
|
||||
@ -115,6 +121,7 @@ func (s *Struct) FillMap(out map[string]interface{}) {
|
||||
n := New(val.Interface())
|
||||
n.TagName = s.TagName
|
||||
m := n.Map()
|
||||
isSubStruct = true
|
||||
if len(m) == 0 {
|
||||
finalVal = val.Interface()
|
||||
} else {
|
||||
@ -132,7 +139,13 @@ func (s *Struct) FillMap(out map[string]interface{}) {
|
||||
continue
|
||||
}
|
||||
|
||||
out[name] = finalVal
|
||||
if isSubStruct && (tagOpts.Has("flatten")) {
|
||||
for k := range finalVal.(map[string]interface{}) {
|
||||
out[k] = finalVal.(map[string]interface{})[k]
|
||||
}
|
||||
} else {
|
||||
out[name] = finalVal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -296,6 +296,60 @@ func TestMap_Anonymous(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMap_Flatnested(t *testing.T) {
|
||||
type A struct {
|
||||
Name string
|
||||
}
|
||||
a := A{Name: "example"}
|
||||
|
||||
type B struct {
|
||||
A `structs:",flatten"`
|
||||
C int
|
||||
}
|
||||
b := &B{C: 123}
|
||||
b.A = a
|
||||
|
||||
m := Map(b)
|
||||
|
||||
_, ok := m["A"].(map[string]interface{})
|
||||
if ok {
|
||||
t.Error("Embedded A struct with tag flatten has to be flat in the map")
|
||||
}
|
||||
|
||||
expectedMap := map[string]interface{}{"Name": "example", "C": 123}
|
||||
if !reflect.DeepEqual(m, expectedMap) {
|
||||
t.Errorf("The exprected map %+v does't correspond to %+v", expectedMap, m)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMap_FlatnestedOverwrite(t *testing.T) {
|
||||
type A struct {
|
||||
Name string
|
||||
}
|
||||
a := A{Name: "example"}
|
||||
|
||||
type B struct {
|
||||
A `structs:",flatten"`
|
||||
Name string
|
||||
C int
|
||||
}
|
||||
b := &B{C: 123, Name: "bName"}
|
||||
b.A = a
|
||||
|
||||
m := Map(b)
|
||||
|
||||
_, ok := m["A"].(map[string]interface{})
|
||||
if ok {
|
||||
t.Error("Embedded A struct with tag flatten has to be flat in the map")
|
||||
}
|
||||
|
||||
expectedMap := map[string]interface{}{"Name": "bName", "C": 123}
|
||||
if !reflect.DeepEqual(m, expectedMap) {
|
||||
t.Errorf("The exprected map %+v does't correspond to %+v", expectedMap, m)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMap_TimeField(t *testing.T) {
|
||||
type A struct {
|
||||
CreatedAt time.Time
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user