Merge pull request #29701 from hashicorp/jbardin/proposed-new-null-objs
objchange: fix ProposedNew from null objects
This commit is contained in:
commit
aece887a85
|
@ -1,33 +0,0 @@
|
|||
package objchange
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/internal/configs/configschema"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// AllBlockAttributesNull constructs a non-null cty.Value of the object type implied
|
||||
// by the given schema that has all of its leaf attributes set to null and all
|
||||
// of its nested block collections set to zero-length.
|
||||
//
|
||||
// This simulates what would result from decoding an empty configuration block
|
||||
// with the given schema, except that it does not produce errors
|
||||
func AllBlockAttributesNull(schema *configschema.Block) cty.Value {
|
||||
// "All attributes null" happens to be the definition of EmptyValue for
|
||||
// a Block, so we can just delegate to that.
|
||||
return schema.EmptyValue()
|
||||
}
|
||||
|
||||
// AllAttributesNull returns a cty.Value of the object type implied by the given
|
||||
// attriubutes that has all of its leaf attributes set to null.
|
||||
func AllAttributesNull(attrs map[string]*configschema.Attribute) cty.Value {
|
||||
newAttrs := make(map[string]cty.Value, len(attrs))
|
||||
|
||||
for name, attr := range attrs {
|
||||
if attr.NestedType != nil {
|
||||
newAttrs[name] = AllAttributesNull(attr.NestedType.Attributes)
|
||||
} else {
|
||||
newAttrs[name] = cty.NullVal(attr.Type)
|
||||
}
|
||||
}
|
||||
return cty.ObjectVal(newAttrs)
|
||||
}
|
|
@ -37,7 +37,10 @@ func ProposedNew(schema *configschema.Block, prior, config cty.Value) cty.Value
|
|||
// similar to the result of decoding an empty configuration block,
|
||||
// which simplifies our handling of the top-level attributes/blocks
|
||||
// below by giving us one non-null level of object to pull values from.
|
||||
prior = AllBlockAttributesNull(schema)
|
||||
//
|
||||
// "All attributes null" happens to be the definition of EmptyValue for
|
||||
// a Block, so we can just delegate to that
|
||||
prior = schema.EmptyValue()
|
||||
}
|
||||
return proposedNew(schema, prior, config)
|
||||
}
|
||||
|
@ -258,12 +261,15 @@ func proposedNewNestedBlock(schema *configschema.NestedBlock, prior, config cty.
|
|||
}
|
||||
|
||||
func proposedNewAttributes(attrs map[string]*configschema.Attribute, prior, config cty.Value) map[string]cty.Value {
|
||||
if prior.IsNull() {
|
||||
prior = AllAttributesNull(attrs)
|
||||
}
|
||||
newAttrs := make(map[string]cty.Value, len(attrs))
|
||||
for name, attr := range attrs {
|
||||
priorV := prior.GetAttr(name)
|
||||
var priorV cty.Value
|
||||
if prior.IsNull() {
|
||||
priorV = cty.NullVal(prior.Type().AttributeType(name))
|
||||
} else {
|
||||
priorV = prior.GetAttr(name)
|
||||
}
|
||||
|
||||
configV := config.GetAttr(name)
|
||||
var newV cty.Value
|
||||
switch {
|
||||
|
|
|
@ -1536,6 +1536,158 @@ func TestProposedNew(t *testing.T) {
|
|||
}),
|
||||
}),
|
||||
},
|
||||
"prior null nested objects": {
|
||||
&configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"single": {
|
||||
NestedType: &configschema.Object{
|
||||
Nesting: configschema.NestingSingle,
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"list": {
|
||||
NestedType: &configschema.Object{
|
||||
Nesting: configschema.NestingList,
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"foo": {
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
"map": {
|
||||
NestedType: &configschema.Object{
|
||||
Nesting: configschema.NestingMap,
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"map": {
|
||||
NestedType: &configschema.Object{
|
||||
Nesting: configschema.NestingList,
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"foo": {
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
cty.NullVal(cty.Object(map[string]cty.Type{
|
||||
"single": cty.Object(map[string]cty.Type{
|
||||
"list": cty.List(cty.Object(map[string]cty.Type{
|
||||
"foo": cty.String,
|
||||
})),
|
||||
}),
|
||||
"map": cty.Map(cty.Object(map[string]cty.Type{
|
||||
"list": cty.List(cty.Object(map[string]cty.Type{
|
||||
"foo": cty.String,
|
||||
})),
|
||||
})),
|
||||
})),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"single": cty.ObjectVal(map[string]cty.Value{
|
||||
"list": cty.ListVal([]cty.Value{
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("a"),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("b"),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
"map": cty.MapVal(map[string]cty.Value{
|
||||
"one": cty.ObjectVal(map[string]cty.Value{
|
||||
"list": cty.ListVal([]cty.Value{
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("a"),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("b"),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"single": cty.ObjectVal(map[string]cty.Value{
|
||||
"list": cty.ListVal([]cty.Value{
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("a"),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("b"),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
"map": cty.MapVal(map[string]cty.Value{
|
||||
"one": cty.ObjectVal(map[string]cty.Value{
|
||||
"list": cty.ListVal([]cty.Value{
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("a"),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("b"),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
},
|
||||
|
||||
// data sources are planned with an unknown value
|
||||
"unknown prior nested objects": {
|
||||
&configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"list": {
|
||||
NestedType: &configschema.Object{
|
||||
Nesting: configschema.NestingList,
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"list": {
|
||||
NestedType: &configschema.Object{
|
||||
Nesting: configschema.NestingList,
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"foo": {
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
},
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
cty.UnknownVal(cty.Object(map[string]cty.Type{
|
||||
"List": cty.List(cty.Object(map[string]cty.Type{
|
||||
"list": cty.List(cty.Object(map[string]cty.Type{
|
||||
"foo": cty.String,
|
||||
})),
|
||||
})),
|
||||
})),
|
||||
cty.NullVal(cty.Object(map[string]cty.Type{
|
||||
"List": cty.List(cty.Object(map[string]cty.Type{
|
||||
"list": cty.List(cty.Object(map[string]cty.Type{
|
||||
"foo": cty.String,
|
||||
})),
|
||||
})),
|
||||
})),
|
||||
cty.UnknownVal(cty.Object(map[string]cty.Type{
|
||||
"List": cty.List(cty.Object(map[string]cty.Type{
|
||||
"list": cty.List(cty.Object(map[string]cty.Type{
|
||||
"foo": cty.String,
|
||||
})),
|
||||
})),
|
||||
})),
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
|
|
Loading…
Reference in New Issue