objects vs maps in nested object types

When using NestedMap objects, unify the codepath for both maps and
objects as they may be interchangeable.
This commit is contained in:
James Bardin 2021-08-30 13:53:49 -04:00
parent 7ca6be8285
commit 903797084a
2 changed files with 37 additions and 62 deletions

View File

@ -368,71 +368,46 @@ func assertPlannedObjectValid(schema *configschema.Object, prior, config, planne
case configschema.NestingMap: case configschema.NestingMap:
// A NestingMap might either be a map or an object, depending on // A NestingMap might either be a map or an object, depending on
// whether there are dynamically-typed attributes inside, but // whether there are dynamically-typed attributes inside, so we will
// that's decided statically and so all values will have the same // break these down to maps to handle them both in the same manner.
// kind. plannedVals := map[string]cty.Value{}
if planned.Type().IsObjectType() { configVals := map[string]cty.Value{}
plannedAtys := planned.Type().AttributeTypes() priorVals := map[string]cty.Value{}
configAtys := config.Type().AttributeTypes()
for k := range plannedAtys {
if _, ok := configAtys[k]; !ok {
errs = append(errs, path.NewErrorf("block key %q from plan is not present in config", k))
continue
}
path := append(path, cty.GetAttrStep{Name: k})
plannedEV := planned.GetAttr(k) if !planned.IsNull() {
if !plannedEV.IsKnown() { plannedVals = planned.AsValueMap()
errs = append(errs, path.NewErrorf("element representing nested block must not be unknown itself; set nested attribute values to unknown instead")) }
continue if !config.IsNull() {
} configVals = config.AsValueMap()
configEV := config.GetAttr(k) }
priorEV := cty.NullVal(schema.ImpliedType()) if !prior.IsNull() {
if !prior.IsNull() && prior.Type().HasAttribute(k) { priorVals = prior.AsValueMap()
priorEV = prior.GetAttr(k) }
}
moreErrs := assertPlannedAttrsValid(schema.Attributes, priorEV, configEV, plannedEV, path) for k, plannedEV := range plannedVals {
errs = append(errs, moreErrs...) configEV, ok := configVals[k]
if !ok {
errs = append(errs, path.NewErrorf("block key %q from plan is not present in config", k))
continue
} }
for k := range configAtys { path := append(path, cty.GetAttrStep{Name: k})
if _, ok := plannedAtys[k]; !ok {
errs = append(errs, path.NewErrorf("block key %q from config is not present in plan", k)) if !plannedEV.IsKnown() {
continue errs = append(errs, path.NewErrorf("element representing nested block must not be unknown itself; set nested attribute values to unknown instead"))
} continue
} }
} else {
plannedL := planned.LengthInt() priorEV, ok := priorVals[k]
configL := config.LengthInt() if !ok {
if plannedL != configL { priorEV = cty.NullVal(schema.ImpliedType())
errs = append(errs, path.NewErrorf("block count in plan (%d) disagrees with count in config (%d)", plannedL, configL))
return errs
} }
for it := planned.ElementIterator(); it.Next(); { moreErrs := assertPlannedAttrsValid(schema.Attributes, priorEV, configEV, plannedEV, path)
idx, plannedEV := it.Element() errs = append(errs, moreErrs...)
path := append(path, cty.IndexStep{Key: idx}) }
if !plannedEV.IsKnown() { for k := range configVals {
errs = append(errs, path.NewErrorf("element representing nested block must not be unknown itself; set nested attribute values to unknown instead")) if _, ok := plannedVals[k]; !ok {
continue errs = append(errs, path.NewErrorf("block key %q from config is not present in plan", k))
} continue
k := idx.AsString()
if !config.HasIndex(idx).True() {
errs = append(errs, path.NewErrorf("block key %q from plan is not present in config", k))
continue
}
configEV := config.Index(idx)
priorEV := cty.NullVal(schema.ImpliedType())
if !prior.IsNull() && prior.HasIndex(idx).True() {
priorEV = prior.Index(idx)
}
moreErrs := assertPlannedAttrsValid(schema.Attributes, priorEV, configEV, plannedEV, path)
errs = append(errs, moreErrs...)
}
for it := config.ElementIterator(); it.Next(); {
idx, _ := it.Element()
if !planned.HasIndex(idx).True() {
errs = append(errs, path.NewErrorf("block key %q from config is not present in plan", idx.AsString()))
continue
}
} }
} }

View File

@ -1307,7 +1307,7 @@ func TestAssertPlanValid(t *testing.T) {
"name": cty.NullVal(cty.String), "name": cty.NullVal(cty.String),
}), }),
}), }),
"map_as_obj": cty.ObjectVal(map[string]cty.Value{ "map_as_obj": cty.MapVal(map[string]cty.Value{
"one": cty.ObjectVal(map[string]cty.Value{ "one": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.DynamicPseudoType), "name": cty.NullVal(cty.DynamicPseudoType),
}), }),