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,73 +368,48 @@ 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 !planned.IsNull() {
if _, ok := configAtys[k]; !ok { plannedVals = planned.AsValueMap()
}
if !config.IsNull() {
configVals = config.AsValueMap()
}
if !prior.IsNull() {
priorVals = prior.AsValueMap()
}
for k, plannedEV := range plannedVals {
configEV, ok := configVals[k]
if !ok {
errs = append(errs, path.NewErrorf("block key %q from plan is not present in config", k)) errs = append(errs, path.NewErrorf("block key %q from plan is not present in config", k))
continue continue
} }
path := append(path, cty.GetAttrStep{Name: k}) path := append(path, cty.GetAttrStep{Name: k})
plannedEV := planned.GetAttr(k)
if !plannedEV.IsKnown() { if !plannedEV.IsKnown() {
errs = append(errs, path.NewErrorf("element representing nested block must not be unknown itself; set nested attribute values to unknown instead")) errs = append(errs, path.NewErrorf("element representing nested block must not be unknown itself; set nested attribute values to unknown instead"))
continue continue
} }
configEV := config.GetAttr(k)
priorEV := cty.NullVal(schema.ImpliedType()) priorEV, ok := priorVals[k]
if !prior.IsNull() && prior.Type().HasAttribute(k) { if !ok {
priorEV = prior.GetAttr(k) priorEV = cty.NullVal(schema.ImpliedType())
} }
moreErrs := assertPlannedAttrsValid(schema.Attributes, priorEV, configEV, plannedEV, path) moreErrs := assertPlannedAttrsValid(schema.Attributes, priorEV, configEV, plannedEV, path)
errs = append(errs, moreErrs...) errs = append(errs, moreErrs...)
} }
for k := range configAtys { for k := range configVals {
if _, ok := plannedAtys[k]; !ok { if _, ok := plannedVals[k]; !ok {
errs = append(errs, path.NewErrorf("block key %q from config is not present in plan", k)) errs = append(errs, path.NewErrorf("block key %q from config is not present in plan", k))
continue continue
} }
} }
} else {
plannedL := planned.LengthInt()
configL := config.LengthInt()
if plannedL != configL {
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(); {
idx, plannedEV := it.Element()
path := append(path, cty.IndexStep{Key: idx})
if !plannedEV.IsKnown() {
errs = append(errs, path.NewErrorf("element representing nested block must not be unknown itself; set nested attribute values to unknown instead"))
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
}
}
}
case configschema.NestingSet: case configschema.NestingSet:
// Because set elements have no identifier with which to correlate // Because set elements have no identifier with which to correlate

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),
}), }),