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.
This commit is contained in:
parent
730014b33e
commit
c4eefd4b5e
|
@ -214,6 +214,33 @@ func readObjectField(
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert map values to the proper primitive type based on schema.Elem
|
||||||
|
func mapValuesToPrimitive(m map[string]interface{}, schema *Schema) error {
|
||||||
|
|
||||||
|
elemType := TypeString
|
||||||
|
if et, ok := schema.Elem.(ValueType); ok {
|
||||||
|
elemType = et
|
||||||
|
}
|
||||||
|
|
||||||
|
switch elemType {
|
||||||
|
case TypeInt, TypeFloat, TypeBool:
|
||||||
|
for k, v := range m {
|
||||||
|
vs, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := stringToPrimitive(vs, false, &Schema{Type: elemType})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func stringToPrimitive(
|
func stringToPrimitive(
|
||||||
value string, computed bool, schema *Schema) (interface{}, error) {
|
value string, computed bool, schema *Schema) (interface{}, error) {
|
||||||
var returnVal interface{}
|
var returnVal interface{}
|
||||||
|
|
|
@ -85,7 +85,7 @@ func (r *ConfigFieldReader) readField(
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return readListField(&nestedConfigFieldReader{r}, address, schema)
|
return readListField(&nestedConfigFieldReader{r}, address, schema)
|
||||||
case TypeMap:
|
case TypeMap:
|
||||||
return r.readMap(k)
|
return r.readMap(k, schema)
|
||||||
case TypeSet:
|
case TypeSet:
|
||||||
return r.readSet(address, schema)
|
return r.readSet(address, schema)
|
||||||
case typeObject:
|
case typeObject:
|
||||||
|
@ -97,7 +97,7 @@ func (r *ConfigFieldReader) readField(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ConfigFieldReader) readMap(k string) (FieldReadResult, error) {
|
func (r *ConfigFieldReader) readMap(k string, schema *Schema) (FieldReadResult, error) {
|
||||||
// We want both the raw value and the interpolated. We use the interpolated
|
// We want both the raw value and the interpolated. We use the interpolated
|
||||||
// to store actual values and we use the raw one to check for
|
// to store actual values and we use the raw one to check for
|
||||||
// computed keys. Actual values are obtained in the switch, depending on
|
// computed keys. Actual values are obtained in the switch, depending on
|
||||||
|
@ -170,6 +170,11 @@ func (r *ConfigFieldReader) readMap(k string) (FieldReadResult, error) {
|
||||||
panic(fmt.Sprintf("unknown type: %#v", mraw))
|
panic(fmt.Sprintf("unknown type: %#v", mraw))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err := mapValuesToPrimitive(result, schema)
|
||||||
|
if err != nil {
|
||||||
|
return FieldReadResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
var value interface{}
|
var value interface{}
|
||||||
if !computed {
|
if !computed {
|
||||||
value = result
|
value = result
|
||||||
|
|
|
@ -35,6 +35,17 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"bar": "baz",
|
"bar": "baz",
|
||||||
},
|
},
|
||||||
|
"mapInt": map[string]interface{}{
|
||||||
|
"one": "1",
|
||||||
|
"two": "2",
|
||||||
|
},
|
||||||
|
"mapFloat": map[string]interface{}{
|
||||||
|
"oneDotTwo": "1.2",
|
||||||
|
},
|
||||||
|
"mapBool": map[string]interface{}{
|
||||||
|
"True": "true",
|
||||||
|
"False": "false",
|
||||||
|
},
|
||||||
|
|
||||||
"set": []interface{}{10, 50},
|
"set": []interface{}{10, 50},
|
||||||
"setDeep": []interface{}{
|
"setDeep": []interface{}{
|
||||||
|
|
|
@ -69,12 +69,6 @@ func (r *DiffFieldReader) readMap(
|
||||||
resultSet = true
|
resultSet = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine what element type the map contains, defaulting to string
|
|
||||||
elemType := TypeString
|
|
||||||
if et, ok := schema.Elem.(ValueType); ok {
|
|
||||||
elemType = et
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, read all the elements we have in our diff, and apply
|
// Next, read all the elements we have in our diff, and apply
|
||||||
// the diff to our result.
|
// the diff to our result.
|
||||||
prefix := strings.Join(address, ".") + "."
|
prefix := strings.Join(address, ".") + "."
|
||||||
|
@ -95,20 +89,12 @@ func (r *DiffFieldReader) readMap(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the new value with one of the correct Elem type if needed.
|
result[k] = v.New
|
||||||
// We don't supported arbitrarily nested schemas, so we can only handle
|
|
||||||
// the primitive types here.
|
|
||||||
var vNew interface{} = v.New
|
|
||||||
switch elemType {
|
|
||||||
case TypeBool, TypeInt, TypeFloat:
|
|
||||||
v, err := stringToPrimitive(v.New, false, &Schema{Type: elemType})
|
|
||||||
if err != nil {
|
|
||||||
return FieldReadResult{}, err
|
|
||||||
}
|
|
||||||
vNew = v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result[k] = vNew
|
err = mapValuesToPrimitive(result, schema)
|
||||||
|
if err != nil {
|
||||||
|
return FieldReadResult{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultVal interface{}
|
var resultVal interface{}
|
||||||
|
|
|
@ -420,6 +420,41 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
New: "baz",
|
New: "baz",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"mapInt.%": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "2",
|
||||||
|
},
|
||||||
|
"mapInt.one": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "1",
|
||||||
|
},
|
||||||
|
"mapInt.two": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "2",
|
||||||
|
},
|
||||||
|
|
||||||
|
"mapFloat.%": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "1",
|
||||||
|
},
|
||||||
|
"mapFloat.oneDotTwo": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "1.2",
|
||||||
|
},
|
||||||
|
|
||||||
|
"mapBool.%": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "2",
|
||||||
|
},
|
||||||
|
"mapBool.True": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "true",
|
||||||
|
},
|
||||||
|
"mapBool.False": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "false",
|
||||||
|
},
|
||||||
|
|
||||||
"set.#": &terraform.ResourceAttrDiff{
|
"set.#": &terraform.ResourceAttrDiff{
|
||||||
Old: "0",
|
Old: "0",
|
||||||
New: "2",
|
New: "2",
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (r *MapFieldReader) ReadField(address []string) (FieldReadResult, error) {
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return readListField(r, address, schema)
|
return readListField(r, address, schema)
|
||||||
case TypeMap:
|
case TypeMap:
|
||||||
return r.readMap(k)
|
return r.readMap(k, schema)
|
||||||
case TypeSet:
|
case TypeSet:
|
||||||
return r.readSet(address, schema)
|
return r.readSet(address, schema)
|
||||||
case typeObject:
|
case typeObject:
|
||||||
|
@ -36,7 +36,7 @@ func (r *MapFieldReader) ReadField(address []string) (FieldReadResult, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *MapFieldReader) readMap(k string) (FieldReadResult, error) {
|
func (r *MapFieldReader) readMap(k string, schema *Schema) (FieldReadResult, error) {
|
||||||
result := make(map[string]interface{})
|
result := make(map[string]interface{})
|
||||||
resultSet := false
|
resultSet := false
|
||||||
|
|
||||||
|
@ -61,6 +61,11 @@ func (r *MapFieldReader) readMap(k string) (FieldReadResult, error) {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
err := mapValuesToPrimitive(result, schema)
|
||||||
|
if err != nil {
|
||||||
|
return FieldReadResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
var resultVal interface{}
|
var resultVal interface{}
|
||||||
if resultSet {
|
if resultSet {
|
||||||
resultVal = result
|
resultVal = result
|
||||||
|
|
|
@ -41,6 +41,17 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
"setDeep.10.value": "foo",
|
"setDeep.10.value": "foo",
|
||||||
"setDeep.50.index": "50",
|
"setDeep.50.index": "50",
|
||||||
"setDeep.50.value": "bar",
|
"setDeep.50.value": "bar",
|
||||||
|
|
||||||
|
"mapInt.%": "2",
|
||||||
|
"mapInt.one": "1",
|
||||||
|
"mapInt.two": "2",
|
||||||
|
|
||||||
|
"mapFloat.%": "1",
|
||||||
|
"mapFloat.oneDotTwo": "1.2",
|
||||||
|
|
||||||
|
"mapBool.%": "2",
|
||||||
|
"mapBool.True": "true",
|
||||||
|
"mapBool.False": "false",
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -211,6 +211,18 @@ func testFieldReader(t *testing.T, f func(map[string]*Schema) FieldReader) {
|
||||||
|
|
||||||
// Maps
|
// Maps
|
||||||
"map": &Schema{Type: TypeMap},
|
"map": &Schema{Type: TypeMap},
|
||||||
|
"mapInt": &Schema{
|
||||||
|
Type: TypeMap,
|
||||||
|
Elem: TypeInt,
|
||||||
|
},
|
||||||
|
"mapFloat": &Schema{
|
||||||
|
Type: TypeMap,
|
||||||
|
Elem: TypeFloat,
|
||||||
|
},
|
||||||
|
"mapBool": &Schema{
|
||||||
|
Type: TypeMap,
|
||||||
|
Elem: TypeBool,
|
||||||
|
},
|
||||||
|
|
||||||
// Sets
|
// Sets
|
||||||
"set": &Schema{
|
"set": &Schema{
|
||||||
|
@ -335,6 +347,44 @@ func testFieldReader(t *testing.T, f func(map[string]*Schema) FieldReader) {
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"mapInt": {
|
||||||
|
[]string{"mapInt"},
|
||||||
|
FieldReadResult{
|
||||||
|
Value: map[string]interface{}{
|
||||||
|
"one": 1,
|
||||||
|
"two": 2,
|
||||||
|
},
|
||||||
|
Exists: true,
|
||||||
|
Computed: false,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"mapFloat": {
|
||||||
|
[]string{"mapFloat"},
|
||||||
|
FieldReadResult{
|
||||||
|
Value: map[string]interface{}{
|
||||||
|
"oneDotTwo": 1.2,
|
||||||
|
},
|
||||||
|
Exists: true,
|
||||||
|
Computed: false,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"mapBool": {
|
||||||
|
[]string{"mapBool"},
|
||||||
|
FieldReadResult{
|
||||||
|
Value: map[string]interface{}{
|
||||||
|
"True": true,
|
||||||
|
"False": false,
|
||||||
|
},
|
||||||
|
Exists: true,
|
||||||
|
Computed: false,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
"mapelem": {
|
"mapelem": {
|
||||||
[]string{"map", "foo"},
|
[]string{"map", "foo"},
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
|
|
Loading…
Reference in New Issue