helper/schema: field readers no longer take a schema as arg
This commit is contained in:
parent
3ff859d734
commit
7e379cb1a1
|
@ -9,7 +9,7 @@ import (
|
||||||
// the proper typed representation. ResourceData uses this to query data
|
// the proper typed representation. ResourceData uses this to query data
|
||||||
// out of multiple sources: config, state, diffs, etc.
|
// out of multiple sources: config, state, diffs, etc.
|
||||||
type FieldReader interface {
|
type FieldReader interface {
|
||||||
ReadField([]string, *Schema) (FieldReadResult, error)
|
ReadField([]string) (FieldReadResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FieldReadResult encapsulates all the resulting data from reading
|
// FieldReadResult encapsulates all the resulting data from reading
|
||||||
|
@ -31,14 +31,92 @@ type FieldReadResult struct {
|
||||||
Computed bool
|
Computed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addrToSchema finds the final element schema for the given address
|
||||||
|
// and the given schema.
|
||||||
|
func addrToSchema(addr []string, schemaMap map[string]*Schema) *Schema {
|
||||||
|
var result *Schema
|
||||||
|
var lastType ValueType
|
||||||
|
current := &Schema{
|
||||||
|
Type: typeObject,
|
||||||
|
Elem: schemaMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(addr) > 0 {
|
||||||
|
k := addr[0]
|
||||||
|
addr = addr[1:]
|
||||||
|
|
||||||
|
REPEAT:
|
||||||
|
if len(addr) == 0 {
|
||||||
|
result = current
|
||||||
|
}
|
||||||
|
|
||||||
|
currentType := current.Type
|
||||||
|
switch current.Type {
|
||||||
|
case TypeBool:
|
||||||
|
fallthrough
|
||||||
|
case TypeInt:
|
||||||
|
fallthrough
|
||||||
|
case TypeString:
|
||||||
|
if len(addr) > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case TypeList:
|
||||||
|
fallthrough
|
||||||
|
case TypeSet:
|
||||||
|
switch v := current.Elem.(type) {
|
||||||
|
case *Resource:
|
||||||
|
current = &Schema{
|
||||||
|
Type: typeObject,
|
||||||
|
Elem: v.Schema,
|
||||||
|
}
|
||||||
|
case *Schema:
|
||||||
|
current = v
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addr) > 0 && addr[0] == "#" {
|
||||||
|
current = &Schema{Type: TypeInt}
|
||||||
|
}
|
||||||
|
case TypeMap:
|
||||||
|
if len(addr) > 0 {
|
||||||
|
current = &Schema{Type: TypeString}
|
||||||
|
}
|
||||||
|
case typeObject:
|
||||||
|
if lastType == TypeSet || lastType == TypeList {
|
||||||
|
// We just ignore sets/lists since they don't access
|
||||||
|
// objects the same way.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
m := current.Elem.(map[string]*Schema)
|
||||||
|
val, ok := m[k]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
current = val
|
||||||
|
goto REPEAT
|
||||||
|
}
|
||||||
|
|
||||||
|
lastType = currentType
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// readListField is a generic method for reading a list field out of a
|
// readListField is a generic method for reading a list field out of a
|
||||||
// a FieldReader. It does this based on the assumption that there is a key
|
// a FieldReader. It does this based on the assumption that there is a key
|
||||||
// "foo.#" for a list "foo" and that the indexes are "foo.0", "foo.1", etc.
|
// "foo.#" for a list "foo" and that the indexes are "foo.0", "foo.1", etc.
|
||||||
// after that point.
|
// after that point.
|
||||||
func readListField(
|
func readListField(
|
||||||
r FieldReader, k string, schema *Schema) (FieldReadResult, error) {
|
r FieldReader, addr []string, schema *Schema) (FieldReadResult, error) {
|
||||||
|
addrPadded := make([]string, len(addr)+1)
|
||||||
|
copy(addrPadded, addr)
|
||||||
|
addrPadded[len(addrPadded)-1] = "#"
|
||||||
|
|
||||||
// Get the number of elements in the list
|
// Get the number of elements in the list
|
||||||
countResult, err := r.ReadField([]string{k + ".#"}, &Schema{Type: TypeInt})
|
countResult, err := r.ReadField(addrPadded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, err
|
return FieldReadResult{}, err
|
||||||
}
|
}
|
||||||
|
@ -56,23 +134,12 @@ func readListField(
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the schema for the elements
|
|
||||||
var elemSchema *Schema
|
|
||||||
switch t := schema.Elem.(type) {
|
|
||||||
case *Resource:
|
|
||||||
elemSchema = &Schema{
|
|
||||||
Type: typeObject,
|
|
||||||
Elem: t.Schema,
|
|
||||||
}
|
|
||||||
case *Schema:
|
|
||||||
elemSchema = t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through each count, and get the item value out of it
|
// Go through each count, and get the item value out of it
|
||||||
result := make([]interface{}, countResult.Value.(int))
|
result := make([]interface{}, countResult.Value.(int))
|
||||||
for i, _ := range result {
|
for i, _ := range result {
|
||||||
is := strconv.FormatInt(int64(i), 10)
|
is := strconv.FormatInt(int64(i), 10)
|
||||||
rawResult, err := r.ReadField([]string{k, is}, elemSchema)
|
addrPadded[len(addrPadded)-1] = is
|
||||||
|
rawResult, err := r.ReadField(addrPadded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, err
|
return FieldReadResult{}, err
|
||||||
}
|
}
|
||||||
|
@ -97,11 +164,14 @@ func readListField(
|
||||||
// will result in the proper field data.
|
// will result in the proper field data.
|
||||||
func readObjectField(
|
func readObjectField(
|
||||||
r FieldReader,
|
r FieldReader,
|
||||||
k string,
|
addr []string,
|
||||||
schema map[string]*Schema) (FieldReadResult, error) {
|
schema map[string]*Schema) (FieldReadResult, error) {
|
||||||
result := make(map[string]interface{})
|
result := make(map[string]interface{})
|
||||||
for field, schema := range schema {
|
for field, _ := range schema {
|
||||||
rawResult, err := r.ReadField([]string{k, field}, schema)
|
addrRead := make([]string, len(addr), len(addr)+1)
|
||||||
|
copy(addrRead, addr)
|
||||||
|
addrRead = append(addrRead, field)
|
||||||
|
rawResult, err := r.ReadField(addrRead)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, err
|
return FieldReadResult{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,15 @@ import (
|
||||||
// the best of its ability.
|
// the best of its ability.
|
||||||
type ConfigFieldReader struct {
|
type ConfigFieldReader struct {
|
||||||
Config *terraform.ResourceConfig
|
Config *terraform.ResourceConfig
|
||||||
|
Schema map[string]*Schema
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ConfigFieldReader) ReadField(
|
func (r *ConfigFieldReader) ReadField(address []string) (FieldReadResult, error) {
|
||||||
address []string, schema *Schema) (FieldReadResult, error) {
|
|
||||||
k := strings.Join(address, ".")
|
k := strings.Join(address, ".")
|
||||||
|
schema := addrToSchema(address, r.Schema)
|
||||||
|
if schema == nil {
|
||||||
|
return FieldReadResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeBool:
|
case TypeBool:
|
||||||
|
@ -26,13 +30,13 @@ func (r *ConfigFieldReader) ReadField(
|
||||||
case TypeString:
|
case TypeString:
|
||||||
return r.readPrimitive(k, schema)
|
return r.readPrimitive(k, schema)
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return readListField(r, k, schema)
|
return readListField(r, address, schema)
|
||||||
case TypeMap:
|
case TypeMap:
|
||||||
return r.readMap(k)
|
return r.readMap(k)
|
||||||
case TypeSet:
|
case TypeSet:
|
||||||
return r.readSet(k, schema)
|
return r.readSet(address, schema)
|
||||||
case typeObject:
|
case typeObject:
|
||||||
return readObjectField(r, k, schema.Elem.(map[string]*Schema))
|
return readObjectField(r, address, schema.Elem.(map[string]*Schema))
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
|
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
|
||||||
}
|
}
|
||||||
|
@ -96,8 +100,8 @@ func (r *ConfigFieldReader) readPrimitive(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ConfigFieldReader) readSet(
|
func (r *ConfigFieldReader) readSet(
|
||||||
k string, schema *Schema) (FieldReadResult, error) {
|
address []string, schema *Schema) (FieldReadResult, error) {
|
||||||
raw, err := readListField(r, k, schema)
|
raw, err := readListField(r, address, schema)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, err
|
return FieldReadResult{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,40 @@ func TestConfigFieldReader_impl(t *testing.T) {
|
||||||
|
|
||||||
func TestConfigFieldReader(t *testing.T) {
|
func TestConfigFieldReader(t *testing.T) {
|
||||||
r := &ConfigFieldReader{
|
r := &ConfigFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"bool": &Schema{Type: TypeBool},
|
||||||
|
"int": &Schema{Type: TypeInt},
|
||||||
|
"string": &Schema{Type: TypeString},
|
||||||
|
"list": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Elem: &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
"listInt": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
},
|
||||||
|
"map": &Schema{Type: TypeMap},
|
||||||
|
"set": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
Set: func(a interface{}) int {
|
||||||
|
return a.(int)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"setDeep": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Elem: &Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"index": &Schema{Type: TypeInt},
|
||||||
|
"value": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: func(a interface{}) int {
|
||||||
|
return a.(map[string]interface{})["index"].(int)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
Config: testConfig(t, map[string]interface{}{
|
Config: testConfig(t, map[string]interface{}{
|
||||||
"bool": true,
|
"bool": true,
|
||||||
"int": 42,
|
"int": 42,
|
||||||
|
@ -45,7 +79,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
|
|
||||||
cases := map[string]struct {
|
cases := map[string]struct {
|
||||||
Addr []string
|
Addr []string
|
||||||
Schema *Schema
|
|
||||||
Out interface{}
|
Out interface{}
|
||||||
OutOk bool
|
OutOk bool
|
||||||
OutComputed bool
|
OutComputed bool
|
||||||
|
@ -53,7 +86,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
"noexist": {
|
"noexist": {
|
||||||
[]string{"boolNOPE"},
|
[]string{"boolNOPE"},
|
||||||
&Schema{Type: TypeBool},
|
|
||||||
nil,
|
nil,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
@ -62,7 +94,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"bool": {
|
"bool": {
|
||||||
[]string{"bool"},
|
[]string{"bool"},
|
||||||
&Schema{Type: TypeBool},
|
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -71,7 +102,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"int": {
|
"int": {
|
||||||
[]string{"int"},
|
[]string{"int"},
|
||||||
&Schema{Type: TypeInt},
|
|
||||||
42,
|
42,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -80,7 +110,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"string": {
|
"string": {
|
||||||
[]string{"string"},
|
[]string{"string"},
|
||||||
&Schema{Type: TypeString},
|
|
||||||
"string",
|
"string",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -89,10 +118,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"list": {
|
"list": {
|
||||||
[]string{"list"},
|
[]string{"list"},
|
||||||
&Schema{
|
|
||||||
Type: TypeList,
|
|
||||||
Elem: &Schema{Type: TypeString},
|
|
||||||
},
|
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
"foo",
|
"foo",
|
||||||
"bar",
|
"bar",
|
||||||
|
@ -104,10 +129,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"listInt": {
|
"listInt": {
|
||||||
[]string{"listInt"},
|
[]string{"listInt"},
|
||||||
&Schema{
|
|
||||||
Type: TypeList,
|
|
||||||
Elem: &Schema{Type: TypeInt},
|
|
||||||
},
|
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
21,
|
21,
|
||||||
42,
|
42,
|
||||||
|
@ -119,7 +140,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"map": {
|
"map": {
|
||||||
[]string{"map"},
|
[]string{"map"},
|
||||||
&Schema{Type: TypeMap},
|
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"bar": "baz",
|
"bar": "baz",
|
||||||
|
@ -131,7 +151,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"mapelem": {
|
"mapelem": {
|
||||||
[]string{"map", "foo"},
|
[]string{"map", "foo"},
|
||||||
&Schema{Type: TypeString},
|
|
||||||
"bar",
|
"bar",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -140,13 +159,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"set": {
|
"set": {
|
||||||
[]string{"set"},
|
[]string{"set"},
|
||||||
&Schema{
|
|
||||||
Type: TypeSet,
|
|
||||||
Elem: &Schema{Type: TypeInt},
|
|
||||||
Set: func(a interface{}) int {
|
|
||||||
return a.(int)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[]interface{}{10, 50},
|
[]interface{}{10, 50},
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -155,18 +167,6 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"setDeep": {
|
"setDeep": {
|
||||||
[]string{"setDeep"},
|
[]string{"setDeep"},
|
||||||
&Schema{
|
|
||||||
Type: TypeSet,
|
|
||||||
Elem: &Resource{
|
|
||||||
Schema: map[string]*Schema{
|
|
||||||
"index": &Schema{Type: TypeInt},
|
|
||||||
"value": &Schema{Type: TypeString},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Set: func(a interface{}) int {
|
|
||||||
return a.(map[string]interface{})["index"].(int)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"index": 10,
|
"index": 10,
|
||||||
|
@ -184,7 +184,7 @@ func TestConfigFieldReader(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, tc := range cases {
|
for name, tc := range cases {
|
||||||
out, err := r.ReadField(tc.Addr, tc.Schema)
|
out, err := r.ReadField(tc.Addr)
|
||||||
if (err != nil) != tc.OutErr {
|
if (err != nil) != tc.OutErr {
|
||||||
t.Fatalf("%s: err: %s", name, err)
|
t.Fatalf("%s: err: %s", name, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,11 +28,14 @@ import (
|
||||||
type DiffFieldReader struct {
|
type DiffFieldReader struct {
|
||||||
Diff *terraform.InstanceDiff
|
Diff *terraform.InstanceDiff
|
||||||
Source FieldReader
|
Source FieldReader
|
||||||
|
Schema map[string]*Schema
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DiffFieldReader) ReadField(
|
func (r *DiffFieldReader) ReadField(address []string) (FieldReadResult, error) {
|
||||||
address []string, schema *Schema) (FieldReadResult, error) {
|
schema := addrToSchema(address, r.Schema)
|
||||||
k := strings.Join(address, ".")
|
if schema == nil {
|
||||||
|
return FieldReadResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeBool:
|
case TypeBool:
|
||||||
|
@ -40,27 +43,27 @@ func (r *DiffFieldReader) ReadField(
|
||||||
case TypeInt:
|
case TypeInt:
|
||||||
fallthrough
|
fallthrough
|
||||||
case TypeString:
|
case TypeString:
|
||||||
return r.readPrimitive(k, schema)
|
return r.readPrimitive(address, schema)
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return readListField(r, k, schema)
|
return readListField(r, address, schema)
|
||||||
case TypeMap:
|
case TypeMap:
|
||||||
return r.readMap(k, schema)
|
return r.readMap(address, schema)
|
||||||
case TypeSet:
|
case TypeSet:
|
||||||
return r.readSet(k, schema)
|
return r.readSet(address, schema)
|
||||||
case typeObject:
|
case typeObject:
|
||||||
return readObjectField(r, k, schema.Elem.(map[string]*Schema))
|
return readObjectField(r, address, schema.Elem.(map[string]*Schema))
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
|
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DiffFieldReader) readMap(
|
func (r *DiffFieldReader) readMap(
|
||||||
k string, schema *Schema) (FieldReadResult, error) {
|
address []string, schema *Schema) (FieldReadResult, error) {
|
||||||
result := make(map[string]interface{})
|
result := make(map[string]interface{})
|
||||||
resultSet := false
|
resultSet := false
|
||||||
|
|
||||||
// First read the map from the underlying source
|
// First read the map from the underlying source
|
||||||
source, err := r.Source.ReadField([]string{k}, schema)
|
source, err := r.Source.ReadField(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, err
|
return FieldReadResult{}, err
|
||||||
}
|
}
|
||||||
|
@ -71,7 +74,7 @@ func (r *DiffFieldReader) readMap(
|
||||||
|
|
||||||
// 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 := k + "."
|
prefix := strings.Join(address, ".") + "."
|
||||||
for k, v := range r.Diff.Attributes {
|
for k, v := range r.Diff.Attributes {
|
||||||
if !strings.HasPrefix(k, prefix) {
|
if !strings.HasPrefix(k, prefix) {
|
||||||
continue
|
continue
|
||||||
|
@ -99,13 +102,13 @@ func (r *DiffFieldReader) readMap(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DiffFieldReader) readPrimitive(
|
func (r *DiffFieldReader) readPrimitive(
|
||||||
k string, schema *Schema) (FieldReadResult, error) {
|
address []string, schema *Schema) (FieldReadResult, error) {
|
||||||
result, err := r.Source.ReadField([]string{k}, schema)
|
result, err := r.Source.ReadField(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, err
|
return FieldReadResult{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
attrD, ok := r.Diff.Attributes[k]
|
attrD, ok := r.Diff.Attributes[strings.Join(address, ".")]
|
||||||
if !ok {
|
if !ok {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
@ -131,24 +134,12 @@ func (r *DiffFieldReader) readPrimitive(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DiffFieldReader) readSet(
|
func (r *DiffFieldReader) readSet(
|
||||||
k string, schema *Schema) (FieldReadResult, error) {
|
address []string, schema *Schema) (FieldReadResult, error) {
|
||||||
// Create the set that will be our result
|
// Create the set that will be our result
|
||||||
set := &Set{F: schema.Set}
|
set := &Set{F: schema.Set}
|
||||||
|
|
||||||
// Get the schema for the elements
|
|
||||||
var elemSchema *Schema
|
|
||||||
switch t := schema.Elem.(type) {
|
|
||||||
case *Resource:
|
|
||||||
elemSchema = &Schema{
|
|
||||||
Type: typeObject,
|
|
||||||
Elem: t.Schema,
|
|
||||||
}
|
|
||||||
case *Schema:
|
|
||||||
elemSchema = t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through the map and find all the set items
|
// Go through the map and find all the set items
|
||||||
prefix := k + "."
|
prefix := strings.Join(address, ".") + "."
|
||||||
for k, _ := range r.Diff.Attributes {
|
for k, _ := range r.Diff.Attributes {
|
||||||
if !strings.HasPrefix(k, prefix) {
|
if !strings.HasPrefix(k, prefix) {
|
||||||
continue
|
continue
|
||||||
|
@ -162,7 +153,7 @@ func (r *DiffFieldReader) readSet(
|
||||||
parts := strings.Split(k[len(prefix):], ".")
|
parts := strings.Split(k[len(prefix):], ".")
|
||||||
idx := parts[0]
|
idx := parts[0]
|
||||||
|
|
||||||
raw, err := r.ReadField([]string{prefix + idx}, elemSchema)
|
raw, err := r.ReadField(append(address, idx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, err
|
return FieldReadResult{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,71 @@ func TestDiffFieldReader_impl(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDiffFieldReader(t *testing.T) {
|
func TestDiffFieldReader(t *testing.T) {
|
||||||
|
schema := map[string]*Schema{
|
||||||
|
"bool": &Schema{Type: TypeBool},
|
||||||
|
"int": &Schema{Type: TypeInt},
|
||||||
|
"string": &Schema{Type: TypeString},
|
||||||
|
"stringComputed": &Schema{Type: TypeString},
|
||||||
|
"list": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Elem: &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
"listInt": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
},
|
||||||
|
"listMap": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Elem: &Schema{
|
||||||
|
Type: TypeMap,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"map": &Schema{Type: TypeMap},
|
||||||
|
"mapRemove": &Schema{Type: TypeMap},
|
||||||
|
"set": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
Set: func(a interface{}) int {
|
||||||
|
return a.(int)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"setChange": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"index": &Schema{
|
||||||
|
Type: TypeInt,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"value": &Schema{
|
||||||
|
Type: TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: func(a interface{}) int {
|
||||||
|
m := a.(map[string]interface{})
|
||||||
|
return m["index"].(int)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"setDeep": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Elem: &Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"index": &Schema{Type: TypeInt},
|
||||||
|
"value": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: func(a interface{}) int {
|
||||||
|
return a.(map[string]interface{})["index"].(int)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
r := &DiffFieldReader{
|
r := &DiffFieldReader{
|
||||||
|
Schema: schema,
|
||||||
Diff: &terraform.InstanceDiff{
|
Diff: &terraform.InstanceDiff{
|
||||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||||
"bool": &terraform.ResourceAttrDiff{
|
"bool": &terraform.ResourceAttrDiff{
|
||||||
|
@ -132,6 +196,7 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
},
|
},
|
||||||
|
|
||||||
Source: &MapFieldReader{
|
Source: &MapFieldReader{
|
||||||
|
Schema: schema,
|
||||||
Map: map[string]string{
|
Map: map[string]string{
|
||||||
"listMap.#": "2",
|
"listMap.#": "2",
|
||||||
"listMap.0.foo": "bar",
|
"listMap.0.foo": "bar",
|
||||||
|
@ -150,13 +215,11 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
cases := map[string]struct {
|
cases := map[string]struct {
|
||||||
Addr []string
|
Addr []string
|
||||||
Schema *Schema
|
|
||||||
Result FieldReadResult
|
Result FieldReadResult
|
||||||
Err bool
|
Err bool
|
||||||
}{
|
}{
|
||||||
"noexist": {
|
"noexist": {
|
||||||
[]string{"boolNOPE"},
|
[]string{"boolNOPE"},
|
||||||
&Schema{Type: TypeBool},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: nil,
|
Value: nil,
|
||||||
Exists: false,
|
Exists: false,
|
||||||
|
@ -167,7 +230,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"bool": {
|
"bool": {
|
||||||
[]string{"bool"},
|
[]string{"bool"},
|
||||||
&Schema{Type: TypeBool},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: true,
|
Value: true,
|
||||||
Exists: true,
|
Exists: true,
|
||||||
|
@ -178,7 +240,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"int": {
|
"int": {
|
||||||
[]string{"int"},
|
[]string{"int"},
|
||||||
&Schema{Type: TypeInt},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: 42,
|
Value: 42,
|
||||||
Exists: true,
|
Exists: true,
|
||||||
|
@ -189,7 +250,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"string": {
|
"string": {
|
||||||
[]string{"string"},
|
[]string{"string"},
|
||||||
&Schema{Type: TypeString},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: "string",
|
Value: "string",
|
||||||
Exists: true,
|
Exists: true,
|
||||||
|
@ -200,7 +260,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"stringComputed": {
|
"stringComputed": {
|
||||||
[]string{"stringComputed"},
|
[]string{"stringComputed"},
|
||||||
&Schema{Type: TypeString},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: "",
|
Value: "",
|
||||||
Exists: true,
|
Exists: true,
|
||||||
|
@ -211,10 +270,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"list": {
|
"list": {
|
||||||
[]string{"list"},
|
[]string{"list"},
|
||||||
&Schema{
|
|
||||||
Type: TypeList,
|
|
||||||
Elem: &Schema{Type: TypeString},
|
|
||||||
},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: []interface{}{
|
Value: []interface{}{
|
||||||
"foo",
|
"foo",
|
||||||
|
@ -228,10 +283,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"listInt": {
|
"listInt": {
|
||||||
[]string{"listInt"},
|
[]string{"listInt"},
|
||||||
&Schema{
|
|
||||||
Type: TypeList,
|
|
||||||
Elem: &Schema{Type: TypeInt},
|
|
||||||
},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: []interface{}{
|
Value: []interface{}{
|
||||||
21,
|
21,
|
||||||
|
@ -245,7 +296,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"map": {
|
"map": {
|
||||||
[]string{"map"},
|
[]string{"map"},
|
||||||
&Schema{Type: TypeMap},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: map[string]interface{}{
|
Value: map[string]interface{}{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
|
@ -259,7 +309,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"mapelem": {
|
"mapelem": {
|
||||||
[]string{"map", "foo"},
|
[]string{"map", "foo"},
|
||||||
&Schema{Type: TypeString},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: "bar",
|
Value: "bar",
|
||||||
Exists: true,
|
Exists: true,
|
||||||
|
@ -270,7 +319,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"mapRemove": {
|
"mapRemove": {
|
||||||
[]string{"mapRemove"},
|
[]string{"mapRemove"},
|
||||||
&Schema{Type: TypeMap},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: map[string]interface{}{
|
Value: map[string]interface{}{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
|
@ -283,13 +331,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"set": {
|
"set": {
|
||||||
[]string{"set"},
|
[]string{"set"},
|
||||||
&Schema{
|
|
||||||
Type: TypeSet,
|
|
||||||
Elem: &Schema{Type: TypeInt},
|
|
||||||
Set: func(a interface{}) int {
|
|
||||||
return a.(int)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: []interface{}{10, 50},
|
Value: []interface{}{10, 50},
|
||||||
Exists: true,
|
Exists: true,
|
||||||
|
@ -300,18 +341,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"setDeep": {
|
"setDeep": {
|
||||||
[]string{"setDeep"},
|
[]string{"setDeep"},
|
||||||
&Schema{
|
|
||||||
Type: TypeSet,
|
|
||||||
Elem: &Resource{
|
|
||||||
Schema: map[string]*Schema{
|
|
||||||
"index": &Schema{Type: TypeInt},
|
|
||||||
"value": &Schema{Type: TypeString},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Set: func(a interface{}) int {
|
|
||||||
return a.(map[string]interface{})["index"].(int)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: []interface{}{
|
Value: []interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
@ -331,12 +360,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"listMapRemoval": {
|
"listMapRemoval": {
|
||||||
[]string{"listMap"},
|
[]string{"listMap"},
|
||||||
&Schema{
|
|
||||||
Type: TypeList,
|
|
||||||
Elem: &Schema{
|
|
||||||
Type: TypeMap,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: []interface{}{
|
Value: []interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
@ -353,27 +376,6 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"setChange": {
|
"setChange": {
|
||||||
[]string{"setChange"},
|
[]string{"setChange"},
|
||||||
&Schema{
|
|
||||||
Type: TypeSet,
|
|
||||||
Optional: true,
|
|
||||||
Elem: &Resource{
|
|
||||||
Schema: map[string]*Schema{
|
|
||||||
"index": &Schema{
|
|
||||||
Type: TypeInt,
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
"value": &Schema{
|
|
||||||
Type: TypeString,
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Set: func(a interface{}) int {
|
|
||||||
m := a.(map[string]interface{})
|
|
||||||
return m["index"].(int)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: []interface{}{
|
Value: []interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
@ -388,7 +390,7 @@ func TestDiffFieldReader(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, tc := range cases {
|
for name, tc := range cases {
|
||||||
out, err := r.ReadField(tc.Addr, tc.Schema)
|
out, err := r.ReadField(tc.Addr)
|
||||||
if (err != nil) != tc.Err {
|
if (err != nil) != tc.Err {
|
||||||
t.Fatalf("%s: err: %s", name, err)
|
t.Fatalf("%s: err: %s", name, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,16 @@ import (
|
||||||
// MapFieldReader reads fields out of an untyped map[string]string to
|
// MapFieldReader reads fields out of an untyped map[string]string to
|
||||||
// the best of its ability.
|
// the best of its ability.
|
||||||
type MapFieldReader struct {
|
type MapFieldReader struct {
|
||||||
Map map[string]string
|
Map map[string]string
|
||||||
|
Schema map[string]*Schema
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *MapFieldReader) ReadField(
|
func (r *MapFieldReader) ReadField(address []string) (FieldReadResult, error) {
|
||||||
address []string, schema *Schema) (FieldReadResult, error) {
|
|
||||||
k := strings.Join(address, ".")
|
k := strings.Join(address, ".")
|
||||||
|
schema := addrToSchema(address, r.Schema)
|
||||||
|
if schema == nil {
|
||||||
|
return FieldReadResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeBool:
|
case TypeBool:
|
||||||
|
@ -23,13 +27,13 @@ func (r *MapFieldReader) ReadField(
|
||||||
case TypeString:
|
case TypeString:
|
||||||
return r.readPrimitive(k, schema)
|
return r.readPrimitive(k, schema)
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return readListField(r, k, schema)
|
return readListField(r, address, schema)
|
||||||
case TypeMap:
|
case TypeMap:
|
||||||
return r.readMap(k)
|
return r.readMap(k)
|
||||||
case TypeSet:
|
case TypeSet:
|
||||||
return r.readSet(k, schema)
|
return r.readSet(k, schema)
|
||||||
case typeObject:
|
case typeObject:
|
||||||
return readObjectField(r, k, schema.Elem.(map[string]*Schema))
|
return readObjectField(r, address, schema.Elem.(map[string]*Schema))
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
|
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
|
||||||
}
|
}
|
||||||
|
@ -102,18 +106,6 @@ func (r *MapFieldReader) readSet(
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the schema for the elements
|
|
||||||
var elemSchema *Schema
|
|
||||||
switch t := schema.Elem.(type) {
|
|
||||||
case *Resource:
|
|
||||||
elemSchema = &Schema{
|
|
||||||
Type: typeObject,
|
|
||||||
Elem: t.Schema,
|
|
||||||
}
|
|
||||||
case *Schema:
|
|
||||||
elemSchema = t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through the map and find all the set items
|
// Go through the map and find all the set items
|
||||||
prefix := k + "."
|
prefix := k + "."
|
||||||
for k, _ := range r.Map {
|
for k, _ := range r.Map {
|
||||||
|
@ -129,7 +121,7 @@ func (r *MapFieldReader) readSet(
|
||||||
parts := strings.Split(k[len(prefix):], ".")
|
parts := strings.Split(k[len(prefix):], ".")
|
||||||
idx := parts[0]
|
idx := parts[0]
|
||||||
|
|
||||||
raw, err := r.ReadField([]string{prefix + idx}, elemSchema)
|
raw, err := r.ReadField([]string{prefix[:len(prefix)-1], idx})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, err
|
return FieldReadResult{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,40 @@ func TestMapFieldReader_impl(t *testing.T) {
|
||||||
|
|
||||||
func TestMapFieldReader(t *testing.T) {
|
func TestMapFieldReader(t *testing.T) {
|
||||||
r := &MapFieldReader{
|
r := &MapFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"bool": &Schema{Type: TypeBool},
|
||||||
|
"int": &Schema{Type: TypeInt},
|
||||||
|
"string": &Schema{Type: TypeString},
|
||||||
|
"list": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Elem: &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
"listInt": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
},
|
||||||
|
"map": &Schema{Type: TypeMap},
|
||||||
|
"set": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
Set: func(a interface{}) int {
|
||||||
|
return a.(int)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"setDeep": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Elem: &Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"index": &Schema{Type: TypeInt},
|
||||||
|
"value": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: func(a interface{}) int {
|
||||||
|
return a.(map[string]interface{})["index"].(int)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
Map: map[string]string{
|
Map: map[string]string{
|
||||||
"bool": "true",
|
"bool": "true",
|
||||||
"int": "42",
|
"int": "42",
|
||||||
|
@ -41,7 +75,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
|
|
||||||
cases := map[string]struct {
|
cases := map[string]struct {
|
||||||
Addr []string
|
Addr []string
|
||||||
Schema *Schema
|
|
||||||
Out interface{}
|
Out interface{}
|
||||||
OutOk bool
|
OutOk bool
|
||||||
OutComputed bool
|
OutComputed bool
|
||||||
|
@ -49,7 +82,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
"noexist": {
|
"noexist": {
|
||||||
[]string{"boolNOPE"},
|
[]string{"boolNOPE"},
|
||||||
&Schema{Type: TypeBool},
|
|
||||||
nil,
|
nil,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
@ -58,7 +90,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"bool": {
|
"bool": {
|
||||||
[]string{"bool"},
|
[]string{"bool"},
|
||||||
&Schema{Type: TypeBool},
|
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -67,7 +98,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"int": {
|
"int": {
|
||||||
[]string{"int"},
|
[]string{"int"},
|
||||||
&Schema{Type: TypeInt},
|
|
||||||
42,
|
42,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -76,7 +106,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"string": {
|
"string": {
|
||||||
[]string{"string"},
|
[]string{"string"},
|
||||||
&Schema{Type: TypeString},
|
|
||||||
"string",
|
"string",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -85,10 +114,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"list": {
|
"list": {
|
||||||
[]string{"list"},
|
[]string{"list"},
|
||||||
&Schema{
|
|
||||||
Type: TypeList,
|
|
||||||
Elem: &Schema{Type: TypeString},
|
|
||||||
},
|
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
"foo",
|
"foo",
|
||||||
"bar",
|
"bar",
|
||||||
|
@ -100,10 +125,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"listInt": {
|
"listInt": {
|
||||||
[]string{"listInt"},
|
[]string{"listInt"},
|
||||||
&Schema{
|
|
||||||
Type: TypeList,
|
|
||||||
Elem: &Schema{Type: TypeInt},
|
|
||||||
},
|
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
21,
|
21,
|
||||||
42,
|
42,
|
||||||
|
@ -115,7 +136,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"map": {
|
"map": {
|
||||||
[]string{"map"},
|
[]string{"map"},
|
||||||
&Schema{Type: TypeMap},
|
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"bar": "baz",
|
"bar": "baz",
|
||||||
|
@ -127,7 +147,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"mapelem": {
|
"mapelem": {
|
||||||
[]string{"map", "foo"},
|
[]string{"map", "foo"},
|
||||||
&Schema{Type: TypeString},
|
|
||||||
"bar",
|
"bar",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -136,13 +155,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"set": {
|
"set": {
|
||||||
[]string{"set"},
|
[]string{"set"},
|
||||||
&Schema{
|
|
||||||
Type: TypeSet,
|
|
||||||
Elem: &Schema{Type: TypeInt},
|
|
||||||
Set: func(a interface{}) int {
|
|
||||||
return a.(int)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[]interface{}{10, 50},
|
[]interface{}{10, 50},
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
@ -151,18 +163,6 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
|
|
||||||
"setDeep": {
|
"setDeep": {
|
||||||
[]string{"setDeep"},
|
[]string{"setDeep"},
|
||||||
&Schema{
|
|
||||||
Type: TypeSet,
|
|
||||||
Elem: &Resource{
|
|
||||||
Schema: map[string]*Schema{
|
|
||||||
"index": &Schema{Type: TypeInt},
|
|
||||||
"value": &Schema{Type: TypeString},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Set: func(a interface{}) int {
|
|
||||||
return a.(map[string]interface{})["index"].(int)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"index": 10,
|
"index": 10,
|
||||||
|
@ -180,7 +180,7 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, tc := range cases {
|
for name, tc := range cases {
|
||||||
out, err := r.ReadField(tc.Addr, tc.Schema)
|
out, err := r.ReadField(tc.Addr)
|
||||||
if (err != nil) != tc.OutErr {
|
if (err != nil) != tc.OutErr {
|
||||||
t.Fatalf("%s: err: %s", name, err)
|
t.Fatalf("%s: err: %s", name, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,20 +16,19 @@ type MultiLevelFieldReader struct {
|
||||||
Levels []string
|
Levels []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *MultiLevelFieldReader) ReadField(
|
func (r *MultiLevelFieldReader) ReadField(address []string) (FieldReadResult, error) {
|
||||||
address []string, schema *Schema) (FieldReadResult, error) {
|
return r.ReadFieldMerge(address, r.Levels[len(r.Levels)-1])
|
||||||
return r.ReadFieldMerge(address, schema, r.Levels[len(r.Levels)-1])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *MultiLevelFieldReader) ReadFieldExact(
|
func (r *MultiLevelFieldReader) ReadFieldExact(
|
||||||
address []string, schema *Schema, level string) (FieldReadResult, error) {
|
address []string, level string) (FieldReadResult, error) {
|
||||||
reader, ok := r.Readers[level]
|
reader, ok := r.Readers[level]
|
||||||
if !ok {
|
if !ok {
|
||||||
return FieldReadResult{}, fmt.Errorf(
|
return FieldReadResult{}, fmt.Errorf(
|
||||||
"Unknown reader level: %s", level)
|
"Unknown reader level: %s", level)
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := reader.ReadField(address, schema)
|
result, err := reader.ReadField(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, fmt.Errorf(
|
return FieldReadResult{}, fmt.Errorf(
|
||||||
"Error reading level %s: %s", level, err)
|
"Error reading level %s: %s", level, err)
|
||||||
|
@ -39,7 +38,7 @@ func (r *MultiLevelFieldReader) ReadFieldExact(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *MultiLevelFieldReader) ReadFieldMerge(
|
func (r *MultiLevelFieldReader) ReadFieldMerge(
|
||||||
address []string, schema *Schema, level string) (FieldReadResult, error) {
|
address []string, level string) (FieldReadResult, error) {
|
||||||
var result FieldReadResult
|
var result FieldReadResult
|
||||||
for _, l := range r.Levels {
|
for _, l := range r.Levels {
|
||||||
r, ok := r.Readers[l]
|
r, ok := r.Readers[l]
|
||||||
|
@ -47,7 +46,7 @@ func (r *MultiLevelFieldReader) ReadFieldMerge(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := r.ReadField(address, schema)
|
out, err := r.ReadField(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, fmt.Errorf(
|
return FieldReadResult{}, fmt.Errorf(
|
||||||
"Error reading level %s: %s", l, err)
|
"Error reading level %s: %s", l, err)
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
|
func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
|
||||||
cases := map[string]struct {
|
cases := map[string]struct {
|
||||||
Addr []string
|
Addr []string
|
||||||
Schema *Schema
|
|
||||||
Readers []FieldReader
|
Readers []FieldReader
|
||||||
Level string
|
Level string
|
||||||
Result FieldReadResult
|
Result FieldReadResult
|
||||||
|
@ -19,22 +18,27 @@ func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
|
||||||
"specific": {
|
"specific": {
|
||||||
Addr: []string{"foo"},
|
Addr: []string{"foo"},
|
||||||
|
|
||||||
Schema: &Schema{
|
|
||||||
Type: TypeString,
|
|
||||||
},
|
|
||||||
|
|
||||||
Readers: []FieldReader{
|
Readers: []FieldReader{
|
||||||
&MapFieldReader{
|
&MapFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"foo": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
Map: map[string]string{
|
Map: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&MapFieldReader{
|
&MapFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"foo": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
Map: map[string]string{
|
Map: map[string]string{
|
||||||
"foo": "baz",
|
"foo": "baz",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&MapFieldReader{
|
&MapFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"foo": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
Map: map[string]string{},
|
Map: map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -61,7 +65,7 @@ func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
|
||||||
Levels: levels,
|
Levels: levels,
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := r.ReadFieldExact(tc.Addr, tc.Schema, tc.Level)
|
out, err := r.ReadFieldExact(tc.Addr, tc.Level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: err: %s", name, err)
|
t.Fatalf("%s: err: %s", name, err)
|
||||||
}
|
}
|
||||||
|
@ -75,23 +79,22 @@ func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
|
||||||
func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
|
func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
|
||||||
cases := map[string]struct {
|
cases := map[string]struct {
|
||||||
Addr []string
|
Addr []string
|
||||||
Schema *Schema
|
|
||||||
Readers []FieldReader
|
Readers []FieldReader
|
||||||
Result FieldReadResult
|
Result FieldReadResult
|
||||||
}{
|
}{
|
||||||
"stringInDiff": {
|
"stringInDiff": {
|
||||||
Addr: []string{"availability_zone"},
|
Addr: []string{"availability_zone"},
|
||||||
|
|
||||||
Schema: &Schema{
|
|
||||||
Type: TypeString,
|
|
||||||
Optional: true,
|
|
||||||
Computed: true,
|
|
||||||
ForceNew: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
Readers: []FieldReader{
|
Readers: []FieldReader{
|
||||||
&DiffFieldReader{
|
&DiffFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"availability_zone": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
|
||||||
Source: &MapFieldReader{
|
Source: &MapFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"availability_zone": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
Map: map[string]string{
|
Map: map[string]string{
|
||||||
"availability_zone": "foo",
|
"availability_zone": "foo",
|
||||||
},
|
},
|
||||||
|
@ -118,22 +121,27 @@ func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
|
||||||
"lastLevelComputed": {
|
"lastLevelComputed": {
|
||||||
Addr: []string{"availability_zone"},
|
Addr: []string{"availability_zone"},
|
||||||
|
|
||||||
Schema: &Schema{
|
|
||||||
Type: TypeString,
|
|
||||||
Optional: true,
|
|
||||||
Computed: true,
|
|
||||||
ForceNew: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
Readers: []FieldReader{
|
Readers: []FieldReader{
|
||||||
&MapFieldReader{
|
&MapFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"availability_zone": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
|
||||||
Map: map[string]string{
|
Map: map[string]string{
|
||||||
"availability_zone": "foo",
|
"availability_zone": "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
&DiffFieldReader{
|
&DiffFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"availability_zone": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
|
||||||
Source: &MapFieldReader{
|
Source: &MapFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"availability_zone": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
|
||||||
Map: map[string]string{
|
Map: map[string]string{
|
||||||
"availability_zone": "foo",
|
"availability_zone": "foo",
|
||||||
},
|
},
|
||||||
|
@ -161,18 +169,23 @@ func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
|
||||||
"list of maps with removal in diff": {
|
"list of maps with removal in diff": {
|
||||||
Addr: []string{"config_vars"},
|
Addr: []string{"config_vars"},
|
||||||
|
|
||||||
Schema: &Schema{
|
|
||||||
Type: TypeList,
|
|
||||||
Optional: true,
|
|
||||||
Computed: true,
|
|
||||||
Elem: &Schema{
|
|
||||||
Type: TypeMap,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
Readers: []FieldReader{
|
Readers: []FieldReader{
|
||||||
&DiffFieldReader{
|
&DiffFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"config_vars": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Elem: &Schema{Type: TypeMap},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
Source: &MapFieldReader{
|
Source: &MapFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"config_vars": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Elem: &Schema{Type: TypeMap},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
Map: map[string]string{
|
Map: map[string]string{
|
||||||
"config_vars.#": "2",
|
"config_vars.#": "2",
|
||||||
"config_vars.0.foo": "bar",
|
"config_vars.0.foo": "bar",
|
||||||
|
@ -207,17 +220,19 @@ func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
|
||||||
"first level only": {
|
"first level only": {
|
||||||
Addr: []string{"foo"},
|
Addr: []string{"foo"},
|
||||||
|
|
||||||
Schema: &Schema{
|
|
||||||
Type: TypeString,
|
|
||||||
},
|
|
||||||
|
|
||||||
Readers: []FieldReader{
|
Readers: []FieldReader{
|
||||||
&MapFieldReader{
|
&MapFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"foo": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
Map: map[string]string{
|
Map: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&MapFieldReader{
|
&MapFieldReader{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"foo": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
Map: map[string]string{},
|
Map: map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -243,7 +258,7 @@ func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
|
||||||
Levels: levels,
|
Levels: levels,
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := r.ReadFieldMerge(tc.Addr, tc.Schema, levels[len(levels)-1])
|
out, err := r.ReadFieldMerge(tc.Addr, levels[len(levels)-1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: err: %s", name, err)
|
t.Fatalf("%s: err: %s", name, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddrToSchema(t *testing.T) {
|
||||||
|
cases := map[string]struct {
|
||||||
|
Addr []string
|
||||||
|
Schema map[string]*Schema
|
||||||
|
Result *Schema
|
||||||
|
}{
|
||||||
|
"mapElem": {
|
||||||
|
[]string{"map", "foo"},
|
||||||
|
map[string]*Schema{
|
||||||
|
"map": &Schema{Type: TypeMap},
|
||||||
|
},
|
||||||
|
&Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
|
||||||
|
"setDeep": {
|
||||||
|
[]string{"set", "50", "index"},
|
||||||
|
map[string]*Schema{
|
||||||
|
"set": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Elem: &Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"index": &Schema{Type: TypeInt},
|
||||||
|
"value": &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: func(a interface{}) int {
|
||||||
|
return a.(map[string]interface{})["index"].(int)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&Schema{Type: TypeInt},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range cases {
|
||||||
|
result := addrToSchema(tc.Addr, tc.Schema)
|
||||||
|
if !reflect.DeepEqual(result, tc.Result) {
|
||||||
|
t.Fatalf("%s: %#v", name, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue