diff --git a/tfsdk/block.go b/tfsdk/block.go index 415cee0a4..5d74893a2 100644 --- a/tfsdk/block.go +++ b/tfsdk/block.go @@ -25,6 +25,9 @@ var _ fwschema.Block = Block{} // The NestingMode field must be set or a runtime error will be raised by the // framework when fetching the schema. type Block struct { + // Typ is an optional field that defines the type of the Block. It defaults + // to types.ObjectType but, any type that fills the attr.TypeWithAttributeTypes + // interface can be used. Typ attr.TypeWithAttributeTypes // Attributes are value fields inside the block. This map of attributes @@ -211,7 +214,7 @@ func (b Block) GetValidators() []AttributeValidator { return b.Validators } -// attributeType returns an attr.Type corresponding to the block. +// Type returns an attr.Type corresponding to the block. func (b Block) Type() attr.Type { var attrType attr.TypeWithAttributeTypes attrType = types.ObjectType{} diff --git a/tfsdk/block_test.go b/tfsdk/block_test.go index 4da4814ce..c056baf2a 100644 --- a/tfsdk/block_test.go +++ b/tfsdk/block_test.go @@ -4,10 +4,47 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/types" ) +var ( + _ attr.Type = CustomType{} +) + +type CustomType struct { + types.ObjectType +} + +func (t CustomType) WithAttributeTypes(typs map[string]attr.Type) attr.TypeWithAttributeTypes { + return CustomType{ + types.ObjectType{ + AttrTypes: typs, + }, + } +} + +func (t CustomType) Equal(candidate attr.Type) bool { + other, ok := candidate.(CustomType) + if !ok { + return false + } + if len(other.AttrTypes) != len(t.AttrTypes) { + return false + } + for k, v := range t.AttrTypes { + attrType, ok := other.AttrTypes[k] + if !ok { + return false + } + if !v.Equal(attrType) { + return false + } + } + return true +} + func TestBlockType(t *testing.T) { t.Parallel() @@ -51,6 +88,45 @@ func TestBlockType(t *testing.T) { }, }, }, + "NestingMode-List-CustomType": { + block: Block{ + Attributes: map[string]Attribute{ + "test_attribute": { + Required: true, + Type: types.StringType, + }, + }, + Blocks: map[string]Block{ + "test_block": { + Typ: CustomType{}, + Attributes: map[string]Attribute{ + "test_block_attribute": { + Required: true, + Type: types.StringType, + }, + }, + NestingMode: BlockNestingModeList, + }, + }, + NestingMode: BlockNestingModeList, + }, + expected: types.ListType{ + ElemType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test_attribute": types.StringType, + "test_block": types.ListType{ + ElemType: CustomType{ + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test_block_attribute": types.StringType, + }, + }, + }, + }, + }, + }, + }, + }, "NestingMode-Set": { block: Block{ Attributes: map[string]Attribute{ @@ -87,6 +163,45 @@ func TestBlockType(t *testing.T) { }, }, }, + "NestingMode-Set-CustomType": { + block: Block{ + Attributes: map[string]Attribute{ + "test_attribute": { + Required: true, + Type: types.StringType, + }, + }, + Blocks: map[string]Block{ + "test_block": { + Typ: CustomType{}, + Attributes: map[string]Attribute{ + "test_block_attribute": { + Required: true, + Type: types.StringType, + }, + }, + NestingMode: BlockNestingModeSet, + }, + }, + NestingMode: BlockNestingModeSet, + }, + expected: types.SetType{ + ElemType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test_attribute": types.StringType, + "test_block": types.SetType{ + ElemType: CustomType{ + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test_block_attribute": types.StringType, + }, + }, + }, + }, + }, + }, + }, + }, "NestingMode-Single": { block: Block{ Attributes: map[string]Attribute{ @@ -119,6 +234,41 @@ func TestBlockType(t *testing.T) { }, }, }, + "NestingMode-Single-CustomType": { + block: Block{ + Attributes: map[string]Attribute{ + "test_attribute": { + Required: true, + Type: types.StringType, + }, + }, + Blocks: map[string]Block{ + "test_block": { + Typ: CustomType{}, + Attributes: map[string]Attribute{ + "test_block_attribute": { + Required: true, + Type: types.StringType, + }, + }, + NestingMode: BlockNestingModeSingle, + }, + }, + NestingMode: BlockNestingModeSingle, + }, + expected: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test_attribute": types.StringType, + "test_block": CustomType{ + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test_block_attribute": types.StringType, + }, + }, + }, + }, + }, + }, } for name, testCase := range testCases {