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,
|
// similar to the result of decoding an empty configuration block,
|
||||||
// which simplifies our handling of the top-level attributes/blocks
|
// which simplifies our handling of the top-level attributes/blocks
|
||||||
// below by giving us one non-null level of object to pull values from.
|
// 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)
|
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 {
|
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))
|
newAttrs := make(map[string]cty.Value, len(attrs))
|
||||||
for name, attr := range 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)
|
configV := config.GetAttr(name)
|
||||||
var newV cty.Value
|
var newV cty.Value
|
||||||
switch {
|
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 {
|
for name, test := range tests {
|
||||||
|
|
Loading…
Reference in New Issue