Skip to content

Consider Exported Reflection Helper for Model Type Attribute Types #774

@bflad

Description

@bflad

Module version

v1.3.1

Use-cases

NOTE: The below is not intended as a maintainer endorsement of this particular design pattern for data handling, however it captures a common problem within that particular design pattern. Provider developers are encouraged to try this pattern or other patterns for their own usage while the ecosystem determines better/easier data handling practices.

One emergent pattern for framework provider developers using the "data model" approach with nested data handling, e.g.

schema.Schema{
  Attributes: map[string]schema.Attribute{
    "example_attribute": schema.SingleNestedAttribute{
      Attributes: map[string]schema.Attribute{
        "example_nested_attribute": schema.SingleNestedAttribute{
          Attributes: map[string]schema.Attribute{
            "example_string_attribute": schema.StringAttribute{
               // ... other fields ...
            },
          },
        },
      },
      // ... other fields ...
    },
  },
}

type ExampleResourceModel struct {
  ExampleAttribute types.Object `tfsdk:"example_attribute"`
}

type ExampleAttributeModel struct {
  ExampleNestedAttribute types.Object `tfsdk:"example_nested_attribute"`
}

type ExampleNestedAttributeModel struct {
  ExampleStringAttribute types.String `tfsdk:"example_string_attribute"`
}

Is to manually create a method on nested model types that has the mapping of object attribute types for recreating the equivalent types.Object:

func (m ExampleAttributeModel) AttributeTypes() map[string]attr.Type {
  return map[string]attr.Type{
    "example_nested_attribute": types.ObjectType{
      AttrTypes: ExampleNestedAttributeModel{}.AttributeTypes(),
    },
  }
}

func (m ExampleNestedAttributeModel) AttributeTypes() map[string]attr.Type {
  return map[string]attr.Type{
    "example_string_attribute": types.StringType,
  }
}

This method creation process can be repetitive, error prone, and verbose in nature.

Attempted Solutions

Manually creating the attribute types helper methods.

Proposal

This proposal is not fully designed nor is it necessarily feasible/recommended, but more intended to capture some brainstorming effort around this particular problem.

The framework could theoretically introduce a function which takes a given model type and uses Go's reflection capabilities to create a map of the tfsdk struct field tag names to the Type() of the struct field types (the type of the value type). Then, provider developers could either still create the method with a simplified implementation, e.g.

// Design sketch, not intended to convey the final API
func (m ExampleNestedAttributeModel) AttributeTypes() map[string]attr.Type {
  return fwreflect.AttributeTypes(m)
}

Or directly use it with value creation functions.

There are definitely challenges or other ideas to ponder though:

  • Would this functionality need error/diagnostic handling? It is inherently risky to assume perfectly compatible provider developer implementations. Adding error/diagnostic handling inherently makes the functionality more difficult to work with since that information needs to be bubbled up through all callers. Is a better approach through out-of-runtime code generation?
  • While this would theoretically work out of the box for primitive (Bool, Float64, Int64, Number, String, and extensions of those) types within the object, collection (List, Map, Set) and structural (Object) types are problematic since they need to know type information about element types or underlying attribute types. This may be resolvable by expanding the information in the tfsdk struct field tags, but what would that look like?
  • Is a better approach to do offer additional methods on the schema or code generation via the schema itself? The schema is the canonical reference implementation and has knowledge of all types, nesting, etc.
  • Is a better approach implementing types.ObjectValuable with model types and creating an associated type for usage with CustomType schema fields?

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions