From f89b01bbbf4007df3d6f9edb391052d07cef6398 Mon Sep 17 00:00:00 2001 From: Paddy Carver Date: Tue, 20 Jul 2021 18:44:23 -0700 Subject: [PATCH] Add support for MapNestedAttributes. Fill in tests for maps. Add MapNestedAttributes and tests for it. --- .changelog/79.txt | 3 ++ internal/proto6/schema_test.go | 24 ++++++++++++++-- schema/nested_attributes.go | 5 ++-- tfsdk/serve_provider_test.go | 52 ++++++++++++++++++++++++++++++++-- tfsdk/serve_test.go | 48 +++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 .changelog/79.txt diff --git a/.changelog/79.txt b/.changelog/79.txt new file mode 100644 index 000000000..9595d30c3 --- /dev/null +++ b/.changelog/79.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +Added support for MapNestedAttributes. +``` diff --git a/internal/proto6/schema_test.go b/internal/proto6/schema_test.go index 1690fceea..09a036f0c 100644 --- a/internal/proto6/schema_test.go +++ b/internal/proto6/schema_test.go @@ -84,7 +84,10 @@ func TestSchema(t *testing.T) { }}, Optional: true, }, - // TODO: add map support when it lands + "map": { + Type: types.MapType{ElemType: types.NumberType}, + Computed: true, + }, // TODO: add tuple support when it lands // TODO: add set support when it lands }, @@ -98,6 +101,11 @@ func TestSchema(t *testing.T) { Type: tftypes.List{ElementType: tftypes.String}, Required: true, }, + { + Name: "map", + Type: tftypes.Map{AttributeType: tftypes.Number}, + Computed: true, + }, { Name: "object", Type: tftypes.Object{AttributeTypes: map[string]tftypes.Type{ @@ -572,6 +580,19 @@ func TestAttribute(t *testing.T) { Optional: true, }, }, + "attr-map": { + name: "map", + attr: schema.Attribute{ + Type: types.MapType{ElemType: types.StringType}, + Optional: true, + }, + path: tftypes.NewAttributePath(), + expected: &tfprotov6.SchemaAttribute{ + Name: "map", + Type: tftypes.Map{AttributeType: tftypes.String}, + Optional: true, + }, + }, "attr-object": { name: "object", attr: schema.Attribute{ @@ -593,7 +614,6 @@ func TestAttribute(t *testing.T) { Optional: true, }, }, - // TODO: add map attribute when we support it // TODO: add set attribute when we support it // TODO: add tuple attribute when we support it "required": { diff --git a/schema/nested_attributes.go b/schema/nested_attributes.go index 4c101cf6c..1cf00d953 100644 --- a/schema/nested_attributes.go +++ b/schema/nested_attributes.go @@ -349,8 +349,9 @@ func (m mapNestedAttributes) GetMaxItems() int64 { // AttributeType returns an attr.Type corresponding to the nested attributes. func (m mapNestedAttributes) AttributeType() attr.Type { - // TODO fill in implementation when types.MapType is available - return nil + return types.MapType{ + ElemType: m.nestedAttributes.AttributeType(), + } } func (m mapNestedAttributes) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { diff --git a/tfsdk/serve_provider_test.go b/tfsdk/serve_provider_test.go index 5883e9e20..1c2a3afe0 100644 --- a/tfsdk/serve_provider_test.go +++ b/tfsdk/serve_provider_test.go @@ -136,7 +136,10 @@ func (t *testServeProvider) GetSchema(_ context.Context) (schema.Schema, []*tfpr Type: types.ObjectType{}, Optional: true, }, - // TODO: add maps when we support them + "map": { + Type: types.MapType{ElemType: types.NumberType}, + Optional: true, + }, // TODO: add sets when we support them // TODO: add tuples when we support them "single-nested-attributes": { @@ -167,6 +170,20 @@ func (t *testServeProvider) GetSchema(_ context.Context) (schema.Schema, []*tfpr }, schema.ListNestedAttributesOptions{}), Optional: true, }, + "map-nested-attributes": { + Attributes: schema.MapNestedAttributes(map[string]schema.Attribute{ + "foo": { + Type: types.StringType, + Optional: true, + Computed: true, + }, + "bar": { + Type: types.NumberType, + Required: true, + }, + }, schema.MapNestedAttributesOptions{}), + Optional: true, + }, }, }, nil } @@ -248,6 +265,33 @@ var testServeProviderProviderSchema = &tfprotov6.Schema{ }, Optional: true, }, + { + Name: "map", + Type: tftypes.Map{ + AttributeType: tftypes.Number, + }, + Optional: true, + }, + { + Name: "map-nested-attributes", + Optional: true, + NestedType: &tfprotov6.SchemaObject{ + Nesting: tfprotov6.SchemaObjectNestingModeMap, + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "bar", + Type: tftypes.Number, + Required: true, + }, + { + Name: "foo", + Type: tftypes.String, + Optional: true, + Computed: true, + }, + }, + }, + }, { Name: "number", Type: tftypes.Number, @@ -314,7 +358,6 @@ var testServeProviderProviderSchema = &tfprotov6.Schema{ Type: tftypes.String, Optional: true, }, - // TODO: add maps when we support them // TODO: add sets when we support them // TODO: add tuples when we support them }, @@ -339,6 +382,7 @@ var testServeProviderProviderType = tftypes.Object{ "bar": tftypes.Bool, "baz": tftypes.Number, }}}, + "map": tftypes.Map{AttributeType: tftypes.Number}, "object": tftypes.Object{AttributeTypes: map[string]tftypes.Type{ "foo": tftypes.String, "bar": tftypes.Bool, @@ -354,6 +398,10 @@ var testServeProviderProviderType = tftypes.Object{ "foo": tftypes.String, "bar": tftypes.Number, }}}, + "map-nested-attributes": tftypes.Map{AttributeType: tftypes.Object{AttributeTypes: map[string]tftypes.Type{ + "foo": tftypes.String, + "bar": tftypes.Number, + }}}, }, } diff --git a/tfsdk/serve_test.go b/tfsdk/serve_test.go index fdf9c73ff..87d9ca28c 100644 --- a/tfsdk/serve_test.go +++ b/tfsdk/serve_test.go @@ -333,6 +333,30 @@ func TestServerConfigureProvider(t *testing.T) { "baz": tftypes.NewValue(tftypes.Number, 8675309), }), }), + "map": tftypes.NewValue(tftypes.Map{AttributeType: tftypes.Number}, map[string]tftypes.Value{ + "foo": tftypes.NewValue(tftypes.Number, 123), + "bar": tftypes.NewValue(tftypes.Number, 456), + "baz": tftypes.NewValue(tftypes.Number, 789), + }), + "map-nested-attributes": tftypes.NewValue(tftypes.Map{AttributeType: tftypes.Object{AttributeTypes: map[string]tftypes.Type{ + "bar": tftypes.Number, + "foo": tftypes.String, + }}}, map[string]tftypes.Value{ + "hello": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{ + "bar": tftypes.Number, + "foo": tftypes.String, + }}, map[string]tftypes.Value{ + "bar": tftypes.NewValue(tftypes.Number, 123456), + "foo": tftypes.NewValue(tftypes.String, "world"), + }), + "goodnight": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{ + "bar": tftypes.Number, + "foo": tftypes.String, + }}, map[string]tftypes.Value{ + "bar": tftypes.NewValue(tftypes.Number, 56789), + "foo": tftypes.NewValue(tftypes.String, "moon"), + }), + }), "object": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{ "foo": tftypes.String, "bar": tftypes.Bool, @@ -422,6 +446,30 @@ func TestServerConfigureProvider(t *testing.T) { "foo": tftypes.String, "bar": tftypes.Number, }}}, tftypes.UnknownValue), + "map": tftypes.NewValue(tftypes.Map{AttributeType: tftypes.Number}, map[string]tftypes.Value{ + "foo": tftypes.NewValue(tftypes.Number, 123), + "bar": tftypes.NewValue(tftypes.Number, 456), + "baz": tftypes.NewValue(tftypes.Number, 789), + }), + "map-nested-attributes": tftypes.NewValue(tftypes.Map{AttributeType: tftypes.Object{AttributeTypes: map[string]tftypes.Type{ + "bar": tftypes.Number, + "foo": tftypes.String, + }}}, map[string]tftypes.Value{ + "hello": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{ + "bar": tftypes.Number, + "foo": tftypes.String, + }}, map[string]tftypes.Value{ + "bar": tftypes.NewValue(tftypes.Number, 123456), + "foo": tftypes.NewValue(tftypes.String, "world"), + }), + "goodnight": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{ + "bar": tftypes.Number, + "foo": tftypes.String, + }}, map[string]tftypes.Value{ + "bar": tftypes.NewValue(tftypes.Number, 56789), + "foo": tftypes.NewValue(tftypes.String, "moon"), + }), + }), }), }, }