-
Notifications
You must be signed in to change notification settings - Fork 99
Description
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
tfsdkstruct 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.ObjectValuablewith model types and creating an associated type for usage withCustomTypeschema fields?