Skip to content

Commit c4eefd4

Browse files
committed
Allow primitive type in maps via all FieldReaders
Now that we can read primitive type out of a map, each field reader needs to be able to set the proper type as expected.
1 parent 730014b commit c4eefd4

8 files changed

Lines changed: 153 additions & 23 deletions

‎helper/schema/field_reader.go‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,33 @@ func readObjectField(
214214
}, nil
215215
}
216216

217+
// convert map values to the proper primitive type based on schema.Elem
218+
func mapValuesToPrimitive(m map[string]interface{}, schema *Schema) error {
219+
220+
elemType := TypeString
221+
if et, ok := schema.Elem.(ValueType); ok {
222+
elemType = et
223+
}
224+
225+
switch elemType {
226+
case TypeInt, TypeFloat, TypeBool:
227+
for k, v := range m {
228+
vs, ok := v.(string)
229+
if !ok {
230+
continue
231+
}
232+
233+
v, err := stringToPrimitive(vs, false, &Schema{Type: elemType})
234+
if err != nil {
235+
return err
236+
}
237+
238+
m[k] = v
239+
}
240+
}
241+
return nil
242+
}
243+
217244
func stringToPrimitive(
218245
value string, computed bool, schema *Schema) (interface{}, error) {
219246
var returnVal interface{}

‎helper/schema/field_reader_config.go‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func (r *ConfigFieldReader) readField(
8585
case TypeList:
8686
return readListField(&nestedConfigFieldReader{r}, address, schema)
8787
case TypeMap:
88-
return r.readMap(k)
88+
return r.readMap(k, schema)
8989
case TypeSet:
9090
return r.readSet(address, schema)
9191
case typeObject:
@@ -97,7 +97,7 @@ func (r *ConfigFieldReader) readField(
9797
}
9898
}
9999

100-
func (r *ConfigFieldReader) readMap(k string) (FieldReadResult, error) {
100+
func (r *ConfigFieldReader) readMap(k string, schema *Schema) (FieldReadResult, error) {
101101
// We want both the raw value and the interpolated. We use the interpolated
102102
// to store actual values and we use the raw one to check for
103103
// computed keys. Actual values are obtained in the switch, depending on
@@ -170,6 +170,11 @@ func (r *ConfigFieldReader) readMap(k string) (FieldReadResult, error) {
170170
panic(fmt.Sprintf("unknown type: %#v", mraw))
171171
}
172172

173+
err := mapValuesToPrimitive(result, schema)
174+
if err != nil {
175+
return FieldReadResult{}, nil
176+
}
177+
173178
var value interface{}
174179
if !computed {
175180
value = result

‎helper/schema/field_reader_config_test.go‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ func TestConfigFieldReader(t *testing.T) {
3535
"foo": "bar",
3636
"bar": "baz",
3737
},
38+
"mapInt": map[string]interface{}{
39+
"one": "1",
40+
"two": "2",
41+
},
42+
"mapFloat": map[string]interface{}{
43+
"oneDotTwo": "1.2",
44+
},
45+
"mapBool": map[string]interface{}{
46+
"True": "true",
47+
"False": "false",
48+
},
3849

3950
"set": []interface{}{10, 50},
4051
"setDeep": []interface{}{

‎helper/schema/field_reader_diff.go‎

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,6 @@ func (r *DiffFieldReader) readMap(
6969
resultSet = true
7070
}
7171

72-
// Determine what element type the map contains, defaulting to string
73-
elemType := TypeString
74-
if et, ok := schema.Elem.(ValueType); ok {
75-
elemType = et
76-
}
77-
7872
// Next, read all the elements we have in our diff, and apply
7973
// the diff to our result.
8074
prefix := strings.Join(address, ".") + "."
@@ -95,20 +89,12 @@ func (r *DiffFieldReader) readMap(
9589
continue
9690
}
9791

98-
// Replace the new value with one of the correct Elem type if needed.
99-
// We don't supported arbitrarily nested schemas, so we can only handle
100-
// the primitive types here.
101-
var vNew interface{} = v.New
102-
switch elemType {
103-
case TypeBool, TypeInt, TypeFloat:
104-
v, err := stringToPrimitive(v.New, false, &Schema{Type: elemType})
105-
if err != nil {
106-
return FieldReadResult{}, err
107-
}
108-
vNew = v
109-
}
92+
result[k] = v.New
93+
}
11094

111-
result[k] = vNew
95+
err = mapValuesToPrimitive(result, schema)
96+
if err != nil {
97+
return FieldReadResult{}, nil
11298
}
11399

114100
var resultVal interface{}

‎helper/schema/field_reader_diff_test.go‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,41 @@ func TestDiffFieldReader(t *testing.T) {
420420
New: "baz",
421421
},
422422

423+
"mapInt.%": &terraform.ResourceAttrDiff{
424+
Old: "",
425+
New: "2",
426+
},
427+
"mapInt.one": &terraform.ResourceAttrDiff{
428+
Old: "",
429+
New: "1",
430+
},
431+
"mapInt.two": &terraform.ResourceAttrDiff{
432+
Old: "",
433+
New: "2",
434+
},
435+
436+
"mapFloat.%": &terraform.ResourceAttrDiff{
437+
Old: "",
438+
New: "1",
439+
},
440+
"mapFloat.oneDotTwo": &terraform.ResourceAttrDiff{
441+
Old: "",
442+
New: "1.2",
443+
},
444+
445+
"mapBool.%": &terraform.ResourceAttrDiff{
446+
Old: "",
447+
New: "2",
448+
},
449+
"mapBool.True": &terraform.ResourceAttrDiff{
450+
Old: "",
451+
New: "true",
452+
},
453+
"mapBool.False": &terraform.ResourceAttrDiff{
454+
Old: "",
455+
New: "false",
456+
},
457+
423458
"set.#": &terraform.ResourceAttrDiff{
424459
Old: "0",
425460
New: "2",

‎helper/schema/field_reader_map.go‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (r *MapFieldReader) ReadField(address []string) (FieldReadResult, error) {
2626
case TypeList:
2727
return readListField(r, address, schema)
2828
case TypeMap:
29-
return r.readMap(k)
29+
return r.readMap(k, schema)
3030
case TypeSet:
3131
return r.readSet(address, schema)
3232
case typeObject:
@@ -36,7 +36,7 @@ func (r *MapFieldReader) ReadField(address []string) (FieldReadResult, error) {
3636
}
3737
}
3838

39-
func (r *MapFieldReader) readMap(k string) (FieldReadResult, error) {
39+
func (r *MapFieldReader) readMap(k string, schema *Schema) (FieldReadResult, error) {
4040
result := make(map[string]interface{})
4141
resultSet := false
4242

@@ -61,6 +61,11 @@ func (r *MapFieldReader) readMap(k string) (FieldReadResult, error) {
6161
return true
6262
})
6363

64+
err := mapValuesToPrimitive(result, schema)
65+
if err != nil {
66+
return FieldReadResult{}, nil
67+
}
68+
6469
var resultVal interface{}
6570
if resultSet {
6671
resultVal = result

‎helper/schema/field_reader_map_test.go‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ func TestMapFieldReader(t *testing.T) {
4141
"setDeep.10.value": "foo",
4242
"setDeep.50.index": "50",
4343
"setDeep.50.value": "bar",
44+
45+
"mapInt.%": "2",
46+
"mapInt.one": "1",
47+
"mapInt.two": "2",
48+
49+
"mapFloat.%": "1",
50+
"mapFloat.oneDotTwo": "1.2",
51+
52+
"mapBool.%": "2",
53+
"mapBool.True": "true",
54+
"mapBool.False": "false",
4455
}),
4556
}
4657
})

‎helper/schema/field_reader_test.go‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,18 @@ func testFieldReader(t *testing.T, f func(map[string]*Schema) FieldReader) {
211211

212212
// Maps
213213
"map": &Schema{Type: TypeMap},
214+
"mapInt": &Schema{
215+
Type: TypeMap,
216+
Elem: TypeInt,
217+
},
218+
"mapFloat": &Schema{
219+
Type: TypeMap,
220+
Elem: TypeFloat,
221+
},
222+
"mapBool": &Schema{
223+
Type: TypeMap,
224+
Elem: TypeBool,
225+
},
214226

215227
// Sets
216228
"set": &Schema{
@@ -335,6 +347,44 @@ func testFieldReader(t *testing.T, f func(map[string]*Schema) FieldReader) {
335347
false,
336348
},
337349

350+
"mapInt": {
351+
[]string{"mapInt"},
352+
FieldReadResult{
353+
Value: map[string]interface{}{
354+
"one": 1,
355+
"two": 2,
356+
},
357+
Exists: true,
358+
Computed: false,
359+
},
360+
false,
361+
},
362+
363+
"mapFloat": {
364+
[]string{"mapFloat"},
365+
FieldReadResult{
366+
Value: map[string]interface{}{
367+
"oneDotTwo": 1.2,
368+
},
369+
Exists: true,
370+
Computed: false,
371+
},
372+
false,
373+
},
374+
375+
"mapBool": {
376+
[]string{"mapBool"},
377+
FieldReadResult{
378+
Value: map[string]interface{}{
379+
"True": true,
380+
"False": false,
381+
},
382+
Exists: true,
383+
Computed: false,
384+
},
385+
false,
386+
},
387+
338388
"mapelem": {
339389
[]string{"map", "foo"},
340390
FieldReadResult{

0 commit comments

Comments
 (0)