Skip to content

Consider Object Nested Attribute Default Implementation #777

@bflad

Description

@bflad

Module version

v1.3.1

Use-cases

When working with nested attributes, it may be desirable to automatically have an object default based on all the nested attribute default values for when the object is null. Today, this is a manual process to re-create the object default value based on the nested attribute defaults.

schema.SingleNestedAttribute{
  // ... other fields ...
  Attributes: map[string]schema.Attribute{
    "attribute_one": schema.StringAttribute{
      // ... other fields ...
      Default: stringdefault.StaticString("one"),
    }
    "attribute_two": schema.StringAttribute{
      // ... other fields ...
      Default: stringdefault.StaticString("two"),
    }
  },
  Default: objectdefault.StaticValue(
    map[string]attr.Type{
      "attribute_one": types.StringType,
      "attribute_two": types.StringType,
    },
    map[string]attr.Value{
      "attribute_one": types.StringValue("one"),
      "attribute_two": types.StringValue("two"),
    },
  )
}

Proposal

NOTE: NestedAttributes is not possible at the moment due to import cycle.

Add an AttributeTypes field and NestedAttributes field to defaults.ObjectRequest:

type ObjectRequest struct {
	// AttributeTypes returns the mapping of nested attribute
	// names to attribute types.
	AttributeTypes map[string]attr.Type

	// NestedAttributes is populated with the schema's nested
	// attributes for this object, if the object itself was a
	// NestedAttributeObject.
	NestedAttributes map[string]fwschema.Attribute

	// Path contains the path of the attribute for setting the
	// default value. Use this path for any response diagnostics.
	Path path.Path
}

In internal/fwschemadata, update the object handling to something like:

case fwschema.AttributeWithObjectDefaultValue:
	defaultValue := a.ObjectDefaultValue()

	if defaultValue != nil {
		req := defaults.ObjectRequest{
			AttributeTypes: a.GetType(), // real implementation is more complicated
			Path: fwPath,
		}
	
		if na, ok := a.(fwschema.NestedAttribute); ok {
			req.NestedAttributes = na.GetNestedObject().GetAttributes()
		}

		resp := defaults.ObjectResponse{}

		defaultValue.DefaultObject(ctx, req, &resp)

		logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath, resp.PlanValue))

		return resp.PlanValue.ToTerraformValue(ctx)
	}

Create a new resource/schema/objectdefault implementation for instantiating the object using all the nested attribute defaults, e.g.

func NestedAttributeDefaults() defaults.Object {/* ... */}

It may also be worth considering whether there should be a simplified object value default function that only takes in the map[string]attr.Value, since we can theoretically have the map[string]attr.Type already available.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions