Skip to content

Commit c97971d

Browse files
authored
Adding support for squash: interface. (#17)
* Adding support for squash: interface. * fix lint issues.
1 parent 2842dc8 commit c97971d

File tree

2 files changed

+203
-3
lines changed

2 files changed

+203
-3
lines changed

mapstructure.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -1375,10 +1375,15 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
13751375
}
13761376

13771377
if squash {
1378-
if fieldVal.Kind() != reflect.Struct {
1379-
errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind()))
1380-
} else {
1378+
switch fieldVal.Kind() {
1379+
case reflect.Struct:
13811380
structs = append(structs, fieldVal)
1381+
case reflect.Interface:
1382+
if !fieldVal.IsNil() {
1383+
structs = append(structs, fieldVal.Elem().Elem())
1384+
}
1385+
default:
1386+
errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind()))
13821387
}
13831388
continue
13841389
}

mapstructure_test.go

+195
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,60 @@ type SquashOnNonStructType struct {
113113
InvalidSquashType int `mapstructure:",squash"`
114114
}
115115

116+
type TestInterface interface {
117+
GetVfoo() string
118+
GetVbarfoo() string
119+
GetVfoobar() string
120+
}
121+
122+
type TestInterfaceImpl struct {
123+
Vfoo string
124+
}
125+
126+
func (t *TestInterfaceImpl) GetVfoo() string {
127+
return t.Vfoo
128+
}
129+
130+
func (t *TestInterfaceImpl) GetVbarfoo() string {
131+
return ""
132+
}
133+
134+
func (t *TestInterfaceImpl) GetVfoobar() string {
135+
return ""
136+
}
137+
138+
type TestNestedInterfaceImpl struct {
139+
SquashOnNestedInterfaceType `mapstructure:",squash"`
140+
Vfoo string
141+
}
142+
143+
func (t *TestNestedInterfaceImpl) GetVfoo() string {
144+
return t.Vfoo
145+
}
146+
147+
func (t *TestNestedInterfaceImpl) GetVbarfoo() string {
148+
return t.Vbarfoo
149+
}
150+
151+
func (t *TestNestedInterfaceImpl) GetVfoobar() string {
152+
return t.NestedSquash.Vfoobar
153+
}
154+
155+
type SquashOnInterfaceType struct {
156+
TestInterface `mapstructure:",squash"`
157+
Vbar string
158+
}
159+
160+
type NestedSquash struct {
161+
SquashOnInterfaceType `mapstructure:",squash"`
162+
Vfoobar string
163+
}
164+
165+
type SquashOnNestedInterfaceType struct {
166+
NestedSquash NestedSquash `mapstructure:",squash"`
167+
Vbarfoo string
168+
}
169+
116170
type Map struct {
117171
Vfoo string
118172
Vother map[string]string
@@ -1051,6 +1105,147 @@ func TestDecode_SquashOnNonStructType(t *testing.T) {
10511105
}
10521106
}
10531107

