Skip to content

Commit

Permalink
Refactoring import, schema, and model field methods on object attribu…
Browse files Browse the repository at this point in the history
…te to use associated external type (#74)
  • Loading branch information
bendbennett committed Oct 24, 2023
1 parent 2ad5b49 commit 668c420
Show file tree
Hide file tree
Showing 15 changed files with 697 additions and 59 deletions.
26 changes: 14 additions & 12 deletions internal/datasource_convert/object_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,28 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"

"github.com/hashicorp/terraform-plugin-codegen-framework/internal/datasource_generate"
generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema"
)

func convertObjectAttribute(o *datasource.ObjectAttribute) (datasource_generate.GeneratorObjectAttribute, error) {
if o == nil {
func convertObjectAttribute(a *datasource.ObjectAttribute) (datasource_generate.GeneratorObjectAttribute, error) {
if a == nil {
return datasource_generate.GeneratorObjectAttribute{}, fmt.Errorf("*datasource.ObjectAttribute is nil")
}

return datasource_generate.GeneratorObjectAttribute{
ObjectAttribute: schema.ObjectAttribute{
Required: isRequired(o.ComputedOptionalRequired),
Optional: isOptional(o.ComputedOptionalRequired),
Computed: isComputed(o.ComputedOptionalRequired),
Sensitive: isSensitive(o.Sensitive),
Description: description(o.Description),
MarkdownDescription: description(o.Description),
DeprecationMessage: deprecationMessage(o.DeprecationMessage),
Required: isRequired(a.ComputedOptionalRequired),
Optional: isOptional(a.ComputedOptionalRequired),
Computed: isComputed(a.ComputedOptionalRequired),
Sensitive: isSensitive(a.Sensitive),
Description: description(a.Description),
MarkdownDescription: description(a.Description),
DeprecationMessage: deprecationMessage(a.DeprecationMessage),
},

AttributeTypes: o.AttributeTypes,
CustomType: o.CustomType,
Validators: o.Validators,
AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType),
AttributeTypes: a.AttributeTypes,
CustomType: a.CustomType,
Validators: a.Validators,
}, nil
}
2 changes: 1 addition & 1 deletion internal/datasource_generate/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var mapNestedAttributeGoTemplate string
var numberAttributeTemplate string

//go:embed templates/object_attribute.gotmpl
var objectAttributeGoTemplate string
var objectAttributeTemplate string

//go:embed templates/set_attribute.gotmpl
var setAttributeTemplate string
Expand Down
57 changes: 52 additions & 5 deletions internal/datasource_generate/object_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package datasource_generate

import (
"fmt"
"strings"
"text/template"

Expand All @@ -17,6 +18,7 @@ import (
type GeneratorObjectAttribute struct {
schema.ObjectAttribute

AssociatedExternalType *generatorschema.AssocExtType
// The "specschema" types are used instead of the types within the attribute
// because support for extracting custom import information is required.
AttributeTypes specschema.ObjectAttributeTypes
Expand Down Expand Up @@ -46,6 +48,12 @@ func (g GeneratorObjectAttribute) Imports() *generatorschema.Imports {
imports.Append(customValidatorImports)
}

if g.AssociatedExternalType != nil {
imports.Append(generatorschema.AssociatedExternalTypeImports())
}

imports.Append(g.AssociatedExternalType.Imports())

return imports
}

Expand Down Expand Up @@ -75,6 +83,7 @@ func (g GeneratorObjectAttribute) Schema(name generatorschema.FrameworkIdentifie
type attribute struct {
Name string
AttributeTypes string
CustomType string
GeneratorObjectAttribute GeneratorObjectAttribute
}

Expand All @@ -84,16 +93,19 @@ func (g GeneratorObjectAttribute) Schema(name generatorschema.FrameworkIdentifie
GeneratorObjectAttribute: g,
}

funcMap := template.FuncMap{
"getAttrTypes": generatorschema.GetAttrTypes,
switch {
case g.CustomType != nil:
a.CustomType = g.CustomType.Type
case g.AssociatedExternalType != nil:
a.CustomType = fmt.Sprintf("%sType{\ntypes.ObjectType{\nAttrTypes: %sValue{}.AttributeTypes(ctx),\n},\n}", name.ToPascalCase(), name.ToPascalCase())
}

t, err := template.New("object_attribute").Funcs(funcMap).Parse(objectAttributeGoTemplate)
t, err := template.New("object_attribute").Parse(objectAttributeTemplate)
if err != nil {
return "", err
}

if _, err = addCommonAttributeTemplate(t); err != nil {
if _, err = addAttributeTemplate(t); err != nil {
return "", err
}

Expand All @@ -114,9 +126,44 @@ func (g GeneratorObjectAttribute) ModelField(name generatorschema.FrameworkIdent
ValueType: model.ObjectValueType,
}

if g.CustomType != nil {
switch {
case g.CustomType != nil:
field.ValueType = g.CustomType.ValueType
case g.AssociatedExternalType != nil:
field.ValueType = fmt.Sprintf("%sValue", name.ToPascalCase())
}

return field, nil
}

//func (g GeneratorObjectAttribute) CustomTypeAndValue(name string) ([]byte, error) {
// if g.AssociatedExternalType == nil {
// return nil, nil
// }
//
// var buf bytes.Buffer
//
// listType := generatorschema.NewCustomObjectType(name)
//
// b, err := listType.Render()
//
// if err != nil {
// return nil, err
// }
//
// buf.Write(b)
//
// elemType := generatorschema.GetElementType(g.ElementType)
//
// listValue := generatorschema.NewCustomObjectValue(name, elemType)
//
// b, err = listValue.Render()
//
// if err != nil {
// return nil, err
// }
//
// buf.Write(b)
//
// return buf.Bytes(), nil
//}
183 changes: 181 additions & 2 deletions internal/datasource_generate/object_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,110 @@ func TestGeneratorObjectAttribute_Imports(t *testing.T) {
},
},
},
"associated-external-type": {
input: GeneratorObjectAttribute{
AssociatedExternalType: &generatorschema.AssocExtType{
AssociatedExternalType: &specschema.AssociatedExternalType{
Type: "*api.ObjectAttribute",
},
},
},
expected: []code.Import{
{
Path: "github.com/hashicorp/terraform-plugin-framework/types",
},
{
Path: "fmt",
},
{
Path: "github.com/hashicorp/terraform-plugin-framework/diag",
},
{
Path: "github.com/hashicorp/terraform-plugin-framework/attr",
},
{
Path: "github.com/hashicorp/terraform-plugin-go/tftypes",
},
{
Path: "github.com/hashicorp/terraform-plugin-framework/types/basetypes",
},
},
},
"associated-external-type-with-import": {
input: GeneratorObjectAttribute{
AssociatedExternalType: &generatorschema.AssocExtType{
AssociatedExternalType: &specschema.AssociatedExternalType{
Import: &code.Import{
Path: "github.com/api",
},
Type: "*api.ObjectAttribute",
},
},
},
expected: []code.Import{
{
Path: "github.com/hashicorp/terraform-plugin-framework/types",
},
{
Path: "fmt",
},
{
Path: "github.com/hashicorp/terraform-plugin-framework/diag",
},
{
Path: "github.com/hashicorp/terraform-plugin-framework/attr",
},
{
Path: "github.com/hashicorp/terraform-plugin-go/tftypes",
},
{
Path: "github.com/hashicorp/terraform-plugin-framework/types/basetypes",
},
{
Path: "github.com/api",
},
},
},
"associated-external-type-with-custom-type": {
input: GeneratorObjectAttribute{
AssociatedExternalType: &generatorschema.AssocExtType{
AssociatedExternalType: &specschema.AssociatedExternalType{
Import: &code.Import{
Path: "github.com/api",
},
Type: "*api.ObjectAttribute",
},
},
CustomType: &specschema.CustomType{
Import: &code.Import{
Path: "github.com/my_account/my_project/attribute",
},
},
},
expected: []code.Import{
{
Path: "github.com/my_account/my_project/attribute",
},
{
Path: "fmt",
},
{
Path: "github.com/hashicorp/terraform-plugin-framework/diag",
},
{
Path: "github.com/hashicorp/terraform-plugin-framework/attr",
},
{
Path: "github.com/hashicorp/terraform-plugin-go/tftypes",
},
{
Path: "github.com/hashicorp/terraform-plugin-framework/types/basetypes",
},
{
Path: "github.com/api",
},
},
},
}

for name, testCase := range testCases {
Expand Down Expand Up @@ -634,9 +738,53 @@ AttributeTypes: map[string]attr.Type{
},
expected: `
"object_attribute": schema.ObjectAttribute{
AttributeTypes: map[string]attr.Type{
"str": types.StringType,
CustomType: my_custom_type,
},`,
},

"associated-external-type": {
input: GeneratorObjectAttribute{
AssociatedExternalType: &generatorschema.AssocExtType{
AssociatedExternalType: &specschema.AssociatedExternalType{
Type: "*api.ObjectAttribute",
},
},
AttributeTypes: specschema.ObjectAttributeTypes{
specschema.ObjectAttributeType{
Name: "bool",
Bool: &specschema.BoolType{},
},
},
},
expected: `
"object_attribute": schema.ObjectAttribute{
CustomType: ObjectAttributeType{
types.ObjectType{
AttrTypes: ObjectAttributeValue{}.AttributeTypes(ctx),
},
},
},`,
},

"custom-type-overriding-associated-external-type": {
input: GeneratorObjectAttribute{
AssociatedExternalType: &generatorschema.AssocExtType{
AssociatedExternalType: &specschema.AssociatedExternalType{
Type: "*api.ObjectAttribute",
},
},
AttributeTypes: specschema.ObjectAttributeTypes{
specschema.ObjectAttributeType{
Name: "bool",
Bool: &specschema.BoolType{},
},
},
CustomType: &specschema.CustomType{
Type: "my_custom_type",
},
},
expected: `
"object_attribute": schema.ObjectAttribute{
CustomType: my_custom_type,
},`,
},
Expand Down Expand Up @@ -1075,6 +1223,37 @@ func TestGeneratorObjectAttribute_ModelField(t *testing.T) {
TfsdkName: "object_attribute",
},
},
"associated-external-type": {
input: GeneratorObjectAttribute{
AssociatedExternalType: &generatorschema.AssocExtType{
AssociatedExternalType: &specschema.AssociatedExternalType{
Type: "*api.BoolAttribute",
},
},
},
expected: model.Field{
Name: "ObjectAttribute",
ValueType: "ObjectAttributeValue",
TfsdkName: "object_attribute",
},
},
"custom-type-overriding-associated-external-type": {
input: GeneratorObjectAttribute{
AssociatedExternalType: &generatorschema.AssocExtType{
AssociatedExternalType: &specschema.AssociatedExternalType{
Type: "*api.BoolAttribute",
},
},
CustomType: &specschema.CustomType{
ValueType: "my_custom_value_type",
},
},
expected: model.Field{
Name: "ObjectAttribute",
ValueType: "my_custom_value_type",
TfsdkName: "object_attribute",
},
},
}

for name, testCase := range testCases {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@

"{{.Name}}": schema.ObjectAttribute{
{{- if .CustomType}}
CustomType: {{.CustomType}},
{{- else}}
AttributeTypes: map[string]attr.Type{
{{.AttributeTypes}}
},
{{- end}}
{{- template "common_attribute" .GeneratorObjectAttribute }}
{{- if gt (len .GeneratorObjectAttribute.Validators) 0 }}
Validators: []validator.Object{
Expand Down
Loading

0 comments on commit 668c420

Please sign in to comment.