69 lines
2.3 KiB
Go
69 lines
2.3 KiB
Go
package objchange
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
// AllAttributesNull 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 AllAttributesNull(schema *configschema.Block) cty.Value {
|
|
vals := make(map[string]cty.Value)
|
|
ty := schema.ImpliedType()
|
|
|
|
for name := range schema.Attributes {
|
|
aty := ty.AttributeType(name)
|
|
vals[name] = cty.NullVal(aty)
|
|
}
|
|
|
|
for name, blockS := range schema.BlockTypes {
|
|
aty := ty.AttributeType(name)
|
|
|
|
switch blockS.Nesting {
|
|
case configschema.NestingSingle:
|
|
// NestingSingle behaves like an object attribute, which decodes
|
|
// as null when it's not present in configuration.
|
|
vals[name] = cty.NullVal(aty)
|
|
default:
|
|
// All other nesting types decode as "empty" when not present, but
|
|
// empty values take different forms depending on the type.
|
|
switch {
|
|
case aty.IsListType():
|
|
vals[name] = cty.ListValEmpty(aty.ElementType())
|
|
case aty.IsSetType():
|
|
vals[name] = cty.SetValEmpty(aty.ElementType())
|
|
case aty.IsMapType():
|
|
vals[name] = cty.MapValEmpty(aty.ElementType())
|
|
case aty.Equals(cty.DynamicPseudoType):
|
|
// We use DynamicPseudoType in situations where there's a
|
|
// nested attribute of DynamicPseudoType, since the schema
|
|
// system cannot predict the final type until it knows exactly
|
|
// how many elements there will be. However, since we're
|
|
// trying to behave as if there are _no_ elements, we know
|
|
// we're producing either an empty tuple or empty object
|
|
// and just need to distinguish these two cases.
|
|
switch blockS.Nesting {
|
|
case configschema.NestingList:
|
|
vals[name] = cty.EmptyTupleVal
|
|
case configschema.NestingMap:
|
|
vals[name] = cty.EmptyObjectVal
|
|
}
|
|
}
|
|
}
|
|
|
|
// By the time we get down here we should always have set a value.
|
|
// If not, that suggests a missing case in the above switches.
|
|
if _, ok := vals[name]; !ok {
|
|
panic(fmt.Sprintf("failed to create empty value for nested block %q", name))
|
|
}
|
|
}
|
|
|
|
return cty.ObjectVal(vals)
|
|
}
|