1108+
func TestDecode_SquashOnInterfaceType(t *testing.T) {
1109+
t.Parallel()
1110+
1111+
input := map[string]interface{}{
1112+
"VFoo": "42",
1113+
"VBar": "43",
1114+
}
1115+
1116+
result := SquashOnInterfaceType{
1117+
TestInterface: &TestInterfaceImpl{},
1118+
}
1119+
err := Decode(input, &result)
1120+
if err != nil {
1121+
t.Fatalf("got an err: %s", err)
1122+
}
1123+
1124+
res := result.GetVfoo()
1125+
if res != "42" {
1126+
t.Errorf("unexpected value for VFoo: %s", res)
1127+
}
1128+
1129+
res = result.Vbar
1130+
if res != "43" {
1131+
t.Errorf("unexpected value for Vbar: %s", res)
1132+
}
1133+
}
1134+
1135+
func TestDecode_SquashOnOuterNestedInterfaceType(t *testing.T) {
1136+
t.Parallel()
1137+
1138+
input := map[string]interface{}{
1139+
"VFoo": "42",
1140+
"VBar": "43",
1141+
"Vfoobar": "44",
1142+
"Vbarfoo": "45",
1143+
}
1144+
1145+
result := SquashOnNestedInterfaceType{
1146+
NestedSquash: NestedSquash{
1147+
SquashOnInterfaceType: SquashOnInterfaceType{
1148+
TestInterface: &TestInterfaceImpl{},
1149+
},
1150+
},
1151+
}
1152+
1153+
err := Decode(input, &result)
1154+
if err != nil {
1155+
t.Fatalf("got an err: %s", err)
1156+
}
1157+
1158+
res := result.NestedSquash.GetVfoo()
1159+
if res != "42" {
1160+
t.Errorf("unexpected value for VFoo: %s", res)
1161+
}
1162+
1163+
res = result.NestedSquash.Vbar
1164+
if res != "43" {
1165+
t.Errorf("unexpected value for Vbar: %s", res)
1166+
}
1167+
1168+
res = result.NestedSquash.Vfoobar
1169+
if res != "44" {
1170+
t.Errorf("unexpected value for Vfoobar: %s", res)
1171+
}
1172+
1173+
res = result.Vbarfoo
1174+
if res != "45" {
1175+
t.Errorf("unexpected value for Vbarfoo: %s", res)
1176+
}
1177+
}
1178+
1179+
func TestDecode_SquashOnInnerNestedInterfaceType(t *testing.T) {
1180+
t.Parallel()
1181+
1182+
input := map[string]interface{}{
1183+
"VFoo": "42",
1184+
"VBar": "43",
1185+
"Vfoobar": "44",
1186+
"Vbarfoo": "45",
1187+
}
1188+
1189+
result := SquashOnInterfaceType{
1190+
TestInterface: &TestNestedInterfaceImpl{
1191+
SquashOnNestedInterfaceType: SquashOnNestedInterfaceType{
1192+
NestedSquash: NestedSquash{
1193+
SquashOnInterfaceType: SquashOnInterfaceType{
1194+
TestInterface: &TestInterfaceImpl{},
1195+
},
1196+
},
1197+
},
1198+
},
1199+
}
1200+
1201+
err := Decode(input, &result)
1202+
if err != nil {
1203+
t.Fatalf("got an err: %s", err)
1204+
}
1205+
1206+
res := result.GetVfoo()
1207+
if res != "42" {
1208+
t.Errorf("unexpected value for VFoo: %s", res)
1209+
}
1210+
1211+
res = result.Vbar
1212+
if res != "43" {
1213+
t.Errorf("unexpected value for Vbar: %s", res)
1214+
}
1215+
1216+
res = result.GetVfoobar()
1217+
if res != "44" {
1218+
t.Errorf("unexpected value for Vfoobar: %s", res)
1219+
}
1220+
1221+
res = result.GetVbarfoo()
1222+
if res != "45" {
1223+
t.Errorf("unexpected value for Vbarfoo: %s", res)
1224+
}
1225+
}
1226+
1227+
func TestDecode_SquashOnNilInterfaceType(t *testing.T) {
1228+
t.Parallel()
1229+
1230+
input := map[string]interface{}{
1231+
"VFoo": "42",
1232+
"VBar": "43",
1233+
}
1234+
1235+
result := SquashOnInterfaceType{
1236+
TestInterface: nil,
1237+
}
1238+
err := Decode(input, &result)
1239+
if err != nil {
1240+
t.Fatalf("got an err: %s", err)
1241+
}
1242+
1243+
res := result.Vbar
1244+
if res != "43" {
1245+
t.Errorf("unexpected value for Vbar: %s", res)
1246+
}
1247+
}
1248+
10541249
func TestDecode_DecodeHook(t *testing.T) {
10551250
t.Parallel()
10561251

0 commit comments

Comments
 (0)