diff --git a/DESIGN.md b/DESIGN.md index ec6ef42..5ac34cd 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -69,6 +69,8 @@ The response body schema found will be deep merged with the query/path `paramete For a given [OAS type](https://spec.openapis.org/oas/v3.1.0#data-types) and format combination, the following rules will be applied for mapping to Framework attribute types. Not all Framework types are represented natively with OAS, those types are noted below in [Unsupported Attribute Types](#unsupported-attribute-types). +> **NOTE:** All `Type` and `Format` fields below are native to OpenAPI Spec 3.x, with the exception of the format `set`, which is a custom field that only this generator tool is expected to support. + | Type (OAS) | Format (OAS) | Items type (OAS `array`) | Plugin Framework Attribute Type | |------------|---------------------|--------------------------|---------------------------------------------------------------------------------------------| | `integer` | - | - | `Int64Attribute` | @@ -77,7 +79,9 @@ For a given [OAS type](https://spec.openapis.org/oas/v3.1.0#data-types) and form | `string` | - | - | `StringAttribute` | | `boolean` | - | - | `BoolAttribute` | | `array` | - | `object` | `ListNestedAttribute` | -| `array` | - | (all others) | `ListAttribute` (nests with [element types](#oas-to-plugin-framework-element-types)) | +| `array` | - | (all others) | `ListAttribute` (nests with [element types](#oas-to-plugin-framework-element-types)) | +| `array` | `set` | `object` | `SetNestedAttribute` | +| `array` | `set` | (all others) | `SetAttribute` (nests with [element types](#oas-to-plugin-framework-element-types)) | | `object` | - | - | `SingleNestedAttribute` | #### Unsupported Attribute Types @@ -85,12 +89,12 @@ For a given [OAS type](https://spec.openapis.org/oas/v3.1.0#data-types) and form - While the Plugin Framework supports blocks, the Plugin Framework team encourages provider developers to prefer `ListNestedAttribute`, `SetNestedAttribute`, and `SingleNestedAttribute` for new provider development. - `ObjectAttribute` - The generator will default to `SingleNestedAttribute` for object types to provide the additional schema information. -- `SetNestedAttribute`, `SetAttribute`, `MapNestedAttribute`, and `MapAttribute` +- `MapNestedAttribute`, and `MapAttribute` - Mapping for these types is currently not supported, but will be considered in future versions. ### OAS to Plugin Framework Element Types -For attributes that don’t have additional schema information (currently only `ListAttribute`), the following rules will be applied for mapping from OAS type and format combinations, into Framework element types. +For attributes that don't have additional schema information (currently only `ListAttribute` and `SetAttribute`), the following rules will be applied for mapping from OAS type and format combinations, into Framework element types. | Type (OAS) | Format (OAS) | Items type (OAS `array`) | Plugin Framework Element Type | |------------|---------------------|--------------------------|---------------------------------| @@ -100,6 +104,7 @@ For attributes that don’t have additional schema information (currently only ` | `string` | - | - | `StringType` | | `boolean` | - | - | `BoolType` | | `array` | - | (all) | `ListType` | +| `array` | `set` | (all) | `SetType` | | `object` | - | - | `ObjectType` | ### Required, Computed, and Optional diff --git a/go.mod b/go.mod index d2d3dc4..c6cf278 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/google/go-cmp v0.5.9 - github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230622133831-8ed4d77d321e + github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230623193314-2a16a9d0b6f3 github.com/mattn/go-colorable v0.1.13 github.com/mitchellh/cli v1.1.5 github.com/pb33f/libopenapi v0.8.5 diff --git a/go.sum b/go.sum index 3597f03..8df99f2 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230622133831-8ed4d77d321e h1:+BPglv17monTwovwckVW/ZXbi3ZzGLanhQvBccSdWSQ= -github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230622133831-8ed4d77d321e/go.mod h1:4aZFKiOI2xiQFOpeQMMyDL8vRmKAZXHUY4kWol7Fdco= +github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230623193314-2a16a9d0b6f3 h1:6IiMR/31Wu/HvEGhLNzx1wSWvYCU2gkRv39sB24Cpis= +github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230623193314-2a16a9d0b6f3/go.mod h1:4aZFKiOI2xiQFOpeQMMyDL8vRmKAZXHUY4kWol7Fdco= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= diff --git a/internal/cmd/testdata/edgecase/generated_framework_ir.json b/internal/cmd/testdata/edgecase/generated_framework_ir.json index d561271..9758be2 100644 --- a/internal/cmd/testdata/edgecase/generated_framework_ir.json +++ b/internal/cmd/testdata/edgecase/generated_framework_ir.json @@ -20,9 +20,97 @@ } ] } + }, + { + "name": "set_collections", + "schema": { + "attributes": [ + { + "name": "set_prop", + "set": { + "computed_optional_required": "computed_optional", + "element_type": { + "string": {} + }, + "description": "This is a set of strings" + } + }, + { + "name": "setnested_prop", + "set_nested": { + "computed_optional_required": "computed_optional", + "nested_object": { + "attributes": [ + { + "name": "bool_prop", + "bool": { + "computed_optional_required": "computed_optional", + "description": "Bool inside a set!" + } + }, + { + "name": "string_prop", + "string": { + "computed_optional_required": "computed_optional", + "description": "String inside a set!", + "sensitive": false + } + } + ] + }, + "description": "This is a set with a nested object" + } + } + ] + } } ], "provider": { "name": "edgecase" - } + }, + "resources": [ + { + "name": "set_collections", + "schema": { + "attributes": [ + { + "name": "set_prop", + "set": { + "computed_optional_required": "computed_optional", + "element_type": { + "string": {} + }, + "description": "This is a set of strings" + } + }, + { + "name": "setnested_prop", + "set_nested": { + "computed_optional_required": "required", + "nested_object": { + "attributes": [ + { + "name": "bool_prop", + "bool": { + "computed_optional_required": "computed_optional", + "description": "Bool inside a set!" + } + }, + { + "name": "string_prop", + "string": { + "computed_optional_required": "computed_optional", + "description": "String inside a set!", + "sensitive": false + } + } + ] + }, + "description": "This is a set with a nested object" + } + } + ] + } + } + ] } diff --git a/internal/cmd/testdata/edgecase/openapi_spec.yml b/internal/cmd/testdata/edgecase/openapi_spec.yml index f21bd13..f5d167f 100644 --- a/internal/cmd/testdata/edgecase/openapi_spec.yml +++ b/internal/cmd/testdata/edgecase/openapi_spec.yml @@ -8,7 +8,7 @@ paths: get: summary: Test for nested lists (list within a list) responses: - '200': + "200": description: OK content: application/json: @@ -16,11 +16,64 @@ paths: type: object properties: main_list: - description: This list has another list nested underneath! + $ref: "#/components/schemas/multidimensional_array_schema" + /set_collections: + get: + summary: Test for SetNested attributes and Set attributes in a data source + responses: + "200": + description: OK + content: + application/json: + schema: + type: object + properties: + setnested_prop: + $ref: "#/components/schemas/setnested_schema" + set_prop: + description: This is a set of strings type: array + format: set items: - type: array - items: - type: string - required: - - main_list \ No newline at end of file + type: string + post: + summary: Test for SetNested attributes and Set attributes in a resource + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - setnested_prop + properties: + setnested_prop: + $ref: "#/components/schemas/setnested_schema" + set_prop: + description: This is a set of strings + type: array + format: set + items: + type: string +components: + schemas: + multidimensional_array_schema: + description: This list has another list nested underneath! + type: array + items: + type: array + items: + type: string + setnested_schema: + description: This is a set with a nested object + type: array + format: set + items: + type: object + properties: + string_prop: + description: String inside a set! + type: string + bool_prop: + description: Bool inside a set! + type: boolean diff --git a/internal/cmd/testdata/edgecase/tfopenapigen_config.yml b/internal/cmd/testdata/edgecase/tfopenapigen_config.yml index aae4315..baa648c 100644 --- a/internal/cmd/testdata/edgecase/tfopenapigen_config.yml +++ b/internal/cmd/testdata/edgecase/tfopenapigen_config.yml @@ -1,11 +1,21 @@ -# Ref: https://registry.terraform.io/providers/integrations/github/latest/docs provider: name: edgecase resources: + set_collections: + create: + path: /set_collections + method: POST + read: + path: /set_collections + method: GET data_sources: nested_lists: read: path: /nested_lists + method: GET + set_collections: + read: + path: /set_collections method: GET \ No newline at end of file diff --git a/internal/mapper/oas/attribute.go b/internal/mapper/oas/attribute.go index bcc65a4..6ad41bd 100644 --- a/internal/mapper/oas/attribute.go +++ b/internal/mapper/oas/attribute.go @@ -49,7 +49,7 @@ func (s *OASSchema) BuildResourceAttribute(name string, computability schema.Com case util.OAS_type_boolean: return s.BuildBoolResource(name, computability) case util.OAS_type_array: - return s.BuildListResource(name, computability) + return s.BuildCollectionResource(name, computability) case util.OAS_type_object: return s.BuildSingleNestedResource(name, computability) default: @@ -94,7 +94,7 @@ func (s *OASSchema) BuildDataSourceAttribute(name string, computability schema.C case util.OAS_type_boolean: return s.BuildBoolDataSource(name, computability) case util.OAS_type_array: - return s.BuildListDataSource(name, computability) + return s.BuildCollectionDataSource(name, computability) case util.OAS_type_object: return s.BuildSingleNestedDataSource(name, computability) default: diff --git a/internal/mapper/oas/list.go b/internal/mapper/oas/collection.go similarity index 62% rename from internal/mapper/oas/list.go rename to internal/mapper/oas/collection.go index ad12440..97b26a5 100644 --- a/internal/mapper/oas/list.go +++ b/internal/mapper/oas/collection.go @@ -12,7 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-codegen-spec/schema" ) -func (s *OASSchema) BuildListResource(name string, computability schema.ComputedOptionalRequired) (*resource.Attribute, error) { +func (s *OASSchema) BuildCollectionResource(name string, computability schema.ComputedOptionalRequired) (*resource.Attribute, error) { if !s.Schema.Items.IsA() { return nil, fmt.Errorf("invalid array type for '%s', doesn't have a schema", name) } @@ -28,6 +28,19 @@ func (s *OASSchema) BuildListResource(name string, computability schema.Computed return nil, fmt.Errorf("failed to map nested object schema proxy - %w", err) } + if s.Schema.Format == util.TF_format_set { + return &resource.Attribute{ + Name: name, + SetNested: &resource.SetNestedAttribute{ + NestedObject: resource.NestedAttributeObject{ + Attributes: *objectAttributes, + }, + ComputedOptionalRequired: computability, + Description: s.GetDescription(), + }, + }, nil + } + return &resource.Attribute{ Name: name, ListNested: &resource.ListNestedAttribute{ @@ -42,7 +55,18 @@ func (s *OASSchema) BuildListResource(name string, computability schema.Computed elemType, err := itemSchema.BuildElementType() if err != nil { - return nil, fmt.Errorf("failed to create list elem type - %w", err) + return nil, fmt.Errorf("failed to create collection elem type - %w", err) + } + + if s.Schema.Format == util.TF_format_set { + return &resource.Attribute{ + Name: name, + Set: &resource.SetAttribute{ + ElementType: elemType, + ComputedOptionalRequired: computability, + Description: s.GetDescription(), + }, + }, nil } return &resource.Attribute{ @@ -55,7 +79,7 @@ func (s *OASSchema) BuildListResource(name string, computability schema.Computed }, nil } -func (s *OASSchema) BuildListDataSource(name string, computability schema.ComputedOptionalRequired) (*datasource.Attribute, error) { +func (s *OASSchema) BuildCollectionDataSource(name string, computability schema.ComputedOptionalRequired) (*datasource.Attribute, error) { if !s.Schema.Items.IsA() { return nil, fmt.Errorf("invalid array type for '%s', doesn't have a schema", name) } @@ -71,6 +95,19 @@ func (s *OASSchema) BuildListDataSource(name string, computability schema.Comput return nil, fmt.Errorf("failed to map nested object schema proxy - %w", err) } + if s.Schema.Format == util.TF_format_set { + return &datasource.Attribute{ + Name: name, + SetNested: &datasource.SetNestedAttribute{ + NestedObject: datasource.NestedAttributeObject{ + Attributes: *objectAttributes, + }, + ComputedOptionalRequired: computability, + Description: s.GetDescription(), + }, + }, nil + } + return &datasource.Attribute{ Name: name, ListNested: &datasource.ListNestedAttribute{ @@ -85,7 +122,18 @@ func (s *OASSchema) BuildListDataSource(name string, computability schema.Comput elemType, err := itemSchema.BuildElementType() if err != nil { - return nil, fmt.Errorf("failed to create list elem type - %w", err) + return nil, fmt.Errorf("failed to create collection elem type - %w", err) + } + + if s.Schema.Format == util.TF_format_set { + return &datasource.Attribute{ + Name: name, + Set: &datasource.SetAttribute{ + ElementType: elemType, + ComputedOptionalRequired: computability, + Description: s.GetDescription(), + }, + }, nil } return &datasource.Attribute{ @@ -98,7 +146,7 @@ func (s *OASSchema) BuildListDataSource(name string, computability schema.Comput }, nil } -func (s *OASSchema) BuildListElementType() (schema.ElementType, error) { +func (s *OASSchema) BuildCollectionElementType() (schema.ElementType, error) { if !s.Schema.Items.IsA() { return schema.ElementType{}, fmt.Errorf("invalid array type for nested elem array, doesn't have a schema") } @@ -112,6 +160,14 @@ func (s *OASSchema) BuildListElementType() (schema.ElementType, error) { return schema.ElementType{}, err } + if s.Schema.Format == util.TF_format_set { + return schema.ElementType{ + Set: &schema.SetType{ + ElementType: elemType, + }, + }, nil + } + return schema.ElementType{ List: &schema.ListType{ ElementType: elemType, diff --git a/internal/mapper/oas/list_test.go b/internal/mapper/oas/collection_test.go similarity index 52% rename from internal/mapper/oas/list_test.go rename to internal/mapper/oas/collection_test.go index c7702a3..eb13c3e 100644 --- a/internal/mapper/oas/list_test.go +++ b/internal/mapper/oas/collection_test.go @@ -17,7 +17,7 @@ import ( // TODO: add error tests -func TestBuildListResource(t *testing.T) { +func TestBuildCollectionResource(t *testing.T) { t.Parallel() testCases := map[string]struct { @@ -81,6 +81,64 @@ func TestBuildListResource(t *testing.T) { }, }, }, + "set nested attributes": { + schema: &base.Schema{ + Type: []string{"object"}, + Required: []string{"nested_set_prop_required"}, + Properties: map[string]*base.SchemaProxy{ + "nested_set_prop_required": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"array"}, + Format: "set", + Description: "hey there! I'm a set nested array type, required.", + Items: &base.DynamicValue[*base.SchemaProxy, bool]{ + A: base.CreateSchemaProxy(&base.Schema{ + Type: []string{"object"}, + Required: []string{"nested_int64_required"}, + Properties: map[string]*base.SchemaProxy{ + "nested_float64": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"number"}, + Format: "double", + Description: "hey there! I'm a nested float64 type.", + }), + "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"integer"}, + Format: "int64", + Description: "hey there! I'm a nested int64 type, required.", + }), + }, + }), + }, + }), + }, + }, + expectedAttributes: &[]resource.Attribute{ + { + Name: "nested_set_prop_required", + SetNested: &resource.SetNestedAttribute{ + ComputedOptionalRequired: schema.Required, + Description: pointer("hey there! I'm a set nested array type, required."), + NestedObject: resource.NestedAttributeObject{ + Attributes: []resource.Attribute{ + { + Name: "nested_float64", + Float64: &resource.Float64Attribute{ + ComputedOptionalRequired: schema.ComputedOptional, + Description: pointer("hey there! I'm a nested float64 type."), + }, + }, + { + Name: "nested_int64_required", + Int64: &resource.Int64Attribute{ + ComputedOptionalRequired: schema.Required, + Description: pointer("hey there! I'm a nested int64 type, required."), + }, + }, + }, + }, + }, + }, + }, + }, "list attributes with list and nested object element type": { schema: &base.Schema{ Type: []string{"object"}, @@ -187,6 +245,116 @@ func TestBuildListResource(t *testing.T) { }, }, }, + "set attributes with set and nested object element type": { + schema: &base.Schema{ + Type: []string{"object"}, + Required: []string{"nested_set_prop_required"}, + Properties: map[string]*base.SchemaProxy{ + "nested_set_prop": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"array"}, + Format: "set", + Description: "hey there! I'm a set of sets.", + Items: &base.DynamicValue[*base.SchemaProxy, bool]{ + A: base.CreateSchemaProxy(&base.Schema{ + Type: []string{"array"}, + Format: "set", + Items: &base.DynamicValue[*base.SchemaProxy, bool]{ + A: base.CreateSchemaProxy(&base.Schema{ + Type: []string{"object"}, + Properties: map[string]*base.SchemaProxy{ + "float64_prop": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"number"}, + Format: "double", + }), + "int64_prop": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"integer"}, + Format: "int64", + }), + }, + }), + }, + }), + }, + }), + "nested_set_prop_required": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"array"}, + Format: "set", + Description: "hey there! I'm a set of sets, required.", + Items: &base.DynamicValue[*base.SchemaProxy, bool]{ + A: base.CreateSchemaProxy(&base.Schema{ + Type: []string{"array"}, + Format: "set", + Items: &base.DynamicValue[*base.SchemaProxy, bool]{ + A: base.CreateSchemaProxy(&base.Schema{ + Type: []string{"object"}, + Properties: map[string]*base.SchemaProxy{ + "bool_prop": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"boolean"}, + }), + "string_prop": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"string"}, + }), + }, + }), + }, + }), + }, + }), + }, + }, + expectedAttributes: &[]resource.Attribute{ + { + Name: "nested_set_prop", + Set: &resource.SetAttribute{ + ComputedOptionalRequired: schema.ComputedOptional, + Description: pointer("hey there! I'm a set of sets."), + ElementType: schema.ElementType{ + Set: &schema.SetType{ + ElementType: schema.ElementType{ + Object: &schema.ObjectType{ + AttributeTypes: []schema.ObjectAttributeType{ + { + Name: "float64_prop", + Float64: &schema.Float64Type{}, + }, + { + Name: "int64_prop", + Int64: &schema.Int64Type{}, + }, + }, + }, + }, + }, + }, + }, + }, + { + Name: "nested_set_prop_required", + Set: &resource.SetAttribute{ + ComputedOptionalRequired: schema.Required, + Description: pointer("hey there! I'm a set of sets, required."), + ElementType: schema.ElementType{ + Set: &schema.SetType{ + ElementType: schema.ElementType{ + Object: &schema.ObjectType{ + AttributeTypes: []schema.ObjectAttributeType{ + { + Name: "bool_prop", + Bool: &schema.BoolType{}, + }, + { + Name: "string_prop", + String: &schema.StringType{}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, } for name, testCase := range testCases { @@ -208,7 +376,7 @@ func TestBuildListResource(t *testing.T) { } } -func TestBuildListDataSource(t *testing.T) { +func TestBuildCollectionDataSource(t *testing.T) { t.Parallel() testCases := map[string]struct { @@ -272,6 +440,64 @@ func TestBuildListDataSource(t *testing.T) { }, }, }, + "set nested attributes": { + schema: &base.Schema{ + Type: []string{"object"}, + Required: []string{"nested_set_prop_required"}, + Properties: map[string]*base.SchemaProxy{ + "nested_set_prop_required": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"array"}, + Format: "set", + Description: "hey there! I'm a set nested array type, required.", + Items: &base.DynamicValue[*base.SchemaProxy, bool]{ + A: base.CreateSchemaProxy(&base.Schema{ + Type: []string{"object"}, + Required: []string{"nested_int64_required"}, + Properties: map[string]*base.SchemaProxy{ + "nested_float64": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"number"}, + Format: "double", + Description: "hey there! I'm a nested float64 type.", + }), + "nested_int64_required": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"integer"}, + Format: "int64", + Description: "hey there! I'm a nested int64 type, required.", + }), + }, + }), + }, + }), + }, + }, + expectedAttributes: &[]datasource.Attribute{ + { + Name: "nested_set_prop_required", + SetNested: &datasource.SetNestedAttribute{ + ComputedOptionalRequired: schema.Required, + Description: pointer("hey there! I'm a set nested array type, required."), + NestedObject: datasource.NestedAttributeObject{ + Attributes: []datasource.Attribute{ + { + Name: "nested_float64", + Float64: &datasource.Float64Attribute{ + ComputedOptionalRequired: schema.ComputedOptional, + Description: pointer("hey there! I'm a nested float64 type."), + }, + }, + { + Name: "nested_int64_required", + Int64: &datasource.Int64Attribute{ + ComputedOptionalRequired: schema.Required, + Description: pointer("hey there! I'm a nested int64 type, required."), + }, + }, + }, + }, + }, + }, + }, + }, "list attributes with list and nested object element type": { schema: &base.Schema{ Type: []string{"object"}, @@ -378,6 +604,116 @@ func TestBuildListDataSource(t *testing.T) { }, }, }, + "set attributes with set and nested object element type": { + schema: &base.Schema{ + Type: []string{"object"}, + Required: []string{"nested_set_prop_required"}, + Properties: map[string]*base.SchemaProxy{ + "nested_set_prop": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"array"}, + Format: "set", + Description: "hey there! I'm a set of sets.", + Items: &base.DynamicValue[*base.SchemaProxy, bool]{ + A: base.CreateSchemaProxy(&base.Schema{ + Type: []string{"array"}, + Format: "set", + Items: &base.DynamicValue[*base.SchemaProxy, bool]{ + A: base.CreateSchemaProxy(&base.Schema{ + Type: []string{"object"}, + Properties: map[string]*base.SchemaProxy{ + "float64_prop": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"number"}, + Format: "double", + }), + "int64_prop": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"integer"}, + Format: "int64", + }), + }, + }), + }, + }), + }, + }), + "nested_set_prop_required": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"array"}, + Format: "set", + Description: "hey there! I'm a set of sets, required.", + Items: &base.DynamicValue[*base.SchemaProxy, bool]{ + A: base.CreateSchemaProxy(&base.Schema{ + Type: []string{"array"}, + Format: "set", + Items: &base.DynamicValue[*base.SchemaProxy, bool]{ + A: base.CreateSchemaProxy(&base.Schema{ + Type: []string{"object"}, + Properties: map[string]*base.SchemaProxy{ + "bool_prop": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"boolean"}, + }), + "string_prop": base.CreateSchemaProxy(&base.Schema{ + Type: []string{"string"}, + }), + }, + }), + }, + }), + }, + }), + }, + }, + expectedAttributes: &[]datasource.Attribute{ + { + Name: "nested_set_prop", + Set: &datasource.SetAttribute{ + ComputedOptionalRequired: schema.ComputedOptional, + Description: pointer("hey there! I'm a set of sets."), + ElementType: schema.ElementType{ + Set: &schema.SetType{ + ElementType: schema.ElementType{ + Object: &schema.ObjectType{ + AttributeTypes: []schema.ObjectAttributeType{ + { + Name: "float64_prop", + Float64: &schema.Float64Type{}, + }, + { + Name: "int64_prop", + Int64: &schema.Int64Type{}, + }, + }, + }, + }, + }, + }, + }, + }, + { + Name: "nested_set_prop_required", + Set: &datasource.SetAttribute{ + ComputedOptionalRequired: schema.Required, + Description: pointer("hey there! I'm a set of sets, required."), + ElementType: schema.ElementType{ + Set: &schema.SetType{ + ElementType: schema.ElementType{ + Object: &schema.ObjectType{ + AttributeTypes: []schema.ObjectAttributeType{ + { + Name: "bool_prop", + Bool: &schema.BoolType{}, + }, + { + Name: "string_prop", + String: &schema.StringType{}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, } for name, testCase := range testCases { diff --git a/internal/mapper/oas/element_type.go b/internal/mapper/oas/element_type.go index becf239..2f5ef02 100644 --- a/internal/mapper/oas/element_type.go +++ b/internal/mapper/oas/element_type.go @@ -21,7 +21,7 @@ func (s *OASSchema) BuildElementType() (schema.ElementType, error) { case util.OAS_type_boolean: return s.BuildBoolElementType() case util.OAS_type_array: - return s.BuildListElementType() + return s.BuildCollectionElementType() case util.OAS_type_object: return s.BuildObjectElementType() diff --git a/internal/mapper/util/oas_constants.go b/internal/mapper/util/oas_constants.go index 8ab26f3..66e59f0 100644 --- a/internal/mapper/util/oas_constants.go +++ b/internal/mapper/util/oas_constants.go @@ -21,6 +21,9 @@ const ( OAS_format_float = "float" OAS_format_password = "password" + // Custom format for SetNested and Set attributes + TF_format_set = "set" + OAS_mediatype_json = "application/json" OAS_response_code_ok = "200"