Skip to content

Commit

Permalink
Merge pull request #29 from zenthangplus/master
Browse files Browse the repository at this point in the history
Support for map of struct
  • Loading branch information
creasty authored Apr 11, 2022
2 parents 369aea6 + f4373b2 commit f8acd9d
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 3 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@ type Sample struct {

Slice []string `default:"[]"`
SliceByJSON []int `default:"[1, 2, 3]"` // Supports JSON
Map map[string]int `default:"{}"`
MapByJSON map[string]int `default:"{\"foo\": 123}"`

Map map[string]int `default:"{}"`
MapByJSON map[string]int `default:"{\"foo\": 123}"`
MapOfStruct map[string]OtherStruct
MapOfPtrStruct map[string]*OtherStruct
MapOfStructWithTag map[string]OtherStruct `default:"{\"Key1\": {\"Foo\":123}}"`

Struct OtherStruct `default:"{}"`
StructPtr *OtherStruct `default:"{\"Foo\": 123}"`

Expand Down
27 changes: 27 additions & 0 deletions defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,31 @@ func setField(field reflect.Value, defaultVal string) error {
return err
}
}
case reflect.Map:
for _, e := range field.MapKeys() {
var v = field.MapIndex(e)
var baseVal interface{}
switch v.Kind() {
case reflect.Ptr:
baseVal = v.Elem().Interface()
default:
baseVal = v.Interface()
}
ref := reflect.New(reflect.TypeOf(baseVal))
ref.Elem().Set(reflect.ValueOf(baseVal))
err := Set(ref.Interface())
if err == nil || err == errInvalidType {
var newVal reflect.Value
if v.Kind() == reflect.Ptr {
newVal = reflect.ValueOf(ref.Interface())
} else {
newVal = reflect.ValueOf(ref.Elem().Interface())
}
field.SetMapIndex(e, newVal)
} else {
return err
}
}
}

return nil
Expand All @@ -187,6 +212,8 @@ func shouldInitializeField(field reflect.Value, tag string) bool {
}
case reflect.Slice:
return field.Len() > 0 || tag != ""
case reflect.Map:
return field.Len() > 0 || tag != ""
}

return tag != ""
Expand Down
77 changes: 76 additions & 1 deletion defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,12 @@ type Sample struct {
StructWithJSON Struct `default:"{\"Foo\": 123}"`
StructPtrWithJSON *Struct `default:"{\"Foo\": 123}"`
MapWithJSON map[string]int `default:"{\"foo\": 123}"`
SliceWithJSON []string `default:"[\"foo\"]"`

MapOfPtrStruct map[string]*Struct
MapOfStruct map[string]Struct
MapOfStructWithTag map[string]Struct `default:"{\"Struct3\": {\"Foo\":123}}"`

SliceWithJSON []string `default:"[\"foo\"]"`

Empty string `default:""`

Expand Down Expand Up @@ -203,6 +208,13 @@ func TestInit(t *testing.T) {
NonInitialStruct: Struct{Foo: 123},
NonInitialStructPtr: &Struct{Foo: 123},
DeepSliceOfStructWithNoTag: [][][]Struct{{{{Foo: 123}}}},
MapOfStruct: map[string]Struct{
"Struct1": {Foo: 1},
},
MapOfPtrStruct: map[string]*Struct{
"Struct1": {Foo: 1},
"Struct2": {Bar: 5},
},
}

if err := Set(sample); err != nil {
Expand Down Expand Up @@ -560,6 +572,69 @@ func TestInit(t *testing.T) {
}
})

t.Run("map of struct", func(t *testing.T) {
if sample.MapOfStruct == nil {
t.Errorf("it should not unset an initiated map")
}
if len(sample.MapOfStruct) != 1 {
t.Errorf("it should not override an initiated map")
}
if sample.MapOfStruct["Struct1"].Foo != 1 {
t.Errorf("it should not override Foo field in Struct1 item")
}
if sample.MapOfStruct["Struct1"].Bar != 456 {
t.Errorf("it should set default for Bar field in Struct1 item")
}
if sample.MapOfStruct["Struct1"].WithDefault != "foo" {
t.Errorf("it should set default for WithDefault field in Struct1 item")
}
})

t.Run("map of ptr struct", func(t *testing.T) {
if sample.MapOfPtrStruct == nil {
t.Errorf("it should not unset an initiated map")
}
if len(sample.MapOfPtrStruct) != 2 {
t.Errorf("it should not override an initiated map")
}
if sample.MapOfPtrStruct["Struct1"].Foo != 1 {
t.Errorf("it should not override Foo field in Struct1 item")
}
if sample.MapOfPtrStruct["Struct1"].Bar != 456 {
t.Errorf("it should set default for Bar field in Struct1 item")
}
if sample.MapOfPtrStruct["Struct1"].WithDefault != "foo" {
t.Errorf("it should set default for WithDefault field in Struct1 item")
}
if sample.MapOfPtrStruct["Struct2"].Foo != 0 {
t.Errorf("it should not override Foo field in Struct2 item")
}
if sample.MapOfPtrStruct["Struct2"].Bar != 456 {
t.Errorf("it should using setter to set default for Bar field in a Struct2 item")
}
if sample.MapOfPtrStruct["Struct2"].WithDefault != "foo" {
t.Errorf("it should set default for WithDefault field in Struct2 item")
}
})

t.Run("map of struct with tag", func(t *testing.T) {
if sample.MapOfStructWithTag == nil {
t.Errorf("it should set default")
}
if len(sample.MapOfStructWithTag) != 1 {
t.Errorf("it should set default with correct value")
}
if sample.MapOfStructWithTag["Struct3"].Foo != 123 {
t.Errorf("it should set default with correct value (Foo)")
}
if sample.MapOfStructWithTag["Struct1"].Bar != 0 {
t.Errorf("it should set default with correct value (Bar)")
}
if sample.MapOfStructWithTag["Struct1"].WithDefault != "" {
t.Errorf("it should set default with correct value (WithDefault)")
}
})

t.Run("opt-out", func(t *testing.T) {
if sample.NoDefault != nil {
t.Errorf("it should not be set")
Expand Down

0 comments on commit f8acd9d

Please sign in to comment.