From 8d8a35119bd9319ba1ddf3e5055a19eefbd20c4b Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 4 Oct 2023 13:13:25 +0100 Subject: [PATCH 01/19] Refactoring to move generation of to/from functions to attributes and blocks --- .../list_nested_attribute.go | 22 +- .../datasource_generate/list_nested_block.go | 20 ++ .../map_nested_attribute.go | 20 ++ .../set_nested_attribute.go | 20 ++ .../datasource_generate/set_nested_block.go | 20 ++ .../single_nested_attribute.go | 20 ++ .../single_nested_block.go | 20 ++ .../list_nested_attribute.go | 20 ++ .../provider_generate/list_nested_block.go | 20 ++ .../provider_generate/map_nested_attribute.go | 20 ++ .../provider_generate/set_nested_attribute.go | 20 ++ .../provider_generate/set_nested_block.go | 20 ++ .../single_nested_attribute.go | 20 ++ .../provider_generate/single_nested_block.go | 20 ++ .../list_nested_attribute.go | 20 ++ .../resource_generate/list_nested_block.go | 20 ++ .../resource_generate/map_nested_attribute.go | 20 ++ .../resource_generate/set_nested_attribute.go | 20 ++ .../resource_generate/set_nested_block.go | 20 ++ .../single_nested_attribute.go | 20 ++ .../resource_generate/single_nested_block.go | 20 ++ internal/schema/associated_external_type.go | 24 ++ internal/schema/attributes.go | 50 +++ internal/schema/blocks.go | 50 +++ internal/schema/embed.go | 6 + internal/schema/schema.go | 302 +----------------- internal/schema/templates/object_from.gotmpl | 15 + internal/schema/templates/object_to.gotmpl | 22 ++ internal/schema/to_from_object.go | 116 +++++++ internal/schema/types.go | 4 + internal/templates/embed.go | 3 - internal/templates/to_from.gotmpl | 38 --- 32 files changed, 715 insertions(+), 337 deletions(-) create mode 100644 internal/schema/templates/object_from.gotmpl create mode 100644 internal/schema/templates/object_to.gotmpl create mode 100644 internal/schema/to_from_object.go delete mode 100644 internal/templates/to_from.gotmpl diff --git a/internal/datasource_generate/list_nested_attribute.go b/internal/datasource_generate/list_nested_attribute.go index 595d7798..5cf79ba7 100644 --- a/internal/datasource_generate/list_nested_attribute.go +++ b/internal/datasource_generate/list_nested_attribute.go @@ -188,7 +188,7 @@ func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, e attributeKeys := g.NestedObject.Attributes.SortedKeys() // Recursively call CustomTypeAndValue() for each attribute that implements - // CustomTypeAndValue interface (i.e, nested attributes). + // CustomTypeAndValue interface. for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(generatorschema.CustomTypeAndValue); ok { b, err := c.CustomTypeAndValue(k) @@ -203,3 +203,23 @@ func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, e return buf.Bytes(), nil } + +func (g GeneratorListNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/datasource_generate/list_nested_block.go b/internal/datasource_generate/list_nested_block.go index 2f2df0d0..fefd47bf 100644 --- a/internal/datasource_generate/list_nested_block.go +++ b/internal/datasource_generate/list_nested_block.go @@ -281,3 +281,23 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error return buf.Bytes(), nil } + +func (g GeneratorListNestedBlock) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/datasource_generate/map_nested_attribute.go b/internal/datasource_generate/map_nested_attribute.go index c8794d9f..e0801036 100644 --- a/internal/datasource_generate/map_nested_attribute.go +++ b/internal/datasource_generate/map_nested_attribute.go @@ -203,3 +203,23 @@ func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } + +func (g GeneratorMapNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/datasource_generate/set_nested_attribute.go b/internal/datasource_generate/set_nested_attribute.go index d8cb9623..8965a4e5 100644 --- a/internal/datasource_generate/set_nested_attribute.go +++ b/internal/datasource_generate/set_nested_attribute.go @@ -203,3 +203,23 @@ func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } + +func (g GeneratorSetNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/datasource_generate/set_nested_block.go b/internal/datasource_generate/set_nested_block.go index 2be58ef6..8a71776c 100644 --- a/internal/datasource_generate/set_nested_block.go +++ b/internal/datasource_generate/set_nested_block.go @@ -281,3 +281,23 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) return buf.Bytes(), nil } + +func (g GeneratorSetNestedBlock) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/datasource_generate/single_nested_attribute.go b/internal/datasource_generate/single_nested_attribute.go index e7101150..3d934242 100644 --- a/internal/datasource_generate/single_nested_attribute.go +++ b/internal/datasource_generate/single_nested_attribute.go @@ -206,3 +206,23 @@ func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, return buf.Bytes(), nil } + +func (g GeneratorSingleNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.Attributes.ToFuncs() + + fromFuncs := g.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/datasource_generate/single_nested_block.go b/internal/datasource_generate/single_nested_block.go index 74c8da8e..7b8be25d 100644 --- a/internal/datasource_generate/single_nested_block.go +++ b/internal/datasource_generate/single_nested_block.go @@ -295,3 +295,23 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err return buf.Bytes(), nil } + +func (g GeneratorSingleNestedBlock) ToFrom(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.Attributes.ToFuncs() + + fromFuncs := g.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/list_nested_attribute.go b/internal/provider_generate/list_nested_attribute.go index beceb34f..e5f55889 100644 --- a/internal/provider_generate/list_nested_attribute.go +++ b/internal/provider_generate/list_nested_attribute.go @@ -203,3 +203,23 @@ func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, e return buf.Bytes(), nil } + +func (g GeneratorListNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/list_nested_block.go b/internal/provider_generate/list_nested_block.go index 028c295a..aa85f559 100644 --- a/internal/provider_generate/list_nested_block.go +++ b/internal/provider_generate/list_nested_block.go @@ -281,3 +281,23 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error return buf.Bytes(), nil } + +func (g GeneratorListNestedBlock) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/map_nested_attribute.go b/internal/provider_generate/map_nested_attribute.go index 96b3fde8..d943e814 100644 --- a/internal/provider_generate/map_nested_attribute.go +++ b/internal/provider_generate/map_nested_attribute.go @@ -203,3 +203,23 @@ func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } + +func (g GeneratorMapNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/set_nested_attribute.go b/internal/provider_generate/set_nested_attribute.go index 5ce1fc66..44bc48cb 100644 --- a/internal/provider_generate/set_nested_attribute.go +++ b/internal/provider_generate/set_nested_attribute.go @@ -203,3 +203,23 @@ func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } + +func (g GeneratorSetNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/set_nested_block.go b/internal/provider_generate/set_nested_block.go index d89ab3ea..6d58acff 100644 --- a/internal/provider_generate/set_nested_block.go +++ b/internal/provider_generate/set_nested_block.go @@ -281,3 +281,23 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) return buf.Bytes(), nil } + +func (g GeneratorSetNestedBlock) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/single_nested_attribute.go b/internal/provider_generate/single_nested_attribute.go index eda5be9a..72d7e815 100644 --- a/internal/provider_generate/single_nested_attribute.go +++ b/internal/provider_generate/single_nested_attribute.go @@ -206,3 +206,23 @@ func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, return buf.Bytes(), nil } + +func (g GeneratorSingleNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.Attributes.ToFuncs() + + fromFuncs := g.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/single_nested_block.go b/internal/provider_generate/single_nested_block.go index e9b7b6c0..03bbe62c 100644 --- a/internal/provider_generate/single_nested_block.go +++ b/internal/provider_generate/single_nested_block.go @@ -295,3 +295,23 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err return buf.Bytes(), nil } + +func (g GeneratorSingleNestedBlock) ToFrom(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.Attributes.ToFuncs() + + fromFuncs := g.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/list_nested_attribute.go b/internal/resource_generate/list_nested_attribute.go index e5fb5b8a..d5163b53 100644 --- a/internal/resource_generate/list_nested_attribute.go +++ b/internal/resource_generate/list_nested_attribute.go @@ -228,3 +228,23 @@ func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, e return buf.Bytes(), nil } + +func (g GeneratorListNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/list_nested_block.go b/internal/resource_generate/list_nested_block.go index 2ff39ecb..25d86167 100644 --- a/internal/resource_generate/list_nested_block.go +++ b/internal/resource_generate/list_nested_block.go @@ -298,3 +298,23 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error return buf.Bytes(), nil } + +func (g GeneratorListNestedBlock) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/map_nested_attribute.go b/internal/resource_generate/map_nested_attribute.go index ec1c721b..33d02eeb 100644 --- a/internal/resource_generate/map_nested_attribute.go +++ b/internal/resource_generate/map_nested_attribute.go @@ -228,3 +228,23 @@ func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } + +func (g GeneratorMapNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/set_nested_attribute.go b/internal/resource_generate/set_nested_attribute.go index 7c22081b..2d3468b6 100644 --- a/internal/resource_generate/set_nested_attribute.go +++ b/internal/resource_generate/set_nested_attribute.go @@ -228,3 +228,23 @@ func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } + +func (g GeneratorSetNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/set_nested_block.go b/internal/resource_generate/set_nested_block.go index 41e30f08..6a69d1a0 100644 --- a/internal/resource_generate/set_nested_block.go +++ b/internal/resource_generate/set_nested_block.go @@ -296,3 +296,23 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) return buf.Bytes(), nil } + +func (g GeneratorSetNestedBlock) ToFrom(name string) ([]byte, error) { + if g.NestedObject.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.NestedObject.Attributes.ToFuncs() + + fromFuncs := g.NestedObject.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.NestedObject.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/single_nested_attribute.go b/internal/resource_generate/single_nested_attribute.go index 92b12f05..9e9c072c 100644 --- a/internal/resource_generate/single_nested_attribute.go +++ b/internal/resource_generate/single_nested_attribute.go @@ -226,3 +226,23 @@ func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, return buf.Bytes(), nil } + +func (g GeneratorSingleNestedAttribute) ToFrom(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.Attributes.ToFuncs() + + fromFuncs := g.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/single_nested_block.go b/internal/resource_generate/single_nested_block.go index c98b1cd9..78fce8b3 100644 --- a/internal/resource_generate/single_nested_block.go +++ b/internal/resource_generate/single_nested_block.go @@ -305,3 +305,23 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err return buf.Bytes(), nil } + +func (g GeneratorSingleNestedBlock) ToFrom(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFuncs := g.Attributes.ToFuncs() + + fromFuncs := g.Attributes.FromFuncs() + + toFrom := generatorschema.NewToFromObject(name, g.AssociatedExternalType, toFuncs, fromFuncs) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/schema/associated_external_type.go b/internal/schema/associated_external_type.go index 80a7b330..6a043ec1 100644 --- a/internal/schema/associated_external_type.go +++ b/internal/schema/associated_external_type.go @@ -75,3 +75,27 @@ func (a *AssocExtType) Equal(other *AssocExtType) bool { return a.AssociatedExternalType.Equal(other.AssociatedExternalType) } + +func (a *AssocExtType) ToPascalCase() string { + inputSplit := strings.Split(a.TypeReference(), ".") + + var ucName string + + for _, v := range inputSplit { + if len(v) < 1 { + continue + } + + firstChar := v[0:1] + ucFirstChar := strings.ToUpper(firstChar) + + if len(v) < 2 { + ucName += ucFirstChar + continue + } + + ucName += ucFirstChar + v[1:] + } + + return ucName +} diff --git a/internal/schema/attributes.go b/internal/schema/attributes.go index f4f5fa8f..0658b928 100644 --- a/internal/schema/attributes.go +++ b/internal/schema/attributes.go @@ -168,6 +168,31 @@ func (g GeneratorAttributes) AttrValues() (map[string]string, error) { return attrValues, nil } +// FromFuncs returns a mapping of attribute names to string representations of the +// function that converts a Go value to a framework value. +func (g GeneratorAttributes) FromFuncs() map[string]string { + attributeKeys := g.SortedKeys() + + fromFuncs := make(map[string]string, len(g)) + + for _, k := range attributeKeys { + switch g[k].GeneratorSchemaType() { + case GeneratorBoolAttribute: + fromFuncs[k] = "BoolPointerValue" + case GeneratorFloat64Attribute: + fromFuncs[k] = "Float64PointerValue" + case GeneratorInt64Attribute: + fromFuncs[k] = "Int64PointerValue" + case GeneratorNumberAttribute: + fromFuncs[k] = "NumberValue" + case GeneratorStringAttribute: + fromFuncs[k] = "StringPointerValue" + } + } + + return fromFuncs +} + func (g GeneratorAttributes) Schema() (string, error) { var s strings.Builder @@ -197,6 +222,31 @@ func (g GeneratorAttributes) Schema() (string, error) { return s.String(), nil } +// ToFuncs returns a mapping of attribute names to string representations of the +// function that converts a framework value to a Go value. +func (g GeneratorAttributes) ToFuncs() map[string]string { + attributeKeys := g.SortedKeys() + + toFuncs := make(map[string]string, len(g)) + + for _, k := range attributeKeys { + switch g[k].GeneratorSchemaType() { + case GeneratorBoolAttribute: + toFuncs[k] = "ValueBoolPointer" + case GeneratorFloat64Attribute: + toFuncs[k] = "ValueFloat64Pointer" + case GeneratorInt64Attribute: + toFuncs[k] = "ValueInt64Pointer" + case GeneratorNumberAttribute: + toFuncs[k] = "ValueBigFloat" + case GeneratorStringAttribute: + toFuncs[k] = "ValueStringPointer" + } + } + + return toFuncs +} + func (g GeneratorAttributes) SortedKeys() []string { var attributeKeys = make([]string, 0, len(g)) diff --git a/internal/schema/blocks.go b/internal/schema/blocks.go index f6d1a8aa..774946dd 100644 --- a/internal/schema/blocks.go +++ b/internal/schema/blocks.go @@ -76,6 +76,31 @@ func (g GeneratorBlocks) AttrValues() (map[string]string, error) { return attrValues, nil } +// FromFuncs returns a mapping of block names to string representations of the +// function that converts a Go value to a framework value. +func (g GeneratorBlocks) FromFuncs() map[string]string { + attributeKeys := g.SortedKeys() + + fromFuncs := make(map[string]string, len(g)) + + for _, k := range attributeKeys { + switch g[k].GeneratorSchemaType() { + case GeneratorBoolAttribute: + fromFuncs[k] = "BoolPointerValue" + case GeneratorFloat64Attribute: + fromFuncs[k] = "Float64PointerValue" + case GeneratorInt64Attribute: + fromFuncs[k] = "Int64PointerValue" + case GeneratorNumberAttribute: + fromFuncs[k] = "NumberValue" + case GeneratorStringAttribute: + fromFuncs[k] = "StringPointerValue" + } + } + + return fromFuncs +} + func (g GeneratorBlocks) Schema() (string, error) { var s strings.Builder @@ -105,6 +130,31 @@ func (g GeneratorBlocks) Schema() (string, error) { return s.String(), nil } +// ToFuncs returns a mapping of block names to string representations of the +// function that converts a framework value to a Go value. +func (g GeneratorBlocks) ToFuncs() map[string]string { + attributeKeys := g.SortedKeys() + + toFuncs := make(map[string]string, len(g)) + + for _, k := range attributeKeys { + switch g[k].GeneratorSchemaType() { + case GeneratorBoolAttribute: + toFuncs[k] = "ValueBoolPointer" + case GeneratorFloat64Attribute: + toFuncs[k] = "ValueFloat64Pointer" + case GeneratorInt64Attribute: + toFuncs[k] = "ValueInt64Pointer" + case GeneratorNumberAttribute: + toFuncs[k] = "ValueBigFloat" + case GeneratorStringAttribute: + toFuncs[k] = "ValueStringPointer" + } + } + + return toFuncs +} + func (g GeneratorBlocks) SortedKeys() []string { var blockKeys = make([]string, 0, len(g)) diff --git a/internal/schema/embed.go b/internal/schema/embed.go index dac60392..13b6ce98 100644 --- a/internal/schema/embed.go +++ b/internal/schema/embed.go @@ -7,6 +7,12 @@ import ( _ "embed" ) +//go:embed templates/object_from.gotmpl +var ObjectFromTemplate string + +//go:embed templates/object_to.gotmpl +var ObjectToTemplate string + //go:embed templates/object_type_equal.gotmpl var ObjectTypeEqualTemplate string diff --git a/internal/schema/schema.go b/internal/schema/schema.go index a3d226d4..4b4ad778 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -7,7 +7,6 @@ import ( "bytes" "errors" "fmt" - "sort" "strings" "text/template" @@ -292,111 +291,15 @@ func (g GeneratorSchema) ModelsToFromBytes() ([]byte, error) { continue } - // Only process attributes implementing GeneratorAttributeAssocExtType. - var attributeAssocExtType GeneratorAttributeAssocExtType - var ok bool + if t, ok := g.Attributes[k].(ToFrom); ok { + b, err := t.ToFrom(k) - if attributeAssocExtType, ok = g.Attributes[k].(GeneratorAttributeAssocExtType); !ok { - continue - } - - // Only process if AssocExtType() is not nil. - assocExtType := attributeAssocExtType.AssocExtType() - - if assocExtType == nil { - continue - } - - // Only process if attribute implements Attributes (i.e., list, map, set, single - // nested attributes). - a, ok := g.Attributes[k].(Attributes) - - if !ok { - continue - } - - var fields []objectField - - attributeAttributes := a.GetAttributes() - - // Using sorted attributeKeys to guarantee attribute order as maps are unordered in Go. - var attributeAttributeKeys = make([]string, 0, len(attributeAttributes)) - - for aa := range attributeAttributes { - attributeAttributeKeys = append(attributeAttributeKeys, aa) - } - - sort.Strings(attributeAttributeKeys) - - for _, x := range attributeAttributeKeys { - name := FrameworkIdentifier(x) - - switch attributeAttributes[x].GeneratorSchemaType() { - case GeneratorBoolAttribute: - fields = append(fields, boolObjectField(name.ToPascalCase())) - case GeneratorFloat64Attribute: - fields = append(fields, float64ObjectField(name.ToPascalCase())) - case GeneratorInt64Attribute: - fields = append(fields, int64ObjectField(name.ToPascalCase())) - case GeneratorNumberAttribute: - fields = append(fields, numberObjectField(name.ToPascalCase())) - case GeneratorStringAttribute: - fields = append(fields, stringObjectField(name.ToPascalCase())) - } - } - - var t *template.Template - var err error - - switch attributeAssocExtType.GeneratorSchemaType() { - case GeneratorListNestedAttribute: - t, err = template.New("to_from").Parse(templates.ToFromTemplate) - if err != nil { - return nil, err - } - case GeneratorMapNestedAttribute: - t, err = template.New("to_from").Parse(templates.ToFromTemplate) if err != nil { return nil, err } - case GeneratorSetNestedAttribute: - t, err = template.New("to_from").Parse(templates.ToFromTemplate) - if err != nil { - return nil, err - } - case GeneratorSingleNestedAttribute: - t, err = template.New("to_from").Parse(templates.ToFromTemplate) - if err != nil { - return nil, err - } - } - if t == nil { - return nil, fmt.Errorf("no matching template for type: %T", attributeAssocExtType.GeneratorSchemaType()) - } - - var templateBuf bytes.Buffer - - templateData := struct { - Name string - Type string - TypeReference string - TypeName string - Fields []objectField - }{ - Name: FrameworkIdentifier(k).ToPascalCase(), - Type: assocExtType.Type(), - TypeReference: assocExtType.TypeReference(), - TypeName: dotNotationToPascalCase(assocExtType.TypeReference()), - Fields: fields, - } - - err = t.Execute(&templateBuf, templateData) - if err != nil { - return nil, err + buf.Write(b) } - - buf.Write(templateBuf.Bytes()) } blockKeys := g.Blocks.SortedKeys() @@ -406,191 +309,24 @@ func (g GeneratorSchema) ModelsToFromBytes() ([]byte, error) { continue } - // Only process blocks implementing GeneratorBlockAssocExtType. - var blockAssocExtType GeneratorBlockAssocExtType - var ok bool - - if blockAssocExtType, ok = g.Blocks[k].(GeneratorBlockAssocExtType); !ok { - continue - } - - // Only process if AssocExtType() is not nil. - assocExtType := blockAssocExtType.AssocExtType() - - if assocExtType == nil { - continue - } - - // Only process if block implements Attributes (i.e., list, set, single - // nested blocks). - a, ok := g.Blocks[k].(Attributes) - - if !ok { + if g.Blocks[k] == nil { continue } - var fields []objectField - - blockAttributes := a.GetAttributes() - - // Using sorted blockKeys to guarantee block order as maps are unordered in Go. - var blockAttributeKeys = make([]string, 0, len(blockAttributes)) - - for ba := range blockAttributes { - blockAttributeKeys = append(blockAttributeKeys, ba) - } - - sort.Strings(blockAttributeKeys) - - for _, x := range blockAttributeKeys { - name := FrameworkIdentifier(x) - - switch blockAttributes[x].GeneratorSchemaType() { - case GeneratorBoolAttribute: - fields = append(fields, boolObjectField(name.ToPascalCase())) - case GeneratorFloat64Attribute: - fields = append(fields, float64ObjectField(name.ToPascalCase())) - case GeneratorInt64Attribute: - fields = append(fields, int64ObjectField(name.ToPascalCase())) - case GeneratorNumberAttribute: - fields = append(fields, numberObjectField(name.ToPascalCase())) - case GeneratorStringAttribute: - fields = append(fields, stringObjectField(name.ToPascalCase())) - } - } - - var t *template.Template - var err error + if t, ok := g.Blocks[k].(ToFrom); ok { + b, err := t.ToFrom(k) - switch blockAssocExtType.GeneratorSchemaType() { - case GeneratorListNestedBlock: - t, err = template.New("to_from").Parse(templates.ToFromTemplate) - if err != nil { - return nil, err - } - case GeneratorSetNestedBlock: - t, err = template.New("to_from").Parse(templates.ToFromTemplate) if err != nil { return nil, err } - case GeneratorSingleNestedBlock: - t, err = template.New("to_from").Parse(templates.ToFromTemplate) - if err != nil { - return nil, err - } - } - - if t == nil { - return nil, fmt.Errorf("no matching template for type: %T", blockAssocExtType.GeneratorSchemaType()) - } - - var templateBuf bytes.Buffer - - templateData := struct { - Name string - Type string - TypeReference string - TypeName string - Fields []objectField - }{ - Name: FrameworkIdentifier(k).ToPascalCase(), - Type: assocExtType.Type(), - TypeReference: assocExtType.TypeReference(), - TypeName: dotNotationToPascalCase(assocExtType.TypeReference()), - Fields: fields, - } - err = t.Execute(&templateBuf, templateData) - if err != nil { - return nil, err + buf.Write(b) } - - buf.Write(templateBuf.Bytes()) } return buf.Bytes(), nil } -type field struct { - DefaultTo string - DefaultFrom string -} - -type objectField struct { - Name string - field -} - -func boolField() field { - return field{ - DefaultTo: "ValueBoolPointer", - DefaultFrom: "BoolPointerValue", - } -} - -func int64Field() field { - return field{ - DefaultTo: "ValueInt64Pointer", - DefaultFrom: "Int64PointerValue", - } -} - -func float64Field() field { - return field{ - DefaultTo: "ValueFloat64Pointer", - DefaultFrom: "Float64PointerValue", - } -} - -func numberField() field { - return field{ - DefaultTo: "ValueBigFloat", - DefaultFrom: "NumberValue", - } -} - -func stringField() field { - return field{ - DefaultTo: "ValueStringPointer", - DefaultFrom: "StringPointerValue", - } -} - -func boolObjectField(name string) objectField { - return objectField{ - Name: name, - field: boolField(), - } -} - -func int64ObjectField(name string) objectField { - return objectField{ - Name: name, - field: int64Field(), - } -} - -func float64ObjectField(name string) objectField { - return objectField{ - Name: name, - field: float64Field(), - } -} - -func numberObjectField(name string) objectField { - return objectField{ - Name: name, - field: numberField(), - } -} - -func stringObjectField(name string) objectField { - return objectField{ - Name: name, - field: stringField(), - } -} - func ElementTypeString(elementType specschema.ElementType) (string, error) { switch { case elementType.Bool != nil: @@ -676,27 +412,3 @@ func AttrTypesString(attrTypes specschema.ObjectAttributeTypes) (string, error) return strings.Join(attrTypesStr, ",\n"), nil } - -func dotNotationToPascalCase(input string) string { - inputSplit := strings.Split(input, ".") - - var ucName string - - for _, v := range inputSplit { - if len(v) < 1 { - continue - } - - firstChar := v[0:1] - ucFirstChar := strings.ToUpper(firstChar) - - if len(v) < 2 { - ucName += ucFirstChar - continue - } - - ucName += ucFirstChar + v[1:] - } - - return ucName -} diff --git a/internal/schema/templates/object_from.gotmpl b/internal/schema/templates/object_from.gotmpl new file mode 100644 index 00000000..c1face19 --- /dev/null +++ b/internal/schema/templates/object_from.gotmpl @@ -0,0 +1,15 @@ + +func (v {{.Name}}Value) From{{.AssocExtType.ToPascalCase}}(ctx context.Context, apiObject {{.AssocExtType.Type}}) ({{.Name}}Value, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return New{{.Name}}ValueNull(), diags +} + +return {{.Name}}Value{ +{{- range $key, $value := .FromFuncs }} +{{$key.ToPascalCase}}: types.{{$value}}(apiObject.{{$key.ToPascalCase}}), +{{- end}} +state: attr.ValueStateKnown, +}, diags +} diff --git a/internal/schema/templates/object_to.gotmpl b/internal/schema/templates/object_to.gotmpl new file mode 100644 index 00000000..0f11cf63 --- /dev/null +++ b/internal/schema/templates/object_to.gotmpl @@ -0,0 +1,22 @@ +func (v {{.Name}}Value) To{{.AssocExtType.ToPascalCase}}(ctx context.Context) ({{.AssocExtType.Type}}, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"{{.Name}}Value Value Is Unknown", +`"{{.Name}}Value" is unknown.`, +)) + +return nil, diags +} + +return &{{.AssocExtType.TypeReference}}{ +{{- range $key, $value := .ToFuncs }} +{{$key.ToPascalCase}}: v.{{$key.ToPascalCase}}.{{$value}}(), +{{- end}} +}, diags +} \ No newline at end of file diff --git a/internal/schema/to_from_object.go b/internal/schema/to_from_object.go new file mode 100644 index 00000000..8bb83fd4 --- /dev/null +++ b/internal/schema/to_from_object.go @@ -0,0 +1,116 @@ +package schema + +import ( + "bytes" + "text/template" +) + +type ToFromObject struct { + Name FrameworkIdentifier + AssocExtType *AssocExtType + FromFuncs map[FrameworkIdentifier]string + ToFuncs map[FrameworkIdentifier]string + templates map[string]string +} + +func NewToFromObject(name string, assocExtType *AssocExtType, toFuncs, fromFuncs map[string]string) ToFromObject { + t := map[string]string{ + "from": ObjectFromTemplate, + "to": ObjectToTemplate, + } + + tf := make(map[FrameworkIdentifier]string, len(toFuncs)) + + for k, v := range toFuncs { + tf[FrameworkIdentifier(k)] = v + } + + ff := make(map[FrameworkIdentifier]string, len(fromFuncs)) + + for k, v := range fromFuncs { + ff[FrameworkIdentifier(k)] = v + } + + return ToFromObject{ + Name: FrameworkIdentifier(name), + AssocExtType: assocExtType, + FromFuncs: ff, + ToFuncs: tf, + templates: t, + } +} + +func (o ToFromObject) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + o.renderTo, + o.renderFrom, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (o ToFromObject) renderTo() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["to"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + ToFuncs map[FrameworkIdentifier]string + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + ToFuncs: o.ToFuncs, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (o ToFromObject) renderFrom() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["from"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + FromFuncs map[FrameworkIdentifier]string + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + FromFuncs: o.FromFuncs, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/internal/schema/types.go b/internal/schema/types.go index 9598537a..27d26ba1 100644 --- a/internal/schema/types.go +++ b/internal/schema/types.go @@ -56,6 +56,10 @@ type GeneratorBlockAssocExtType interface { AssocExtType() *AssocExtType } +type ToFrom interface { + ToFrom(name string) ([]byte, error) +} + type Type int64 const ( diff --git a/internal/templates/embed.go b/internal/templates/embed.go index a3328bc7..01b05ed3 100644 --- a/internal/templates/embed.go +++ b/internal/templates/embed.go @@ -9,6 +9,3 @@ import ( //go:embed schema.gotmpl var SchemaGoTemplate string - -//go:embed to_from.gotmpl -var ToFromTemplate string diff --git a/internal/templates/to_from.gotmpl b/internal/templates/to_from.gotmpl deleted file mode 100644 index cd1f3a88..00000000 --- a/internal/templates/to_from.gotmpl +++ /dev/null @@ -1,38 +0,0 @@ - -func (v {{.Name}}Value) To{{.TypeName}}(ctx context.Context) ({{.Type}}, diag.Diagnostics) { -var diags diag.Diagnostics - -if v.IsNull() { -return nil, diags -} - -if v.IsUnknown() { -diags.Append(diag.NewErrorDiagnostic( -"{{.Name}}Value Value Is Unknown", -`"{{.Name}}Value" is unknown.`, -)) - -return nil, diags -} - -return &{{.TypeReference}}{ -{{- range $field := .Fields }} -{{$field.Name}}: v.{{$field.Name}}.{{$field.DefaultTo}}(), -{{- end}} -}, diags -} - -func (v {{.Name}}Value) From{{.TypeName}}(ctx context.Context, apiObject {{.Type}}) ({{.Name}}Value, diag.Diagnostics) { -var diags diag.Diagnostics - -if apiObject == nil { -return New{{.Name}}ValueNull(), diags -} - -return {{.Name}}Value{ -{{- range $field := .Fields }} -{{$field.Name}}: types.{{$field.DefaultFrom}}(apiObject.{{$field.Name}}), -{{- end}} -state: attr.ValueStateKnown, -}, diags -} From 9120230b61ef3b9aaa2137784ca1bf22f4ea2ef0 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 4 Oct 2023 13:15:33 +0100 Subject: [PATCH 02/19] Moving schema.gotmpl --- internal/schema/embed.go | 3 +++ internal/schema/schema.go | 3 +-- internal/{ => schema}/templates/schema.gotmpl | 0 internal/templates/embed.go | 11 ----------- 4 files changed, 4 insertions(+), 13 deletions(-) rename internal/{ => schema}/templates/schema.gotmpl (100%) delete mode 100644 internal/templates/embed.go diff --git a/internal/schema/embed.go b/internal/schema/embed.go index 13b6ce98..da7a5fe8 100644 --- a/internal/schema/embed.go +++ b/internal/schema/embed.go @@ -75,3 +75,6 @@ var ObjectValueValuableTemplate string //go:embed templates/object_value_value.gotmpl var ObjectValueValueTemplate string + +//go:embed templates/schema.gotmpl +var SchemaGoTemplate string diff --git a/internal/schema/schema.go b/internal/schema/schema.go index 4b4ad778..7d793756 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -14,7 +14,6 @@ import ( specschema "github.com/hashicorp/terraform-plugin-codegen-spec/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" - "github.com/hashicorp/terraform-plugin-codegen-framework/internal/templates" ) type GeneratorSchema struct { @@ -156,7 +155,7 @@ func (g GeneratorSchema) SchemaBytes(name, packageName, generatorType string) ([ } t, err := template.New("schema").Parse( - templates.SchemaGoTemplate, + SchemaGoTemplate, ) if err != nil { diff --git a/internal/templates/schema.gotmpl b/internal/schema/templates/schema.gotmpl similarity index 100% rename from internal/templates/schema.gotmpl rename to internal/schema/templates/schema.gotmpl diff --git a/internal/templates/embed.go b/internal/templates/embed.go deleted file mode 100644 index 01b05ed3..00000000 --- a/internal/templates/embed.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package templates - -import ( - _ "embed" -) - -//go:embed schema.gotmpl -var SchemaGoTemplate string From 5eb6acb5c405113aca3e82a36592f5640709e7a1 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 4 Oct 2023 13:27:13 +0100 Subject: [PATCH 03/19] Renaming interface method --- internal/cmd/generate_data_sources.go | 6 +++--- internal/cmd/generate_provider.go | 6 +++--- internal/cmd/generate_resources.go | 6 +++--- .../datasource_generate/list_nested_attribute.go | 2 +- internal/datasource_generate/list_nested_block.go | 2 +- .../datasource_generate/map_nested_attribute.go | 2 +- .../datasource_generate/set_nested_attribute.go | 2 +- internal/datasource_generate/set_nested_block.go | 2 +- .../datasource_generate/single_nested_attribute.go | 2 +- internal/datasource_generate/single_nested_block.go | 2 +- internal/provider_generate/list_nested_attribute.go | 2 +- internal/provider_generate/list_nested_block.go | 2 +- internal/provider_generate/map_nested_attribute.go | 2 +- internal/provider_generate/set_nested_attribute.go | 2 +- internal/provider_generate/set_nested_block.go | 2 +- .../provider_generate/single_nested_attribute.go | 2 +- internal/provider_generate/single_nested_block.go | 2 +- internal/resource_generate/list_nested_attribute.go | 2 +- internal/resource_generate/list_nested_block.go | 2 +- internal/resource_generate/map_nested_attribute.go | 2 +- internal/resource_generate/set_nested_attribute.go | 2 +- internal/resource_generate/set_nested_block.go | 2 +- .../resource_generate/single_nested_attribute.go | 2 +- internal/resource_generate/single_nested_block.go | 2 +- internal/schema/schema.go | 13 ++++++------- internal/schema/schemas.go | 4 ++-- internal/schema/to_from_object.go | 3 +++ internal/schema/types.go | 2 +- 28 files changed, 42 insertions(+), 40 deletions(-) diff --git a/internal/cmd/generate_data_sources.go b/internal/cmd/generate_data_sources.go index 3b077248..2ff8cd05 100644 --- a/internal/cmd/generate_data_sources.go +++ b/internal/cmd/generate_data_sources.go @@ -153,7 +153,7 @@ func generateDataSourceCode(spec spec.Specification, outputPath, packageName, ge } // generate "expand" and "flatten" code - modelsToFromBytes, err := g.ModelsToFromBytes() + toFromFunctions, err := g.ToFromFunctions() if err != nil { log.Fatal(err) } @@ -177,13 +177,13 @@ func generateDataSourceCode(spec spec.Specification, outputPath, packageName, ge } // format "expand" and "flatten" code - formattedDataSourcesToFrom, err := format.Format(modelsToFromBytes) + formattedToFromFunctions, err := format.Format(toFromFunctions) if err != nil { log.Fatal(err) } // write code - err = output.WriteDataSources(formattedDataSourcesSchema, formattedDataSourcesModels, formattedCustomTypeValue, formattedDataSourcesToFrom, outputPath, packageName) + err = output.WriteDataSources(formattedDataSourcesSchema, formattedDataSourcesModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) if err != nil { return fmt.Errorf("error writing Go code to output: %w", err) } diff --git a/internal/cmd/generate_provider.go b/internal/cmd/generate_provider.go index 31472c31..f3c2c928 100644 --- a/internal/cmd/generate_provider.go +++ b/internal/cmd/generate_provider.go @@ -153,7 +153,7 @@ func generateProviderCode(spec spec.Specification, outputPath, packageName, gene } // generate "expand" and "flatten" code - modelsToFromBytes, err := g.ModelsToFromBytes() + toFromFunctions, err := g.ToFromFunctions() if err != nil { log.Fatal(err) } @@ -177,13 +177,13 @@ func generateProviderCode(spec spec.Specification, outputPath, packageName, gene } // format "expand" and "flatten" code - formattedProviderToFrom, err := format.Format(modelsToFromBytes) + formattedToFromFunctions, err := format.Format(toFromFunctions) if err != nil { log.Fatal(err) } // write code - err = output.WriteProviders(formattedProvidersSchema, formattedProvidersModels, formattedCustomTypeValue, formattedProviderToFrom, outputPath, packageName) + err = output.WriteProviders(formattedProvidersSchema, formattedProvidersModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) if err != nil { return fmt.Errorf("error writing Go code to output: %w", err) } diff --git a/internal/cmd/generate_resources.go b/internal/cmd/generate_resources.go index 59517301..1ba3645c 100644 --- a/internal/cmd/generate_resources.go +++ b/internal/cmd/generate_resources.go @@ -153,7 +153,7 @@ func generateResourceCode(spec spec.Specification, outputPath, packageName, gene } // generate "expand" and "flatten" code - modelsToFromBytes, err := g.ModelsToFromBytes() + toFromFunctions, err := g.ToFromFunctions() if err != nil { log.Fatal(err) } @@ -177,13 +177,13 @@ func generateResourceCode(spec spec.Specification, outputPath, packageName, gene } // format "expand" and "flatten" code - formattedResourcesToFrom, err := format.Format(modelsToFromBytes) + formattedToFromFunctions, err := format.Format(toFromFunctions) if err != nil { log.Fatal(err) } // write code - err = output.WriteResources(formattedResourcesSchema, formattedResourcesModels, formattedCustomTypeValue, formattedResourcesToFrom, outputPath, packageName) + err = output.WriteResources(formattedResourcesSchema, formattedResourcesModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) if err != nil { return fmt.Errorf("error writing Go code to output: %w", err) } diff --git a/internal/datasource_generate/list_nested_attribute.go b/internal/datasource_generate/list_nested_attribute.go index 5cf79ba7..ee21aa49 100644 --- a/internal/datasource_generate/list_nested_attribute.go +++ b/internal/datasource_generate/list_nested_attribute.go @@ -204,7 +204,7 @@ func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, e return buf.Bytes(), nil } -func (g GeneratorListNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorListNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/datasource_generate/list_nested_block.go b/internal/datasource_generate/list_nested_block.go index fefd47bf..dc6d2692 100644 --- a/internal/datasource_generate/list_nested_block.go +++ b/internal/datasource_generate/list_nested_block.go @@ -282,7 +282,7 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error return buf.Bytes(), nil } -func (g GeneratorListNestedBlock) ToFrom(name string) ([]byte, error) { +func (g GeneratorListNestedBlock) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/datasource_generate/map_nested_attribute.go b/internal/datasource_generate/map_nested_attribute.go index e0801036..0a07bca4 100644 --- a/internal/datasource_generate/map_nested_attribute.go +++ b/internal/datasource_generate/map_nested_attribute.go @@ -204,7 +204,7 @@ func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } -func (g GeneratorMapNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorMapNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/datasource_generate/set_nested_attribute.go b/internal/datasource_generate/set_nested_attribute.go index 8965a4e5..0eb5dc33 100644 --- a/internal/datasource_generate/set_nested_attribute.go +++ b/internal/datasource_generate/set_nested_attribute.go @@ -204,7 +204,7 @@ func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } -func (g GeneratorSetNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorSetNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/datasource_generate/set_nested_block.go b/internal/datasource_generate/set_nested_block.go index 8a71776c..da255aa6 100644 --- a/internal/datasource_generate/set_nested_block.go +++ b/internal/datasource_generate/set_nested_block.go @@ -282,7 +282,7 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) return buf.Bytes(), nil } -func (g GeneratorSetNestedBlock) ToFrom(name string) ([]byte, error) { +func (g GeneratorSetNestedBlock) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/datasource_generate/single_nested_attribute.go b/internal/datasource_generate/single_nested_attribute.go index 3d934242..92022421 100644 --- a/internal/datasource_generate/single_nested_attribute.go +++ b/internal/datasource_generate/single_nested_attribute.go @@ -207,7 +207,7 @@ func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, return buf.Bytes(), nil } -func (g GeneratorSingleNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorSingleNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/datasource_generate/single_nested_block.go b/internal/datasource_generate/single_nested_block.go index 7b8be25d..66bd6558 100644 --- a/internal/datasource_generate/single_nested_block.go +++ b/internal/datasource_generate/single_nested_block.go @@ -296,7 +296,7 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err return buf.Bytes(), nil } -func (g GeneratorSingleNestedBlock) ToFrom(name string) ([]byte, error) { +func (g GeneratorSingleNestedBlock) ToFromFunctions(name string) ([]byte, error) { if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/provider_generate/list_nested_attribute.go b/internal/provider_generate/list_nested_attribute.go index e5f55889..bc91e731 100644 --- a/internal/provider_generate/list_nested_attribute.go +++ b/internal/provider_generate/list_nested_attribute.go @@ -204,7 +204,7 @@ func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, e return buf.Bytes(), nil } -func (g GeneratorListNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorListNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/provider_generate/list_nested_block.go b/internal/provider_generate/list_nested_block.go index aa85f559..550abd79 100644 --- a/internal/provider_generate/list_nested_block.go +++ b/internal/provider_generate/list_nested_block.go @@ -282,7 +282,7 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error return buf.Bytes(), nil } -func (g GeneratorListNestedBlock) ToFrom(name string) ([]byte, error) { +func (g GeneratorListNestedBlock) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/provider_generate/map_nested_attribute.go b/internal/provider_generate/map_nested_attribute.go index d943e814..d22c17da 100644 --- a/internal/provider_generate/map_nested_attribute.go +++ b/internal/provider_generate/map_nested_attribute.go @@ -204,7 +204,7 @@ func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } -func (g GeneratorMapNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorMapNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/provider_generate/set_nested_attribute.go b/internal/provider_generate/set_nested_attribute.go index 44bc48cb..79a29818 100644 --- a/internal/provider_generate/set_nested_attribute.go +++ b/internal/provider_generate/set_nested_attribute.go @@ -204,7 +204,7 @@ func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } -func (g GeneratorSetNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorSetNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/provider_generate/set_nested_block.go b/internal/provider_generate/set_nested_block.go index 6d58acff..ff7c6295 100644 --- a/internal/provider_generate/set_nested_block.go +++ b/internal/provider_generate/set_nested_block.go @@ -282,7 +282,7 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) return buf.Bytes(), nil } -func (g GeneratorSetNestedBlock) ToFrom(name string) ([]byte, error) { +func (g GeneratorSetNestedBlock) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/provider_generate/single_nested_attribute.go b/internal/provider_generate/single_nested_attribute.go index 72d7e815..426315dc 100644 --- a/internal/provider_generate/single_nested_attribute.go +++ b/internal/provider_generate/single_nested_attribute.go @@ -207,7 +207,7 @@ func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, return buf.Bytes(), nil } -func (g GeneratorSingleNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorSingleNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/provider_generate/single_nested_block.go b/internal/provider_generate/single_nested_block.go index 03bbe62c..259b4ff7 100644 --- a/internal/provider_generate/single_nested_block.go +++ b/internal/provider_generate/single_nested_block.go @@ -296,7 +296,7 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err return buf.Bytes(), nil } -func (g GeneratorSingleNestedBlock) ToFrom(name string) ([]byte, error) { +func (g GeneratorSingleNestedBlock) ToFromFunctions(name string) ([]byte, error) { if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource_generate/list_nested_attribute.go b/internal/resource_generate/list_nested_attribute.go index d5163b53..31a0e759 100644 --- a/internal/resource_generate/list_nested_attribute.go +++ b/internal/resource_generate/list_nested_attribute.go @@ -229,7 +229,7 @@ func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, e return buf.Bytes(), nil } -func (g GeneratorListNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorListNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource_generate/list_nested_block.go b/internal/resource_generate/list_nested_block.go index 25d86167..47431c53 100644 --- a/internal/resource_generate/list_nested_block.go +++ b/internal/resource_generate/list_nested_block.go @@ -299,7 +299,7 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error return buf.Bytes(), nil } -func (g GeneratorListNestedBlock) ToFrom(name string) ([]byte, error) { +func (g GeneratorListNestedBlock) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource_generate/map_nested_attribute.go b/internal/resource_generate/map_nested_attribute.go index 33d02eeb..2b8a391d 100644 --- a/internal/resource_generate/map_nested_attribute.go +++ b/internal/resource_generate/map_nested_attribute.go @@ -229,7 +229,7 @@ func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } -func (g GeneratorMapNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorMapNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource_generate/set_nested_attribute.go b/internal/resource_generate/set_nested_attribute.go index 2d3468b6..745f960d 100644 --- a/internal/resource_generate/set_nested_attribute.go +++ b/internal/resource_generate/set_nested_attribute.go @@ -229,7 +229,7 @@ func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, er return buf.Bytes(), nil } -func (g GeneratorSetNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorSetNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource_generate/set_nested_block.go b/internal/resource_generate/set_nested_block.go index 6a69d1a0..3758adc0 100644 --- a/internal/resource_generate/set_nested_block.go +++ b/internal/resource_generate/set_nested_block.go @@ -297,7 +297,7 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) return buf.Bytes(), nil } -func (g GeneratorSetNestedBlock) ToFrom(name string) ([]byte, error) { +func (g GeneratorSetNestedBlock) ToFromFunctions(name string) ([]byte, error) { if g.NestedObject.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource_generate/single_nested_attribute.go b/internal/resource_generate/single_nested_attribute.go index 9e9c072c..6f804ba8 100644 --- a/internal/resource_generate/single_nested_attribute.go +++ b/internal/resource_generate/single_nested_attribute.go @@ -227,7 +227,7 @@ func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, return buf.Bytes(), nil } -func (g GeneratorSingleNestedAttribute) ToFrom(name string) ([]byte, error) { +func (g GeneratorSingleNestedAttribute) ToFromFunctions(name string) ([]byte, error) { if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource_generate/single_nested_block.go b/internal/resource_generate/single_nested_block.go index 78fce8b3..46966046 100644 --- a/internal/resource_generate/single_nested_block.go +++ b/internal/resource_generate/single_nested_block.go @@ -306,7 +306,7 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err return buf.Bytes(), nil } -func (g GeneratorSingleNestedBlock) ToFrom(name string) ([]byte, error) { +func (g GeneratorSingleNestedBlock) ToFromFunctions(name string) ([]byte, error) { if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/schema/schema.go b/internal/schema/schema.go index 7d793756..91ef3077 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -276,11 +276,10 @@ func (g GeneratorSchema) CustomTypeValueBytes() ([]byte, error) { return buf.Bytes(), nil } -// ModelsToFromBytes generates code for expand and flatten functions. -// Whilst associated external types can be defined on any attribute -// type, the only types which are processed are list, map, set and -// single nested attributes, and list, set and single nested blocks. -func (g GeneratorSchema) ModelsToFromBytes() ([]byte, error) { +// ToFromFunctions generates code for converting to an associated +// external type from a framework type, and from an associated +// external type to a framework type. +func (g GeneratorSchema) ToFromFunctions() ([]byte, error) { var buf bytes.Buffer attributeKeys := g.Attributes.SortedKeys() @@ -291,7 +290,7 @@ func (g GeneratorSchema) ModelsToFromBytes() ([]byte, error) { } if t, ok := g.Attributes[k].(ToFrom); ok { - b, err := t.ToFrom(k) + b, err := t.ToFromFunctions(k) if err != nil { return nil, err @@ -313,7 +312,7 @@ func (g GeneratorSchema) ModelsToFromBytes() ([]byte, error) { } if t, ok := g.Blocks[k].(ToFrom); ok { - b, err := t.ToFrom(k) + b, err := t.ToFromFunctions(k) if err != nil { return nil, err diff --git a/internal/schema/schemas.go b/internal/schema/schemas.go index 833974d7..d578c4be 100644 --- a/internal/schema/schemas.go +++ b/internal/schema/schemas.go @@ -82,11 +82,11 @@ func (g GeneratorSchemas) CustomTypeValueBytes() (map[string][]byte, error) { return customTypeValueBytes, nil } -func (g GeneratorSchemas) ModelsToFromBytes() (map[string][]byte, error) { +func (g GeneratorSchemas) ToFromFunctions() (map[string][]byte, error) { modelsExpandFlattenBytes := make(map[string][]byte, len(g.schemas)) for name, s := range g.schemas { - b, err := s.ModelsToFromBytes() + b, err := s.ToFromFunctions() if err != nil { return nil, err } diff --git a/internal/schema/to_from_object.go b/internal/schema/to_from_object.go index 8bb83fd4..516e8c51 100644 --- a/internal/schema/to_from_object.go +++ b/internal/schema/to_from_object.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package schema import ( diff --git a/internal/schema/types.go b/internal/schema/types.go index 27d26ba1..a1461bf4 100644 --- a/internal/schema/types.go +++ b/internal/schema/types.go @@ -57,7 +57,7 @@ type GeneratorBlockAssocExtType interface { } type ToFrom interface { - ToFrom(name string) ([]byte, error) + ToFromFunctions(name string) ([]byte, error) } type Type int64 From c75a95cd2ffb82a9782354f992c0bb6a93ef5ed1 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 4 Oct 2023 15:56:38 +0100 Subject: [PATCH 04/19] Removing unneeded template variable --- internal/schema/schema.go | 20 ++++++++------------ internal/schema/templates/schema.gotmpl | 4 ++-- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/internal/schema/schema.go b/internal/schema/schema.go index 91ef3077..e53a6c00 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -137,26 +137,22 @@ func (g GeneratorSchema) SchemaBytes(name, packageName, generatorType string) ([ } templateData := struct { - Name string - GeneratorSchema + Name string PackageName string GeneratorType string Attributes string Blocks string Imports string }{ - Name: FrameworkIdentifier(name).ToPascalCase(), - GeneratorSchema: g, - PackageName: packageName, - GeneratorType: generatorType, - Attributes: attributes, - Blocks: blocks, - Imports: imports, + Name: FrameworkIdentifier(name).ToPascalCase(), + PackageName: packageName, + GeneratorType: generatorType, + Attributes: attributes, + Blocks: blocks, + Imports: imports, } - t, err := template.New("schema").Parse( - SchemaGoTemplate, - ) + t, err := template.New("schema").Parse(SchemaGoTemplate) if err != nil { return nil, err diff --git a/internal/schema/templates/schema.gotmpl b/internal/schema/templates/schema.gotmpl index 15c7b186..77fc102c 100644 --- a/internal/schema/templates/schema.gotmpl +++ b/internal/schema/templates/schema.gotmpl @@ -15,12 +15,12 @@ import ( func {{.Name}}{{.GeneratorType}}Schema(ctx context.Context) schema.Schema { return schema.Schema{ - {{- if gt (len .GeneratorSchema.Attributes) 0 }} + {{- if .Attributes}} Attributes: map[string]schema.Attribute{ {{- .Attributes}} }, {{- end}} - {{- if gt (len .GeneratorSchema.Blocks) 0 }} + {{- if .Blocks }} Blocks: map[string]schema.Block{ {{- .Blocks}} }, From 5ab1e983147d3f62363c0ba4ca56070f92ead122 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 4 Oct 2023 15:58:23 +0100 Subject: [PATCH 05/19] Renaming method --- internal/schema/schema.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/schema/schema.go b/internal/schema/schema.go index e53a6c00..e7871d23 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -21,7 +21,7 @@ type GeneratorSchema struct { Blocks GeneratorBlocks } -func (g GeneratorSchema) ImportsString() (string, error) { +func (g GeneratorSchema) Imports() (string, error) { imports := NewImports() for _, a := range g.Attributes { @@ -130,7 +130,7 @@ func (g GeneratorSchema) SchemaBytes(name, packageName, generatorType string) ([ return nil, err } - imports, err := g.ImportsString() + imports, err := g.Imports() if err != nil { return nil, err From e70ff492ef6464f935a200f7b6978c653a8efc47 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 4 Oct 2023 16:01:32 +0100 Subject: [PATCH 06/19] Renaming methods --- internal/cmd/generate_data_sources.go | 6 +++--- internal/cmd/generate_provider.go | 6 +++--- internal/cmd/generate_resources.go | 6 +++--- internal/schema/schema.go | 2 +- internal/schema/schemas.go | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/internal/cmd/generate_data_sources.go b/internal/cmd/generate_data_sources.go index 2ff8cd05..d0012b15 100644 --- a/internal/cmd/generate_data_sources.go +++ b/internal/cmd/generate_data_sources.go @@ -135,7 +135,7 @@ func generateDataSourceCode(spec spec.Specification, outputPath, packageName, ge // convert framework schema to []byte g := schema.NewGeneratorSchemas(s) - schemaBytes, err := g.SchemasBytes(packageName, generatorType) + schemas, err := g.Schemas(packageName, generatorType) if err != nil { return fmt.Errorf("error converting Plugin Framework schema to Go code: %w", err) } @@ -159,7 +159,7 @@ func generateDataSourceCode(spec spec.Specification, outputPath, packageName, ge } // format schema code - formattedDataSourcesSchema, err := format.Format(schemaBytes) + formattedSchemas, err := format.Format(schemas) if err != nil { return fmt.Errorf("error formatting Go code: %w", err) } @@ -183,7 +183,7 @@ func generateDataSourceCode(spec spec.Specification, outputPath, packageName, ge } // write code - err = output.WriteDataSources(formattedDataSourcesSchema, formattedDataSourcesModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) + err = output.WriteDataSources(formattedSchemas, formattedDataSourcesModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) if err != nil { return fmt.Errorf("error writing Go code to output: %w", err) } diff --git a/internal/cmd/generate_provider.go b/internal/cmd/generate_provider.go index f3c2c928..56fab9dd 100644 --- a/internal/cmd/generate_provider.go +++ b/internal/cmd/generate_provider.go @@ -135,7 +135,7 @@ func generateProviderCode(spec spec.Specification, outputPath, packageName, gene // convert framework schema to []byte g := schema.NewGeneratorSchemas(s) - schemaBytes, err := g.SchemasBytes(packageName, generatorType) + schemas, err := g.Schemas(packageName, generatorType) if err != nil { return fmt.Errorf("error converting Plugin Framework schema to Go code: %w", err) } @@ -159,7 +159,7 @@ func generateProviderCode(spec spec.Specification, outputPath, packageName, gene } // format schema code - formattedProvidersSchema, err := format.Format(schemaBytes) + formattedSchemas, err := format.Format(schemas) if err != nil { return fmt.Errorf("error formatting Go code: %w", err) } @@ -183,7 +183,7 @@ func generateProviderCode(spec spec.Specification, outputPath, packageName, gene } // write code - err = output.WriteProviders(formattedProvidersSchema, formattedProvidersModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) + err = output.WriteProviders(formattedSchemas, formattedProvidersModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) if err != nil { return fmt.Errorf("error writing Go code to output: %w", err) } diff --git a/internal/cmd/generate_resources.go b/internal/cmd/generate_resources.go index 1ba3645c..df378583 100644 --- a/internal/cmd/generate_resources.go +++ b/internal/cmd/generate_resources.go @@ -135,7 +135,7 @@ func generateResourceCode(spec spec.Specification, outputPath, packageName, gene // convert framework schema to []byte g := schema.NewGeneratorSchemas(s) - schemaBytes, err := g.SchemasBytes(packageName, generatorType) + schemas, err := g.Schemas(packageName, generatorType) if err != nil { return fmt.Errorf("error converting Plugin Framework schema to Go code: %w", err) } @@ -159,7 +159,7 @@ func generateResourceCode(spec spec.Specification, outputPath, packageName, gene } // format schema code - formattedResourcesSchema, err := format.Format(schemaBytes) + formattedSchemas, err := format.Format(schemas) if err != nil { return fmt.Errorf("error formatting Go code: %w", err) } @@ -183,7 +183,7 @@ func generateResourceCode(spec spec.Specification, outputPath, packageName, gene } // write code - err = output.WriteResources(formattedResourcesSchema, formattedResourcesModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) + err = output.WriteResources(formattedSchemas, formattedResourcesModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) if err != nil { return fmt.Errorf("error writing Go code to output: %w", err) } diff --git a/internal/schema/schema.go b/internal/schema/schema.go index e7871d23..3f7f3507 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -117,7 +117,7 @@ func (g GeneratorSchema) Imports() (string, error) { return sb.String(), nil } -func (g GeneratorSchema) SchemaBytes(name, packageName, generatorType string) ([]byte, error) { +func (g GeneratorSchema) Schema(name, packageName, generatorType string) ([]byte, error) { attributes, err := g.Attributes.Schema() if err != nil { diff --git a/internal/schema/schemas.go b/internal/schema/schemas.go index d578c4be..8ab53666 100644 --- a/internal/schema/schemas.go +++ b/internal/schema/schemas.go @@ -20,7 +20,7 @@ func NewGeneratorSchemas(schemas map[string]GeneratorSchema) GeneratorSchemas { } } -func (g GeneratorSchemas) SchemasBytes(packageName, generatorType string) (map[string][]byte, error) { +func (g GeneratorSchemas) Schemas(packageName, generatorType string) (map[string][]byte, error) { schemasBytes := make(map[string][]byte, len(g.schemas)) for k, s := range g.schemas { @@ -29,7 +29,7 @@ func (g GeneratorSchemas) SchemasBytes(packageName, generatorType string) (map[s packageName = fmt.Sprintf("%s_%s", strings.ToLower(generatorType), k) } - b, err := s.SchemaBytes(k, packageName, generatorType) + b, err := s.Schema(k, packageName, generatorType) if err != nil { return nil, err From 2c7e56c19b34d31e7a1a22a6df34ce8f561d0027 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 4 Oct 2023 16:06:06 +0100 Subject: [PATCH 07/19] Inline function --- internal/schema/schema.go | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/internal/schema/schema.go b/internal/schema/schema.go index 3f7f3507..c3be36a9 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -171,22 +171,6 @@ func (g GeneratorSchema) Schema(name, packageName, generatorType string) ([]byte func (g GeneratorSchema) Models(name string) ([]model.Model, error) { var models []model.Model - fields, err := g.ModelFields() - if err != nil { - return nil, err - } - - m := model.Model{ - Name: FrameworkIdentifier(name).ToPascalCase(), - Fields: fields, - } - - models = append(models, m) - - return models, nil -} - -func (g GeneratorSchema) ModelFields() ([]model.Field, error) { var modelFields []model.Field attributeKeys := g.Attributes.SortedKeys() @@ -221,7 +205,14 @@ func (g GeneratorSchema) ModelFields() ([]model.Field, error) { modelFields = append(modelFields, modelField) } - return modelFields, nil + m := model.Model{ + Name: FrameworkIdentifier(name).ToPascalCase(), + Fields: modelFields, + } + + models = append(models, m) + + return models, nil } // CustomTypeValueBytes iterates over all the attributes and blocks to generate code From c94153c3969a475d744a7ac32e6e7468175845fc Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 4 Oct 2023 16:12:31 +0100 Subject: [PATCH 08/19] Renaming --- internal/cmd/generate_data_sources.go | 10 +++++----- internal/cmd/generate_provider.go | 10 +++++----- internal/cmd/generate_resources.go | 10 +++++----- internal/datasource_generate/schemas_test.go | 2 +- internal/provider_generate/schemas_test.go | 2 +- internal/resource_generate/schemas_test.go | 2 +- internal/schema/schemas.go | 4 ++-- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/internal/cmd/generate_data_sources.go b/internal/cmd/generate_data_sources.go index d0012b15..0741fc84 100644 --- a/internal/cmd/generate_data_sources.go +++ b/internal/cmd/generate_data_sources.go @@ -141,13 +141,13 @@ func generateDataSourceCode(spec spec.Specification, outputPath, packageName, ge } // generate model code - modelsBytes, err := g.ModelsBytes() + models, err := g.Models() if err != nil { log.Fatal(err) } // generate custom type and value types code - customTypeValueBytes, err := g.CustomTypeValueBytes() + customTypeValue, err := g.CustomTypeValue() if err != nil { log.Fatal(err) } @@ -165,13 +165,13 @@ func generateDataSourceCode(spec spec.Specification, outputPath, packageName, ge } // format model code - formattedDataSourcesModels, err := format.Format(modelsBytes) + formattedModels, err := format.Format(models) if err != nil { log.Fatal(err) } // format custom type and value types code - formattedCustomTypeValue, err := format.Format(customTypeValueBytes) + formattedCustomTypeValue, err := format.Format(customTypeValue) if err != nil { log.Fatal(err) } @@ -183,7 +183,7 @@ func generateDataSourceCode(spec spec.Specification, outputPath, packageName, ge } // write code - err = output.WriteDataSources(formattedSchemas, formattedDataSourcesModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) + err = output.WriteDataSources(formattedSchemas, formattedModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) if err != nil { return fmt.Errorf("error writing Go code to output: %w", err) } diff --git a/internal/cmd/generate_provider.go b/internal/cmd/generate_provider.go index 56fab9dd..7d8ae240 100644 --- a/internal/cmd/generate_provider.go +++ b/internal/cmd/generate_provider.go @@ -141,13 +141,13 @@ func generateProviderCode(spec spec.Specification, outputPath, packageName, gene } // generate model code - modelsBytes, err := g.ModelsBytes() + models, err := g.Models() if err != nil { log.Fatal(err) } // generate custom type and value types code - customTypeValueBytes, err := g.CustomTypeValueBytes() + customTypeValue, err := g.CustomTypeValue() if err != nil { log.Fatal(err) } @@ -165,13 +165,13 @@ func generateProviderCode(spec spec.Specification, outputPath, packageName, gene } // format model code - formattedProvidersModels, err := format.Format(modelsBytes) + formattedModels, err := format.Format(models) if err != nil { log.Fatal(err) } // format custom type and value types code - formattedCustomTypeValue, err := format.Format(customTypeValueBytes) + formattedCustomTypeValue, err := format.Format(customTypeValue) if err != nil { log.Fatal(err) } @@ -183,7 +183,7 @@ func generateProviderCode(spec spec.Specification, outputPath, packageName, gene } // write code - err = output.WriteProviders(formattedSchemas, formattedProvidersModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) + err = output.WriteProviders(formattedSchemas, formattedModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) if err != nil { return fmt.Errorf("error writing Go code to output: %w", err) } diff --git a/internal/cmd/generate_resources.go b/internal/cmd/generate_resources.go index df378583..e02b6580 100644 --- a/internal/cmd/generate_resources.go +++ b/internal/cmd/generate_resources.go @@ -141,13 +141,13 @@ func generateResourceCode(spec spec.Specification, outputPath, packageName, gene } // generate model code - modelsBytes, err := g.ModelsBytes() + models, err := g.Models() if err != nil { log.Fatal(err) } // generate custom type and value types code - customTypeValueBytes, err := g.CustomTypeValueBytes() + customTypeValue, err := g.CustomTypeValue() if err != nil { log.Fatal(err) } @@ -165,13 +165,13 @@ func generateResourceCode(spec spec.Specification, outputPath, packageName, gene } // format model code - formattedResourcesModels, err := format.Format(modelsBytes) + formattedModels, err := format.Format(models) if err != nil { log.Fatal(err) } // format custom type and value types code - formattedCustomTypeValue, err := format.Format(customTypeValueBytes) + formattedCustomTypeValue, err := format.Format(customTypeValue) if err != nil { log.Fatal(err) } @@ -183,7 +183,7 @@ func generateResourceCode(spec spec.Specification, outputPath, packageName, gene } // write code - err = output.WriteResources(formattedSchemas, formattedResourcesModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) + err = output.WriteResources(formattedSchemas, formattedModels, formattedCustomTypeValue, formattedToFromFunctions, outputPath, packageName) if err != nil { return fmt.Errorf("error writing Go code to output: %w", err) } diff --git a/internal/datasource_generate/schemas_test.go b/internal/datasource_generate/schemas_test.go index 0b738af8..76cc065e 100644 --- a/internal/datasource_generate/schemas_test.go +++ b/internal/datasource_generate/schemas_test.go @@ -206,7 +206,7 @@ func TestGeneratorDataSourceSchemas_ModelsBytes(t *testing.T) { t.Parallel() g := schema.NewGeneratorSchemas(testCase.input) - got, err := g.ModelsBytes() + got, err := g.Models() if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected error: %s", diff) diff --git a/internal/provider_generate/schemas_test.go b/internal/provider_generate/schemas_test.go index fc479545..9300cf7d 100644 --- a/internal/provider_generate/schemas_test.go +++ b/internal/provider_generate/schemas_test.go @@ -206,7 +206,7 @@ func TestGeneratorProviderSchemas_ModelsBytes(t *testing.T) { t.Parallel() g := generatorschema.NewGeneratorSchemas(testCase.input) - got, err := g.ModelsBytes() + got, err := g.Models() if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected error: %s", diff) diff --git a/internal/resource_generate/schemas_test.go b/internal/resource_generate/schemas_test.go index e16bf88d..9d84c559 100644 --- a/internal/resource_generate/schemas_test.go +++ b/internal/resource_generate/schemas_test.go @@ -206,7 +206,7 @@ func TestGeneratorResourceSchemas_ModelsBytes(t *testing.T) { t.Parallel() g := generatorschema.NewGeneratorSchemas(testCase.input) - got, err := g.ModelsBytes() + got, err := g.Models() if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected error: %s", diff) diff --git a/internal/schema/schemas.go b/internal/schema/schemas.go index 8ab53666..32260c86 100644 --- a/internal/schema/schemas.go +++ b/internal/schema/schemas.go @@ -41,7 +41,7 @@ func (g GeneratorSchemas) Schemas(packageName, generatorType string) (map[string return schemasBytes, nil } -func (g GeneratorSchemas) ModelsBytes() (map[string][]byte, error) { +func (g GeneratorSchemas) Models() (map[string][]byte, error) { modelsBytes := make(map[string][]byte, len(g.schemas)) for name, schema := range g.schemas { @@ -67,7 +67,7 @@ func (g GeneratorSchemas) ModelsBytes() (map[string][]byte, error) { return modelsBytes, nil } -func (g GeneratorSchemas) CustomTypeValueBytes() (map[string][]byte, error) { +func (g GeneratorSchemas) CustomTypeValue() (map[string][]byte, error) { customTypeValueBytes := make(map[string][]byte, len(g.schemas)) for name, s := range g.schemas { From 6993ad3ad9d5af57dec2019778e11880fa0e6ea5 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 4 Oct 2023 16:40:12 +0100 Subject: [PATCH 09/19] Adding tests for to/from method generated code --- internal/schema/to_from_object_test.go | 140 +++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 internal/schema/to_from_object_test.go diff --git a/internal/schema/to_from_object_test.go b/internal/schema/to_from_object_test.go new file mode 100644 index 00000000..3c534a9d --- /dev/null +++ b/internal/schema/to_from_object_test.go @@ -0,0 +1,140 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-codegen-spec/code" + "github.com/hashicorp/terraform-plugin-codegen-spec/schema" +) + +func TestToFromObject_renderFrom(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + fromFuncs map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + fromFuncs: map[string]string{ + "bool_attribute": "BoolPointerValue", + }, + expected: []byte(` +func (v ExampleValue) FromApisdkType(ctx context.Context, apiObject *apisdk.Type) (ExampleValue, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return NewExampleValueNull(), diags +} + +return ExampleValue{ +BoolAttribute: types.BoolPointerValue(apiObject.BoolAttribute), +state: attr.ValueStateKnown, +}, diags +} +`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromObject := NewToFromObject(testCase.name, testCase.assocExtType, nil, testCase.fromFuncs) + + got, err := toFromObject.renderFrom() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestToFromObject_renderTo(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + toFuncs map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + toFuncs: map[string]string{ + "bool_attribute": "ValueBoolPointer", + }, + expected: []byte(`func (v ExampleValue) ToApisdkType(ctx context.Context) (*apisdk.Type, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"ExampleValue Value Is Unknown", +` + "`" + `"ExampleValue" is unknown.` + "`" + `, +)) + +return nil, diags +} + +return &apisdk.Type{ +BoolAttribute: v.BoolAttribute.ValueBoolPointer(), +}, diags +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromObject := NewToFromObject(testCase.name, testCase.assocExtType, testCase.toFuncs, nil) + + got, err := toFromObject.renderTo() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} From 29e537452483da7f5e5fba1e9a9b50b5f402c3a4 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 6 Oct 2023 09:32:41 +0100 Subject: [PATCH 10/19] Adding initial implementation of custom type and value types for data source bool attribute along with To/From method generation --- internal/datasource_convert/bool_attribute.go | 6 +- .../datasource_generate/bool_attribute.go | 48 ++ internal/schema/custom_bool.go | 345 +++++++++++++ internal/schema/custom_bool_test.go | 460 ++++++++++++++++++ internal/schema/embed.go | 51 ++ internal/schema/templates/bool_from.gotmpl | 14 + internal/schema/templates/bool_to.gotmpl | 20 + .../schema/templates/bool_type_equal.gotmpl | 9 + .../schema/templates/bool_type_string.gotmpl | 4 + .../schema/templates/bool_type_typable.gotmpl | 1 + .../schema/templates/bool_type_type.gotmpl | 3 + .../bool_type_value_from_bool.gotmpl | 6 + .../bool_type_value_from_terraform.gotmpl | 22 + .../templates/bool_type_value_type.gotmpl | 4 + .../schema/templates/bool_value_equal.gotmpl | 10 + .../schema/templates/bool_value_type.gotmpl | 5 + .../templates/bool_value_valuable.gotmpl | 1 + .../schema/templates/bool_value_value.gotmpl | 3 + internal/schema/to_from_bool.go | 99 ++++ internal/schema/to_from_bool_test.go | 133 +++++ 20 files changed, 1242 insertions(+), 2 deletions(-) create mode 100644 internal/schema/custom_bool.go create mode 100644 internal/schema/custom_bool_test.go create mode 100644 internal/schema/templates/bool_from.gotmpl create mode 100644 internal/schema/templates/bool_to.gotmpl create mode 100644 internal/schema/templates/bool_type_equal.gotmpl create mode 100644 internal/schema/templates/bool_type_string.gotmpl create mode 100644 internal/schema/templates/bool_type_typable.gotmpl create mode 100644 internal/schema/templates/bool_type_type.gotmpl create mode 100644 internal/schema/templates/bool_type_value_from_bool.gotmpl create mode 100644 internal/schema/templates/bool_type_value_from_terraform.gotmpl create mode 100644 internal/schema/templates/bool_type_value_type.gotmpl create mode 100644 internal/schema/templates/bool_value_equal.gotmpl create mode 100644 internal/schema/templates/bool_value_type.gotmpl create mode 100644 internal/schema/templates/bool_value_valuable.gotmpl create mode 100644 internal/schema/templates/bool_value_value.gotmpl create mode 100644 internal/schema/to_from_bool.go create mode 100644 internal/schema/to_from_bool_test.go diff --git a/internal/datasource_convert/bool_attribute.go b/internal/datasource_convert/bool_attribute.go index 7e9ae35d..55d82b4a 100644 --- a/internal/datasource_convert/bool_attribute.go +++ b/internal/datasource_convert/bool_attribute.go @@ -10,6 +10,7 @@ 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 convertBoolAttribute(a *datasource.BoolAttribute) (datasource_generate.GeneratorBoolAttribute, error) { @@ -28,7 +29,8 @@ func convertBoolAttribute(a *datasource.BoolAttribute) (datasource_generate.Gene DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Validators: a.Validators, + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Validators: a.Validators, }, nil } diff --git a/internal/datasource_generate/bool_attribute.go b/internal/datasource_generate/bool_attribute.go index 69a432ae..620e23c8 100644 --- a/internal/datasource_generate/bool_attribute.go +++ b/internal/datasource_generate/bool_attribute.go @@ -4,6 +4,7 @@ package datasource_generate import ( + "bytes" "strings" "text/template" @@ -17,6 +18,7 @@ import ( type GeneratorBoolAttribute struct { schema.BoolAttribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -101,3 +103,49 @@ func (g GeneratorBoolAttribute) ModelField(name generatorschema.FrameworkIdentif return field, nil } + +func (g GeneratorBoolAttribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + boolType := generatorschema.NewCustomBoolType(name) + + b, err := boolType.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + boolValue := generatorschema.NewCustomBoolValue(name) + + b, err = boolValue.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorBoolAttribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromBool(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/schema/custom_bool.go b/internal/schema/custom_bool.go new file mode 100644 index 00000000..44321037 --- /dev/null +++ b/internal/schema/custom_bool.go @@ -0,0 +1,345 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "bytes" + "text/template" +) + +type CustomBoolType struct { + Name FrameworkIdentifier + templates map[string]string +} + +func NewCustomBoolType(name string) CustomBoolType { + t := map[string]string{ + "equal": BoolTypeEqualTemplate, + "string": BoolTypeStringTemplate, + "type": BoolTypeTypeTemplate, + "typable": BoolTypeTypableTemplate, + "valueFromBool": BoolTypeValueFromBoolTemplate, + "valueFromTerraform": BoolTypeValueFromTerraformTemplate, + "valueType": BoolTypeValueTypeTemplate, + } + + return CustomBoolType{ + Name: FrameworkIdentifier(name), + templates: t, + } +} + +func (c CustomBoolType) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + c.renderTypable, + c.renderType, + c.renderEqual, + c.renderString, + c.renderValueFromBool, + c.renderValueFromTerraform, + c.renderValueType, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (c CustomBoolType) renderEqual() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["equal"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomBoolType) renderString() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["string"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomBoolType) renderType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["type"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomBoolType) renderTypable() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["typable"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomBoolType) renderValueFromBool() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueFromBool"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomBoolType) renderValueFromTerraform() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueFromTerraform"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomBoolType) renderValueType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueType"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type CustomBoolValue struct { + Name FrameworkIdentifier + templates map[string]string +} + +func NewCustomBoolValue(name string) CustomBoolValue { + t := map[string]string{ + "equal": BoolValueEqualTemplate, + "type": BoolValueTypeTemplate, + "valuable": BoolValueValuableTemplate, + "value": BoolValueValueTemplate, + } + + return CustomBoolValue{ + Name: FrameworkIdentifier(name), + templates: t, + } +} + +func (c CustomBoolValue) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + c.renderValuable, + c.renderValue, + c.renderEqual, + c.renderType, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (c CustomBoolValue) renderEqual() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["equal"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomBoolValue) renderType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["type"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomBoolValue) renderValuable() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valuable"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomBoolValue) renderValue() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["value"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/internal/schema/custom_bool_test.go b/internal/schema/custom_bool_test.go new file mode 100644 index 00000000..f962555f --- /dev/null +++ b/internal/schema/custom_bool_test.go @@ -0,0 +1,460 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestCustomBoolType_renderEqual(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`func (t ExampleType) Equal(o attr.Type) bool { +other, ok := o.(ExampleType) + +if !ok { +return false +} + +return t.BoolType.Equal(other.BoolType) +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolType := NewCustomBoolType(testCase.name) + + got, err := customBoolType.renderEqual() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomBoolType_renderString(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) String() string { +return "ExampleType" +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolType := NewCustomBoolType(testCase.name) + + got, err := customBoolType.renderString() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomBoolType_renderTypable(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`var _ basetypes.BoolTypable = ExampleType{}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolType := NewCustomBoolType(testCase.name) + + got, err := customBoolType.renderTypable() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomBoolType_renderType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`type ExampleType struct { +basetypes.BoolType +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolType := NewCustomBoolType(testCase.name) + + got, err := customBoolType.renderType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomBoolType_renderValueFromBool(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + attrValues map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + attrValues: map[string]string{ + "bool_attribute": "basetypes.BoolValue", + }, + expected: []byte(` +func (t ExampleType) ValueFromBool(ctx context.Context, in basetypes.BoolValue) (basetypes.BoolValuable, diag.Diagnostics) { +return ExampleValue{ +BoolValue: in, +}, nil +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolType := NewCustomBoolType(testCase.name) + + got, err := customBoolType.renderValueFromBool() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomBoolType_renderValueFromTerraform(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +attrValue, err := t.BoolType.ValueFromTerraform(ctx, in) + +if err != nil { +return nil, err +} + +boolValue, ok := attrValue.(basetypes.BoolValue) + +if !ok { +return nil, fmt.Errorf("unexpected value type of %T", attrValue) +} + +boolValuable, diags := t.ValueFromBool(ctx, boolValue) + +if diags.HasError() { +return nil, fmt.Errorf("unexpected error converting BoolValue to BoolValuable: %v", diags) +} + +return boolValuable, nil +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolType := NewCustomBoolType(testCase.name) + + got, err := customBoolType.renderValueFromTerraform() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomBoolType_renderValueType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) ValueType(ctx context.Context) attr.Value { +return ExampleValue{} +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolType := NewCustomBoolType(testCase.name) + + got, err := customBoolType.renderValueType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomBoolValue_renderEqual(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + attrValues map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + attrValues: map[string]string{ + "bool_attribute": "basetypes.BoolValue", + }, + expected: []byte(` +func (v ExampleValue) Equal(o attr.Value) bool { +other, ok := o.(ExampleValue) + +if !ok { +return false +} + +return v.BoolValue.Equal(other.BoolValue) +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolValue := NewCustomBoolValue(testCase.name) + + got, err := customBoolValue.renderEqual() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomBoolValue_renderType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (v ExampleValue) Type(ctx context.Context) attr.Type { +return ExampleType{ +} +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolValue := NewCustomBoolValue(testCase.name) + + got, err := customBoolValue.renderType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomBoolValue_renderValuable(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`var _ basetypes.BoolValuable = ExampleValue{}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolValue := NewCustomBoolValue(testCase.name) + + got, err := customBoolValue.renderValuable() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomBoolValue_renderValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`type ExampleValue struct { +basetypes.BoolValue +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customBoolValue := NewCustomBoolValue(testCase.name) + + got, err := customBoolValue.renderValue() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/internal/schema/embed.go b/internal/schema/embed.go index da7a5fe8..6ca14432 100644 --- a/internal/schema/embed.go +++ b/internal/schema/embed.go @@ -7,12 +7,61 @@ import ( _ "embed" ) +// Bool + +//go:embed templates/bool_from.gotmpl +var BoolFromTemplate string + +//go:embed templates/bool_to.gotmpl +var BoolToTemplate string + +// Bool Type + +//go:embed templates/bool_type_equal.gotmpl +var BoolTypeEqualTemplate string + +//go:embed templates/bool_type_string.gotmpl +var BoolTypeStringTemplate string + +//go:embed templates/bool_type_type.gotmpl +var BoolTypeTypeTemplate string + +//go:embed templates/bool_type_typable.gotmpl +var BoolTypeTypableTemplate string + +//go:embed templates/bool_type_value_from_bool.gotmpl +var BoolTypeValueFromBoolTemplate string + +//go:embed templates/bool_type_value_from_terraform.gotmpl +var BoolTypeValueFromTerraformTemplate string + +//go:embed templates/bool_type_value_type.gotmpl +var BoolTypeValueTypeTemplate string + +// Bool Value + +//go:embed templates/bool_value_equal.gotmpl +var BoolValueEqualTemplate string + +//go:embed templates/bool_value_type.gotmpl +var BoolValueTypeTemplate string + +//go:embed templates/bool_value_value.gotmpl +var BoolValueValueTemplate string + +//go:embed templates/bool_value_valuable.gotmpl +var BoolValueValuableTemplate string + +// Object + //go:embed templates/object_from.gotmpl var ObjectFromTemplate string //go:embed templates/object_to.gotmpl var ObjectToTemplate string +// Object Type + //go:embed templates/object_type_equal.gotmpl var ObjectTypeEqualTemplate string @@ -46,6 +95,8 @@ var ObjectTypeValueTypeTemplate string //go:embed templates/object_type_value_unknown.gotmpl var ObjectTypeValueUnknownTemplate string +// Object Value + //go:embed templates/object_value_attribute_types.gotmpl var ObjectValueAttributeTypesTemplate string diff --git a/internal/schema/templates/bool_from.gotmpl b/internal/schema/templates/bool_from.gotmpl new file mode 100644 index 00000000..38eec569 --- /dev/null +++ b/internal/schema/templates/bool_from.gotmpl @@ -0,0 +1,14 @@ + +func (v {{.Name}}Value) From{{.AssocExtType.ToPascalCase}}(ctx context.Context, apiObject {{.AssocExtType.Type}}) ({{.Name}}Value, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return {{.Name}}Value{ +types.BoolNull(), +}, diags +} + +return {{.Name}}Value{ +types.BoolPointerValue(*apiObject), +}, diags +} diff --git a/internal/schema/templates/bool_to.gotmpl b/internal/schema/templates/bool_to.gotmpl new file mode 100644 index 00000000..97c3fe5a --- /dev/null +++ b/internal/schema/templates/bool_to.gotmpl @@ -0,0 +1,20 @@ +func (v {{.Name}}Value) To{{.AssocExtType.ToPascalCase}}(ctx context.Context) ({{.AssocExtType.Type}}, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"{{.Name}}Value Value Is Unknown", +`"{{.Name}}Value" is unknown.`, +)) + +return nil, diags +} + +a := {{.AssocExtType.TypeReference}}(v.ValueBoolPointer()) + +return &a, diags +} \ No newline at end of file diff --git a/internal/schema/templates/bool_type_equal.gotmpl b/internal/schema/templates/bool_type_equal.gotmpl new file mode 100644 index 00000000..409be80f --- /dev/null +++ b/internal/schema/templates/bool_type_equal.gotmpl @@ -0,0 +1,9 @@ +func (t {{.Name}}Type) Equal(o attr.Type) bool { +other, ok := o.({{.Name}}Type) + +if !ok { +return false +} + +return t.BoolType.Equal(other.BoolType) +} \ No newline at end of file diff --git a/internal/schema/templates/bool_type_string.gotmpl b/internal/schema/templates/bool_type_string.gotmpl new file mode 100644 index 00000000..f01b8ac3 --- /dev/null +++ b/internal/schema/templates/bool_type_string.gotmpl @@ -0,0 +1,4 @@ + +func (t {{.Name}}Type) String() string { +return "{{.Name}}Type" +} \ No newline at end of file diff --git a/internal/schema/templates/bool_type_typable.gotmpl b/internal/schema/templates/bool_type_typable.gotmpl new file mode 100644 index 00000000..3dd7951a --- /dev/null +++ b/internal/schema/templates/bool_type_typable.gotmpl @@ -0,0 +1 @@ +var _ basetypes.BoolTypable = {{.Name}}Type{} \ No newline at end of file diff --git a/internal/schema/templates/bool_type_type.gotmpl b/internal/schema/templates/bool_type_type.gotmpl new file mode 100644 index 00000000..08d365b4 --- /dev/null +++ b/internal/schema/templates/bool_type_type.gotmpl @@ -0,0 +1,3 @@ +type {{.Name}}Type struct { +basetypes.BoolType +} \ No newline at end of file diff --git a/internal/schema/templates/bool_type_value_from_bool.gotmpl b/internal/schema/templates/bool_type_value_from_bool.gotmpl new file mode 100644 index 00000000..73d3f24a --- /dev/null +++ b/internal/schema/templates/bool_type_value_from_bool.gotmpl @@ -0,0 +1,6 @@ + +func (t {{.Name}}Type) ValueFromBool(ctx context.Context, in basetypes.BoolValue) (basetypes.BoolValuable, diag.Diagnostics) { +return {{.Name}}Value{ +BoolValue: in, +}, nil +} \ No newline at end of file diff --git a/internal/schema/templates/bool_type_value_from_terraform.gotmpl b/internal/schema/templates/bool_type_value_from_terraform.gotmpl new file mode 100644 index 00000000..1a816779 --- /dev/null +++ b/internal/schema/templates/bool_type_value_from_terraform.gotmpl @@ -0,0 +1,22 @@ + +func (t {{.Name}}Type) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +attrValue, err := t.BoolType.ValueFromTerraform(ctx, in) + +if err != nil { +return nil, err +} + +boolValue, ok := attrValue.(basetypes.BoolValue) + +if !ok { +return nil, fmt.Errorf("unexpected value type of %T", attrValue) +} + +boolValuable, diags := t.ValueFromBool(ctx, boolValue) + +if diags.HasError() { +return nil, fmt.Errorf("unexpected error converting BoolValue to BoolValuable: %v", diags) +} + +return boolValuable, nil +} \ No newline at end of file diff --git a/internal/schema/templates/bool_type_value_type.gotmpl b/internal/schema/templates/bool_type_value_type.gotmpl new file mode 100644 index 00000000..1f7b7fea --- /dev/null +++ b/internal/schema/templates/bool_type_value_type.gotmpl @@ -0,0 +1,4 @@ + +func (t {{.Name}}Type) ValueType(ctx context.Context) attr.Value { +return {{.Name}}Value{} +} \ No newline at end of file diff --git a/internal/schema/templates/bool_value_equal.gotmpl b/internal/schema/templates/bool_value_equal.gotmpl new file mode 100644 index 00000000..6c5c01e2 --- /dev/null +++ b/internal/schema/templates/bool_value_equal.gotmpl @@ -0,0 +1,10 @@ + +func (v {{.Name}}Value) Equal(o attr.Value) bool { +other, ok := o.({{.Name}}Value) + +if !ok { +return false +} + +return v.BoolValue.Equal(other.BoolValue) +} \ No newline at end of file diff --git a/internal/schema/templates/bool_value_type.gotmpl b/internal/schema/templates/bool_value_type.gotmpl new file mode 100644 index 00000000..751cd5c0 --- /dev/null +++ b/internal/schema/templates/bool_value_type.gotmpl @@ -0,0 +1,5 @@ + +func (v {{.Name}}Value) Type(ctx context.Context) attr.Type { +return {{.Name}}Type{ +} +} \ No newline at end of file diff --git a/internal/schema/templates/bool_value_valuable.gotmpl b/internal/schema/templates/bool_value_valuable.gotmpl new file mode 100644 index 00000000..469f4614 --- /dev/null +++ b/internal/schema/templates/bool_value_valuable.gotmpl @@ -0,0 +1 @@ +var _ basetypes.BoolValuable = {{.Name}}Value{} \ No newline at end of file diff --git a/internal/schema/templates/bool_value_value.gotmpl b/internal/schema/templates/bool_value_value.gotmpl new file mode 100644 index 00000000..e4744962 --- /dev/null +++ b/internal/schema/templates/bool_value_value.gotmpl @@ -0,0 +1,3 @@ +type {{.Name}}Value struct { +basetypes.BoolValue +} \ No newline at end of file diff --git a/internal/schema/to_from_bool.go b/internal/schema/to_from_bool.go new file mode 100644 index 00000000..6570df26 --- /dev/null +++ b/internal/schema/to_from_bool.go @@ -0,0 +1,99 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "bytes" + "text/template" +) + +type ToFromBool struct { + Name FrameworkIdentifier + AssocExtType *AssocExtType + templates map[string]string +} + +func NewToFromBool(name string, assocExtType *AssocExtType) ToFromBool { + t := map[string]string{ + "from": BoolFromTemplate, + "to": BoolToTemplate, + } + + return ToFromBool{ + Name: FrameworkIdentifier(name), + AssocExtType: assocExtType, + templates: t, + } +} + +func (o ToFromBool) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + o.renderTo, + o.renderFrom, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (o ToFromBool) renderTo() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["to"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (o ToFromBool) renderFrom() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["from"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/internal/schema/to_from_bool_test.go b/internal/schema/to_from_bool_test.go new file mode 100644 index 00000000..0f527879 --- /dev/null +++ b/internal/schema/to_from_bool_test.go @@ -0,0 +1,133 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-codegen-spec/code" + "github.com/hashicorp/terraform-plugin-codegen-spec/schema" +) + +func TestToFromBool_renderFrom(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + expected: []byte(` +func (v ExampleValue) FromApisdkType(ctx context.Context, apiObject *apisdk.Type) (ExampleValue, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return ExampleValue{ +types.BoolNull(), +}, diags +} + +return ExampleValue{ +types.BoolPointerValue(*apiObject), +}, diags +} +`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromBool := NewToFromBool(testCase.name, testCase.assocExtType) + + got, err := toFromBool.renderFrom() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestToFromBool_renderTo(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + expected: []byte(`func (v ExampleValue) ToApisdkType(ctx context.Context) (*apisdk.Type, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"ExampleValue Value Is Unknown", +` + "`" + `"ExampleValue" is unknown.` + "`" + `, +)) + +return nil, diags +} + +a := apisdk.Type(v.ValueBoolPointer()) + +return &a, diags +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromBool := NewToFromBool(testCase.name, testCase.assocExtType) + + got, err := toFromBool.renderTo() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} From c0e4690ad97a78120da2b9f6f74cf11b463e5247 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 17 Oct 2023 10:28:00 +0100 Subject: [PATCH 11/19] Updating data source attributes to use generated type and value type in schema and models if associated external type is defined --- .../datasource_generate/bool_attribute.go | 25 +++++++++++++++--- internal/datasource_generate/embed.go | 21 +++++++++++---- .../datasource_generate/float64_attribute.go | 25 +++++++++++++++--- .../datasource_generate/int64_attribute.go | 25 +++++++++++++++--- .../datasource_generate/number_attribute.go | 25 +++++++++++++++--- .../datasource_generate/string_attribute.go | 25 +++++++++++++++--- .../templates/attribute.gotmpl | 26 +++++++++++++++++++ .../templates/bool_attribute.gotmpl | 3 +++ .../templates/float64_attribute.gotmpl | 3 +++ .../templates/int64_attribute.gotmpl | 3 +++ .../templates/number_attribute.gotmpl | 3 +++ .../templates/string_attribute.gotmpl | 3 +++ internal/schema/embed.go | 2 +- internal/schema/import.go | 24 +++++++++++++++++ 14 files changed, 192 insertions(+), 21 deletions(-) create mode 100644 internal/datasource_generate/templates/attribute.gotmpl diff --git a/internal/datasource_generate/bool_attribute.go b/internal/datasource_generate/bool_attribute.go index 620e23c8..601ad816 100644 --- a/internal/datasource_generate/bool_attribute.go +++ b/internal/datasource_generate/bool_attribute.go @@ -5,6 +5,7 @@ package datasource_generate import ( "bytes" + "fmt" "strings" "text/template" @@ -40,6 +41,12 @@ func (g GeneratorBoolAttribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -63,6 +70,7 @@ func (g GeneratorBoolAttribute) Equal(ga generatorschema.GeneratorAttribute) boo func (g GeneratorBoolAttribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string GeneratorBoolAttribute GeneratorBoolAttribute } @@ -71,12 +79,20 @@ func (g GeneratorBoolAttribute) Schema(name generatorschema.FrameworkIdentifier) GeneratorBoolAttribute: g, } - t, err := template.New("bool_attribute").Parse(boolAttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("bool_attribute").Parse(boolAttributeTemplate) + if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -97,8 +113,11 @@ func (g GeneratorBoolAttribute) ModelField(name generatorschema.FrameworkIdentif ValueType: model.BoolValueType, } - 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 diff --git a/internal/datasource_generate/embed.go b/internal/datasource_generate/embed.go index c58a3bc7..c4ee8e00 100644 --- a/internal/datasource_generate/embed.go +++ b/internal/datasource_generate/embed.go @@ -10,13 +10,13 @@ import ( ) //go:embed templates/bool_attribute.gotmpl -var boolAttributeGoTemplate string +var boolAttributeTemplate string //go:embed templates/float64_attribute.gotmpl -var float64AttributeGoTemplate string +var float64AttributeTemplate string //go:embed templates/int64_attribute.gotmpl -var int64AttributeGoTemplate string +var int64AttributeTemplate string //go:embed templates/list_attribute.gotmpl var listAttributeGoTemplate string @@ -31,7 +31,7 @@ var mapAttributeGoTemplate string var mapNestedAttributeGoTemplate string //go:embed templates/number_attribute.gotmpl -var numberAttributeGoTemplate string +var numberAttributeTemplate string //go:embed templates/object_attribute.gotmpl var objectAttributeGoTemplate string @@ -46,7 +46,7 @@ var setNestedAttributeGoTemplate string var singleNestedAttributeGoTemplate string //go:embed templates/string_attribute.gotmpl -var stringAttributeGoTemplate string +var stringAttributeTemplate string //go:embed templates/list_nested_block.gotmpl var listNestedBlockGoTemplate string @@ -78,3 +78,14 @@ func addCommonBlockTemplate(t *template.Template) (*template.Template, error) { return t.New("common_block").Funcs(commonTemplateFuncs).Parse(commonBlockGoTemplate) } + +//go:embed templates/attribute.gotmpl +var attributeTemplate string + +func addAttributeTemplate(t *template.Template) (*template.Template, error) { + templateFuncs := template.FuncMap{ + "quote": strconv.Quote, + } + + return t.New("attribute").Funcs(templateFuncs).Parse(attributeTemplate) +} diff --git a/internal/datasource_generate/float64_attribute.go b/internal/datasource_generate/float64_attribute.go index c649636a..94bf69d6 100644 --- a/internal/datasource_generate/float64_attribute.go +++ b/internal/datasource_generate/float64_attribute.go @@ -4,6 +4,7 @@ package datasource_generate import ( + "fmt" "strings" "text/template" @@ -17,6 +18,7 @@ import ( type GeneratorFloat64Attribute struct { schema.Float64Attribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -38,6 +40,12 @@ func (g GeneratorFloat64Attribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -61,6 +69,7 @@ func (g GeneratorFloat64Attribute) Equal(ga generatorschema.GeneratorAttribute) func (g GeneratorFloat64Attribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string GeneratorFloat64Attribute GeneratorFloat64Attribute } @@ -69,12 +78,19 @@ func (g GeneratorFloat64Attribute) Schema(name generatorschema.FrameworkIdentifi GeneratorFloat64Attribute: g, } - t, err := template.New("float64_attribute").Parse(float64AttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("float64_attribute").Parse(float64AttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -95,8 +111,11 @@ func (g GeneratorFloat64Attribute) ModelField(name generatorschema.FrameworkIden ValueType: model.Float64ValueType, } - 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 diff --git a/internal/datasource_generate/int64_attribute.go b/internal/datasource_generate/int64_attribute.go index 247f139e..76d9ff0c 100644 --- a/internal/datasource_generate/int64_attribute.go +++ b/internal/datasource_generate/int64_attribute.go @@ -4,6 +4,7 @@ package datasource_generate import ( + "fmt" "strings" "text/template" @@ -17,6 +18,7 @@ import ( type GeneratorInt64Attribute struct { schema.Int64Attribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -38,6 +40,12 @@ func (g GeneratorInt64Attribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -61,6 +69,7 @@ func (g GeneratorInt64Attribute) Equal(ga generatorschema.GeneratorAttribute) bo func (g GeneratorInt64Attribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string GeneratorInt64Attribute GeneratorInt64Attribute } @@ -69,12 +78,19 @@ func (g GeneratorInt64Attribute) Schema(name generatorschema.FrameworkIdentifier GeneratorInt64Attribute: g, } - t, err := template.New("int64_attribute").Parse(int64AttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("int64_attribute").Parse(int64AttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -95,8 +111,11 @@ func (g GeneratorInt64Attribute) ModelField(name generatorschema.FrameworkIdenti ValueType: model.Int64ValueType, } - 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 diff --git a/internal/datasource_generate/number_attribute.go b/internal/datasource_generate/number_attribute.go index 701f37b6..ff27f3d6 100644 --- a/internal/datasource_generate/number_attribute.go +++ b/internal/datasource_generate/number_attribute.go @@ -4,6 +4,7 @@ package datasource_generate import ( + "fmt" "strings" "text/template" @@ -17,6 +18,7 @@ import ( type GeneratorNumberAttribute struct { schema.NumberAttribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -38,6 +40,12 @@ func (g GeneratorNumberAttribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -61,6 +69,7 @@ func (g GeneratorNumberAttribute) Equal(ga generatorschema.GeneratorAttribute) b func (g GeneratorNumberAttribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string GeneratorNumberAttribute GeneratorNumberAttribute } @@ -69,12 +78,19 @@ func (g GeneratorNumberAttribute) Schema(name generatorschema.FrameworkIdentifie GeneratorNumberAttribute: g, } - t, err := template.New("number_attribute").Parse(numberAttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("number_attribute").Parse(numberAttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -95,8 +111,11 @@ func (g GeneratorNumberAttribute) ModelField(name generatorschema.FrameworkIdent ValueType: model.NumberValueType, } - 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 diff --git a/internal/datasource_generate/string_attribute.go b/internal/datasource_generate/string_attribute.go index 715f9522..8727c049 100644 --- a/internal/datasource_generate/string_attribute.go +++ b/internal/datasource_generate/string_attribute.go @@ -4,6 +4,7 @@ package datasource_generate import ( + "fmt" "strings" "text/template" @@ -17,6 +18,7 @@ import ( type GeneratorStringAttribute struct { schema.StringAttribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -38,6 +40,12 @@ func (g GeneratorStringAttribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -61,6 +69,7 @@ func (g GeneratorStringAttribute) Equal(ga generatorschema.GeneratorAttribute) b func (g GeneratorStringAttribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string GeneratorStringAttribute GeneratorStringAttribute } @@ -69,12 +78,19 @@ func (g GeneratorStringAttribute) Schema(name generatorschema.FrameworkIdentifie GeneratorStringAttribute: g, } - t, err := template.New("string_attribute").Parse(stringAttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("string_attribute").Parse(stringAttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -95,8 +111,11 @@ func (g GeneratorStringAttribute) ModelField(name generatorschema.FrameworkIdent ValueType: model.StringValueType, } - 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 diff --git a/internal/datasource_generate/templates/attribute.gotmpl b/internal/datasource_generate/templates/attribute.gotmpl new file mode 100644 index 00000000..abab8c3d --- /dev/null +++ b/internal/datasource_generate/templates/attribute.gotmpl @@ -0,0 +1,26 @@ +{{define "common_attribute"}} + +{{- if .Required}} +Required: {{.Required}}, +{{- end}} + +{{- if .Optional}} +Optional: {{.Optional}}, +{{- end}} + +{{- if .Computed}} +Computed: {{.Computed}}, +{{- end}} + +{{- if .Sensitive }} +Sensitive: {{.Sensitive}}, +{{- end}} + +{{- if .Description }} +Description: {{ .Description | quote }}, +MarkdownDescription: {{.Description | quote }}, +{{- end}} + +{{- if .DeprecationMessage }} +DeprecationMessage: {{ .DeprecationMessage | quote }},{{- end}} +{{- end}} \ No newline at end of file diff --git a/internal/datasource_generate/templates/bool_attribute.gotmpl b/internal/datasource_generate/templates/bool_attribute.gotmpl index 98d9d2b6..8ac85743 100644 --- a/internal/datasource_generate/templates/bool_attribute.gotmpl +++ b/internal/datasource_generate/templates/bool_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.BoolAttribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorBoolAttribute }} {{- if gt (len .GeneratorBoolAttribute.Validators) 0 }} Validators: []validator.Bool{ diff --git a/internal/datasource_generate/templates/float64_attribute.gotmpl b/internal/datasource_generate/templates/float64_attribute.gotmpl index d6530c7f..752c64e6 100644 --- a/internal/datasource_generate/templates/float64_attribute.gotmpl +++ b/internal/datasource_generate/templates/float64_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.Float64Attribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorFloat64Attribute }} {{- if gt (len .GeneratorFloat64Attribute.Validators) 0 }} Validators: []validator.Float64{ diff --git a/internal/datasource_generate/templates/int64_attribute.gotmpl b/internal/datasource_generate/templates/int64_attribute.gotmpl index d0ce7c04..2f65cbb2 100644 --- a/internal/datasource_generate/templates/int64_attribute.gotmpl +++ b/internal/datasource_generate/templates/int64_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.Int64Attribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorInt64Attribute }} {{- if gt (len .GeneratorInt64Attribute.Validators) 0 }} Validators: []validator.Int64{ diff --git a/internal/datasource_generate/templates/number_attribute.gotmpl b/internal/datasource_generate/templates/number_attribute.gotmpl index 98425de0..e089ecd0 100644 --- a/internal/datasource_generate/templates/number_attribute.gotmpl +++ b/internal/datasource_generate/templates/number_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.NumberAttribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorNumberAttribute }} {{- if gt (len .GeneratorNumberAttribute.Validators) 0 }} Validators: []validator.Number{ diff --git a/internal/datasource_generate/templates/string_attribute.gotmpl b/internal/datasource_generate/templates/string_attribute.gotmpl index fab62020..ebb12b19 100644 --- a/internal/datasource_generate/templates/string_attribute.gotmpl +++ b/internal/datasource_generate/templates/string_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.StringAttribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorStringAttribute }} {{- if gt (len .GeneratorStringAttribute.Validators) 0 }} Validators: []validator.String{ diff --git a/internal/schema/embed.go b/internal/schema/embed.go index 6ca14432..9cfb57d8 100644 --- a/internal/schema/embed.go +++ b/internal/schema/embed.go @@ -7,7 +7,7 @@ import ( _ "embed" ) -// Bool +// Bool From/To //go:embed templates/bool_from.gotmpl var BoolFromTemplate string diff --git a/internal/schema/import.go b/internal/schema/import.go index 6d07609b..6a1ea6a4 100644 --- a/internal/schema/import.go +++ b/internal/schema/import.go @@ -311,3 +311,27 @@ func CustomValidatorImports(cv *specschema.CustomValidator) *Imports { return imports } + +func AssociatedExternalTypeImports() *Imports { + imports := NewImports() + + imports.Add([]code.Import{ + { + Path: FmtImport, + }, + { + Path: DiagImport, + }, + { + Path: AttrImport, + }, + { + Path: TfTypesImport, + }, + { + Path: BaseTypesImport, + }, + }...) + + return imports +} From 1cee4173ef3d967e1069cd2dea7596dd9eee53c6 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 17 Oct 2023 10:31:23 +0100 Subject: [PATCH 12/19] Populating data source associated external type --- internal/datasource_convert/float64_attribute.go | 6 ++++-- internal/datasource_convert/int64_attribute.go | 6 ++++-- internal/datasource_convert/number_attribute.go | 6 ++++-- internal/datasource_convert/string_attribute.go | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/internal/datasource_convert/float64_attribute.go b/internal/datasource_convert/float64_attribute.go index ba3be791..27a7b96d 100644 --- a/internal/datasource_convert/float64_attribute.go +++ b/internal/datasource_convert/float64_attribute.go @@ -10,6 +10,7 @@ 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 convertFloat64Attribute(a *datasource.Float64Attribute) (datasource_generate.GeneratorFloat64Attribute, error) { @@ -28,7 +29,8 @@ func convertFloat64Attribute(a *datasource.Float64Attribute) (datasource_generat DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Validators: a.Validators, + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Validators: a.Validators, }, nil } diff --git a/internal/datasource_convert/int64_attribute.go b/internal/datasource_convert/int64_attribute.go index f3a105a1..8ee639a8 100644 --- a/internal/datasource_convert/int64_attribute.go +++ b/internal/datasource_convert/int64_attribute.go @@ -10,6 +10,7 @@ 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 convertInt64Attribute(a *datasource.Int64Attribute) (datasource_generate.GeneratorInt64Attribute, error) { @@ -28,7 +29,8 @@ func convertInt64Attribute(a *datasource.Int64Attribute) (datasource_generate.Ge DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Validators: a.Validators, + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Validators: a.Validators, }, nil } diff --git a/internal/datasource_convert/number_attribute.go b/internal/datasource_convert/number_attribute.go index db86cac7..53f86af5 100644 --- a/internal/datasource_convert/number_attribute.go +++ b/internal/datasource_convert/number_attribute.go @@ -10,6 +10,7 @@ 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 convertNumberAttribute(a *datasource.NumberAttribute) (datasource_generate.GeneratorNumberAttribute, error) { @@ -28,7 +29,8 @@ func convertNumberAttribute(a *datasource.NumberAttribute) (datasource_generate. DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Validators: a.Validators, + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Validators: a.Validators, }, nil } diff --git a/internal/datasource_convert/string_attribute.go b/internal/datasource_convert/string_attribute.go index c2fa8595..7796cfce 100644 --- a/internal/datasource_convert/string_attribute.go +++ b/internal/datasource_convert/string_attribute.go @@ -10,6 +10,7 @@ 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 convertStringAttribute(a *datasource.StringAttribute) (datasource_generate.GeneratorStringAttribute, error) { @@ -28,7 +29,8 @@ func convertStringAttribute(a *datasource.StringAttribute) (datasource_generate. DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Validators: a.Validators, + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Validators: a.Validators, }, nil } From 48c96133c8870fa1b0a60511d5302d60d11815d2 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 17 Oct 2023 14:06:34 +0100 Subject: [PATCH 13/19] Setting up generation of custom type and value types and to/from functions for data source float64, int64, number, and string attributes --- .../datasource_generate/float64_attribute.go | 47 ++ .../datasource_generate/int64_attribute.go | 47 ++ .../datasource_generate/number_attribute.go | 47 ++ .../datasource_generate/string_attribute.go | 47 ++ internal/schema/custom_float64.go | 345 +++++++++++++ internal/schema/custom_float64_test.go | 460 ++++++++++++++++++ internal/schema/custom_int64.go | 345 +++++++++++++ internal/schema/custom_int64_test.go | 460 ++++++++++++++++++ internal/schema/custom_number.go | 345 +++++++++++++ internal/schema/custom_number_test.go | 460 ++++++++++++++++++ internal/schema/custom_string.go | 345 +++++++++++++ internal/schema/embed.go | 182 ++++++- internal/schema/templates/float64_from.gotmpl | 14 + internal/schema/templates/float64_to.gotmpl | 20 + .../templates/float64_type_equal.gotmpl | 9 + .../templates/float64_type_string.gotmpl | 4 + .../templates/float64_type_typable.gotmpl | 1 + .../schema/templates/float64_type_type.gotmpl | 3 + .../float64_type_value_from_float64.gotmpl | 6 + .../float64_type_value_from_terraform.gotmpl | 22 + .../templates/float64_type_value_type.gotmpl | 4 + .../templates/float64_value_equal.gotmpl | 10 + .../templates/float64_value_type.gotmpl | 5 + .../templates/float64_value_valuable.gotmpl | 1 + .../templates/float64_value_value.gotmpl | 3 + internal/schema/templates/int64_from.gotmpl | 14 + internal/schema/templates/int64_to.gotmpl | 20 + .../schema/templates/int64_type_equal.gotmpl | 9 + .../schema/templates/int64_type_string.gotmpl | 4 + .../templates/int64_type_typable.gotmpl | 1 + .../schema/templates/int64_type_type.gotmpl | 3 + .../int64_type_value_from_int64.gotmpl | 6 + .../int64_type_value_from_terraform.gotmpl | 22 + .../templates/int64_type_value_type.gotmpl | 4 + .../schema/templates/int64_value_equal.gotmpl | 10 + .../schema/templates/int64_value_type.gotmpl | 5 + .../templates/int64_value_valuable.gotmpl | 1 + .../schema/templates/int64_value_value.gotmpl | 3 + internal/schema/templates/number_from.gotmpl | 14 + internal/schema/templates/number_to.gotmpl | 20 + .../schema/templates/number_type_equal.gotmpl | 9 + .../templates/number_type_string.gotmpl | 4 + .../templates/number_type_typable.gotmpl | 1 + .../schema/templates/number_type_type.gotmpl | 3 + .../number_type_value_from_number.gotmpl | 6 + .../number_type_value_from_terraform.gotmpl | 22 + .../templates/number_type_value_type.gotmpl | 4 + .../templates/number_value_equal.gotmpl | 10 + .../schema/templates/number_value_type.gotmpl | 5 + .../templates/number_value_valuable.gotmpl | 1 + .../templates/number_value_value.gotmpl | 3 + internal/schema/templates/string_from.gotmpl | 14 + internal/schema/templates/string_to.gotmpl | 20 + .../schema/templates/string_type_equal.gotmpl | 9 + .../templates/string_type_string.gotmpl | 4 + .../templates/string_type_typable.gotmpl | 1 + .../schema/templates/string_type_type.gotmpl | 3 + .../string_type_value_from_string.gotmpl | 6 + .../string_type_value_from_terraform.gotmpl | 22 + .../templates/string_type_value_type.gotmpl | 4 + .../templates/string_value_equal.gotmpl | 10 + .../schema/templates/string_value_type.gotmpl | 5 + .../templates/string_value_valuable.gotmpl | 1 + .../templates/string_value_value.gotmpl | 3 + internal/schema/to_from_float64.go | 99 ++++ internal/schema/to_from_float64_test.go | 133 +++++ internal/schema/to_from_int64.go | 99 ++++ internal/schema/to_from_int64_test.go | 133 +++++ internal/schema/to_from_number.go | 99 ++++ internal/schema/to_from_number_test.go | 133 +++++ internal/schema/to_from_string.go | 99 ++++ 71 files changed, 4332 insertions(+), 1 deletion(-) create mode 100644 internal/schema/custom_float64.go create mode 100644 internal/schema/custom_float64_test.go create mode 100644 internal/schema/custom_int64.go create mode 100644 internal/schema/custom_int64_test.go create mode 100644 internal/schema/custom_number.go create mode 100644 internal/schema/custom_number_test.go create mode 100644 internal/schema/custom_string.go create mode 100644 internal/schema/templates/float64_from.gotmpl create mode 100644 internal/schema/templates/float64_to.gotmpl create mode 100644 internal/schema/templates/float64_type_equal.gotmpl create mode 100644 internal/schema/templates/float64_type_string.gotmpl create mode 100644 internal/schema/templates/float64_type_typable.gotmpl create mode 100644 internal/schema/templates/float64_type_type.gotmpl create mode 100644 internal/schema/templates/float64_type_value_from_float64.gotmpl create mode 100644 internal/schema/templates/float64_type_value_from_terraform.gotmpl create mode 100644 internal/schema/templates/float64_type_value_type.gotmpl create mode 100644 internal/schema/templates/float64_value_equal.gotmpl create mode 100644 internal/schema/templates/float64_value_type.gotmpl create mode 100644 internal/schema/templates/float64_value_valuable.gotmpl create mode 100644 internal/schema/templates/float64_value_value.gotmpl create mode 100644 internal/schema/templates/int64_from.gotmpl create mode 100644 internal/schema/templates/int64_to.gotmpl create mode 100644 internal/schema/templates/int64_type_equal.gotmpl create mode 100644 internal/schema/templates/int64_type_string.gotmpl create mode 100644 internal/schema/templates/int64_type_typable.gotmpl create mode 100644 internal/schema/templates/int64_type_type.gotmpl create mode 100644 internal/schema/templates/int64_type_value_from_int64.gotmpl create mode 100644 internal/schema/templates/int64_type_value_from_terraform.gotmpl create mode 100644 internal/schema/templates/int64_type_value_type.gotmpl create mode 100644 internal/schema/templates/int64_value_equal.gotmpl create mode 100644 internal/schema/templates/int64_value_type.gotmpl create mode 100644 internal/schema/templates/int64_value_valuable.gotmpl create mode 100644 internal/schema/templates/int64_value_value.gotmpl create mode 100644 internal/schema/templates/number_from.gotmpl create mode 100644 internal/schema/templates/number_to.gotmpl create mode 100644 internal/schema/templates/number_type_equal.gotmpl create mode 100644 internal/schema/templates/number_type_string.gotmpl create mode 100644 internal/schema/templates/number_type_typable.gotmpl create mode 100644 internal/schema/templates/number_type_type.gotmpl create mode 100644 internal/schema/templates/number_type_value_from_number.gotmpl create mode 100644 internal/schema/templates/number_type_value_from_terraform.gotmpl create mode 100644 internal/schema/templates/number_type_value_type.gotmpl create mode 100644 internal/schema/templates/number_value_equal.gotmpl create mode 100644 internal/schema/templates/number_value_type.gotmpl create mode 100644 internal/schema/templates/number_value_valuable.gotmpl create mode 100644 internal/schema/templates/number_value_value.gotmpl create mode 100644 internal/schema/templates/string_from.gotmpl create mode 100644 internal/schema/templates/string_to.gotmpl create mode 100644 internal/schema/templates/string_type_equal.gotmpl create mode 100644 internal/schema/templates/string_type_string.gotmpl create mode 100644 internal/schema/templates/string_type_typable.gotmpl create mode 100644 internal/schema/templates/string_type_type.gotmpl create mode 100644 internal/schema/templates/string_type_value_from_string.gotmpl create mode 100644 internal/schema/templates/string_type_value_from_terraform.gotmpl create mode 100644 internal/schema/templates/string_type_value_type.gotmpl create mode 100644 internal/schema/templates/string_value_equal.gotmpl create mode 100644 internal/schema/templates/string_value_type.gotmpl create mode 100644 internal/schema/templates/string_value_valuable.gotmpl create mode 100644 internal/schema/templates/string_value_value.gotmpl create mode 100644 internal/schema/to_from_float64.go create mode 100644 internal/schema/to_from_float64_test.go create mode 100644 internal/schema/to_from_int64.go create mode 100644 internal/schema/to_from_int64_test.go create mode 100644 internal/schema/to_from_number.go create mode 100644 internal/schema/to_from_number_test.go create mode 100644 internal/schema/to_from_string.go diff --git a/internal/datasource_generate/float64_attribute.go b/internal/datasource_generate/float64_attribute.go index 94bf69d6..18da604e 100644 --- a/internal/datasource_generate/float64_attribute.go +++ b/internal/datasource_generate/float64_attribute.go @@ -4,6 +4,7 @@ package datasource_generate import ( + "bytes" "fmt" "strings" "text/template" @@ -120,3 +121,49 @@ func (g GeneratorFloat64Attribute) ModelField(name generatorschema.FrameworkIden return field, nil } + +func (g GeneratorFloat64Attribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + float64Type := generatorschema.NewCustomFloat64Type(name) + + b, err := float64Type.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + float64Value := generatorschema.NewCustomFloat64Value(name) + + b, err = float64Value.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorFloat64Attribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromFloat64(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/datasource_generate/int64_attribute.go b/internal/datasource_generate/int64_attribute.go index 76d9ff0c..3531239d 100644 --- a/internal/datasource_generate/int64_attribute.go +++ b/internal/datasource_generate/int64_attribute.go @@ -4,6 +4,7 @@ package datasource_generate import ( + "bytes" "fmt" "strings" "text/template" @@ -120,3 +121,49 @@ func (g GeneratorInt64Attribute) ModelField(name generatorschema.FrameworkIdenti return field, nil } + +func (g GeneratorInt64Attribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + int64Type := generatorschema.NewCustomInt64Type(name) + + b, err := int64Type.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + int64Value := generatorschema.NewCustomInt64Value(name) + + b, err = int64Value.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorInt64Attribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromInt64(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/datasource_generate/number_attribute.go b/internal/datasource_generate/number_attribute.go index ff27f3d6..1d6f91e7 100644 --- a/internal/datasource_generate/number_attribute.go +++ b/internal/datasource_generate/number_attribute.go @@ -4,6 +4,7 @@ package datasource_generate import ( + "bytes" "fmt" "strings" "text/template" @@ -120,3 +121,49 @@ func (g GeneratorNumberAttribute) ModelField(name generatorschema.FrameworkIdent return field, nil } + +func (g GeneratorNumberAttribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + numberType := generatorschema.NewCustomNumberType(name) + + b, err := numberType.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + numberValue := generatorschema.NewCustomNumberValue(name) + + b, err = numberValue.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorNumberAttribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromNumber(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/datasource_generate/string_attribute.go b/internal/datasource_generate/string_attribute.go index 8727c049..247e622a 100644 --- a/internal/datasource_generate/string_attribute.go +++ b/internal/datasource_generate/string_attribute.go @@ -4,6 +4,7 @@ package datasource_generate import ( + "bytes" "fmt" "strings" "text/template" @@ -120,3 +121,49 @@ func (g GeneratorStringAttribute) ModelField(name generatorschema.FrameworkIdent return field, nil } + +func (g GeneratorStringAttribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + stringType := generatorschema.NewCustomStringType(name) + + b, err := stringType.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + stringValue := generatorschema.NewCustomStringValue(name) + + b, err = stringValue.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorStringAttribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromString(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/schema/custom_float64.go b/internal/schema/custom_float64.go new file mode 100644 index 00000000..703ac6fa --- /dev/null +++ b/internal/schema/custom_float64.go @@ -0,0 +1,345 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "bytes" + "text/template" +) + +type CustomFloat64Type struct { + Name FrameworkIdentifier + templates map[string]string +} + +func NewCustomFloat64Type(name string) CustomFloat64Type { + t := map[string]string{ + "equal": Float64TypeEqualTemplate, + "string": Float64TypeStringTemplate, + "type": Float64TypeTypeTemplate, + "typable": Float64TypeTypableTemplate, + "valueFromFloat64": Float64TypeValueFromFloat64Template, + "valueFromTerraform": Float64TypeValueFromTerraformTemplate, + "valueType": Float64TypeValueTypeTemplate, + } + + return CustomFloat64Type{ + Name: FrameworkIdentifier(name), + templates: t, + } +} + +func (c CustomFloat64Type) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + c.renderTypable, + c.renderType, + c.renderEqual, + c.renderString, + c.renderValueFromFloat64, + c.renderValueFromTerraform, + c.renderValueType, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Type) renderEqual() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["equal"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Type) renderString() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["string"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Type) renderType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["type"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Type) renderTypable() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["typable"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Type) renderValueFromFloat64() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueFromFloat64"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Type) renderValueFromTerraform() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueFromTerraform"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Type) renderValueType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueType"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type CustomFloat64Value struct { + Name FrameworkIdentifier + templates map[string]string +} + +func NewCustomFloat64Value(name string) CustomFloat64Value { + t := map[string]string{ + "equal": Float64ValueEqualTemplate, + "type": Float64ValueTypeTemplate, + "valuable": Float64ValueValuableTemplate, + "value": Float64ValueValueTemplate, + } + + return CustomFloat64Value{ + Name: FrameworkIdentifier(name), + templates: t, + } +} + +func (c CustomFloat64Value) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + c.renderValuable, + c.renderValue, + c.renderEqual, + c.renderType, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Value) renderEqual() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["equal"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Value) renderType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["type"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Value) renderValuable() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valuable"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomFloat64Value) renderValue() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["value"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/internal/schema/custom_float64_test.go b/internal/schema/custom_float64_test.go new file mode 100644 index 00000000..38749b94 --- /dev/null +++ b/internal/schema/custom_float64_test.go @@ -0,0 +1,460 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestCustomFloat64Type_renderEqual(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`func (t ExampleType) Equal(o attr.Type) bool { +other, ok := o.(ExampleType) + +if !ok { +return false +} + +return t.Float64Type.Equal(other.Float64Type) +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Type := NewCustomFloat64Type(testCase.name) + + got, err := customFloat64Type.renderEqual() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomFloat64Type_renderString(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) String() string { +return "ExampleType" +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Type := NewCustomFloat64Type(testCase.name) + + got, err := customFloat64Type.renderString() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomFloat64Type_renderTypable(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`var _ basetypes.Float64Typable = ExampleType{}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Type := NewCustomFloat64Type(testCase.name) + + got, err := customFloat64Type.renderTypable() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomFloat64Type_renderType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`type ExampleType struct { +basetypes.Float64Type +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Type := NewCustomFloat64Type(testCase.name) + + got, err := customFloat64Type.renderType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomFloat64Type_renderValueFromFloat64(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + attrValues map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + attrValues: map[string]string{ + "bool_attribute": "basetypes.Float64Value", + }, + expected: []byte(` +func (t ExampleType) ValueFromFloat64(ctx context.Context, in basetypes.Float64Value) (basetypes.Float64Valuable, diag.Diagnostics) { +return ExampleValue{ +Float64Value: in, +}, nil +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Type := NewCustomFloat64Type(testCase.name) + + got, err := customFloat64Type.renderValueFromFloat64() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomFloat64Type_renderValueFromTerraform(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +attrValue, err := t.Float64Type.ValueFromTerraform(ctx, in) + +if err != nil { +return nil, err +} + +boolValue, ok := attrValue.(basetypes.Float64Value) + +if !ok { +return nil, fmt.Errorf("unexpected value type of %T", attrValue) +} + +boolValuable, diags := t.ValueFromFloat64(ctx, boolValue) + +if diags.HasError() { +return nil, fmt.Errorf("unexpected error converting Float64Value to Float64Valuable: %v", diags) +} + +return boolValuable, nil +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Type := NewCustomFloat64Type(testCase.name) + + got, err := customFloat64Type.renderValueFromTerraform() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomFloat64Type_renderValueType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) ValueType(ctx context.Context) attr.Value { +return ExampleValue{} +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Type := NewCustomFloat64Type(testCase.name) + + got, err := customFloat64Type.renderValueType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomFloat64Value_renderEqual(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + attrValues map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + attrValues: map[string]string{ + "bool_attribute": "basetypes.Float64Value", + }, + expected: []byte(` +func (v ExampleValue) Equal(o attr.Value) bool { +other, ok := o.(ExampleValue) + +if !ok { +return false +} + +return v.Float64Value.Equal(other.Float64Value) +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Value := NewCustomFloat64Value(testCase.name) + + got, err := customFloat64Value.renderEqual() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomFloat64Value_renderType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (v ExampleValue) Type(ctx context.Context) attr.Type { +return ExampleType{ +} +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Value := NewCustomFloat64Value(testCase.name) + + got, err := customFloat64Value.renderType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomFloat64Value_renderValuable(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`var _ basetypes.Float64Valuable = ExampleValue{}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Value := NewCustomFloat64Value(testCase.name) + + got, err := customFloat64Value.renderValuable() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomFloat64Value_renderValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`type ExampleValue struct { +basetypes.Float64Value +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customFloat64Value := NewCustomFloat64Value(testCase.name) + + got, err := customFloat64Value.renderValue() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/internal/schema/custom_int64.go b/internal/schema/custom_int64.go new file mode 100644 index 00000000..a7ce57be --- /dev/null +++ b/internal/schema/custom_int64.go @@ -0,0 +1,345 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "bytes" + "text/template" +) + +type CustomInt64Type struct { + Name FrameworkIdentifier + templates map[string]string +} + +func NewCustomInt64Type(name string) CustomInt64Type { + t := map[string]string{ + "equal": Int64TypeEqualTemplate, + "string": Int64TypeStringTemplate, + "type": Int64TypeTypeTemplate, + "typable": Int64TypeTypableTemplate, + "valueFromInt64": Int64TypeValueFromInt64Template, + "valueFromTerraform": Int64TypeValueFromTerraformTemplate, + "valueType": Int64TypeValueTypeTemplate, + } + + return CustomInt64Type{ + Name: FrameworkIdentifier(name), + templates: t, + } +} + +func (c CustomInt64Type) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + c.renderTypable, + c.renderType, + c.renderEqual, + c.renderString, + c.renderValueFromInt64, + c.renderValueFromTerraform, + c.renderValueType, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Type) renderEqual() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["equal"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Type) renderString() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["string"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Type) renderType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["type"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Type) renderTypable() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["typable"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Type) renderValueFromInt64() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueFromInt64"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Type) renderValueFromTerraform() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueFromTerraform"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Type) renderValueType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueType"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type CustomInt64Value struct { + Name FrameworkIdentifier + templates map[string]string +} + +func NewCustomInt64Value(name string) CustomInt64Value { + t := map[string]string{ + "equal": Int64ValueEqualTemplate, + "type": Int64ValueTypeTemplate, + "valuable": Int64ValueValuableTemplate, + "value": Int64ValueValueTemplate, + } + + return CustomInt64Value{ + Name: FrameworkIdentifier(name), + templates: t, + } +} + +func (c CustomInt64Value) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + c.renderValuable, + c.renderValue, + c.renderEqual, + c.renderType, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Value) renderEqual() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["equal"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Value) renderType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["type"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Value) renderValuable() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valuable"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomInt64Value) renderValue() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["value"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/internal/schema/custom_int64_test.go b/internal/schema/custom_int64_test.go new file mode 100644 index 00000000..ad5047da --- /dev/null +++ b/internal/schema/custom_int64_test.go @@ -0,0 +1,460 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestCustomInt64Type_renderEqual(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`func (t ExampleType) Equal(o attr.Type) bool { +other, ok := o.(ExampleType) + +if !ok { +return false +} + +return t.Int64Type.Equal(other.Int64Type) +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Type := NewCustomInt64Type(testCase.name) + + got, err := customInt64Type.renderEqual() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomInt64Type_renderString(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) String() string { +return "ExampleType" +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Type := NewCustomInt64Type(testCase.name) + + got, err := customInt64Type.renderString() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomInt64Type_renderTypable(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`var _ basetypes.Int64Typable = ExampleType{}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Type := NewCustomInt64Type(testCase.name) + + got, err := customInt64Type.renderTypable() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomInt64Type_renderType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`type ExampleType struct { +basetypes.Int64Type +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Type := NewCustomInt64Type(testCase.name) + + got, err := customInt64Type.renderType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomInt64Type_renderValueFromInt64(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + attrValues map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + attrValues: map[string]string{ + "bool_attribute": "basetypes.Int64Value", + }, + expected: []byte(` +func (t ExampleType) ValueFromInt64(ctx context.Context, in basetypes.Int64Value) (basetypes.Int64Valuable, diag.Diagnostics) { +return ExampleValue{ +Int64Value: in, +}, nil +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Type := NewCustomInt64Type(testCase.name) + + got, err := customInt64Type.renderValueFromInt64() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomInt64Type_renderValueFromTerraform(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +attrValue, err := t.Int64Type.ValueFromTerraform(ctx, in) + +if err != nil { +return nil, err +} + +boolValue, ok := attrValue.(basetypes.Int64Value) + +if !ok { +return nil, fmt.Errorf("unexpected value type of %T", attrValue) +} + +boolValuable, diags := t.ValueFromInt64(ctx, boolValue) + +if diags.HasError() { +return nil, fmt.Errorf("unexpected error converting Int64Value to Int64Valuable: %v", diags) +} + +return boolValuable, nil +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Type := NewCustomInt64Type(testCase.name) + + got, err := customInt64Type.renderValueFromTerraform() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomInt64Type_renderValueType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) ValueType(ctx context.Context) attr.Value { +return ExampleValue{} +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Type := NewCustomInt64Type(testCase.name) + + got, err := customInt64Type.renderValueType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomInt64Value_renderEqual(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + attrValues map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + attrValues: map[string]string{ + "bool_attribute": "basetypes.Int64Value", + }, + expected: []byte(` +func (v ExampleValue) Equal(o attr.Value) bool { +other, ok := o.(ExampleValue) + +if !ok { +return false +} + +return v.Int64Value.Equal(other.Int64Value) +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Value := NewCustomInt64Value(testCase.name) + + got, err := customInt64Value.renderEqual() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomInt64Value_renderType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (v ExampleValue) Type(ctx context.Context) attr.Type { +return ExampleType{ +} +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Value := NewCustomInt64Value(testCase.name) + + got, err := customInt64Value.renderType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomInt64Value_renderValuable(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`var _ basetypes.Int64Valuable = ExampleValue{}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Value := NewCustomInt64Value(testCase.name) + + got, err := customInt64Value.renderValuable() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomInt64Value_renderValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`type ExampleValue struct { +basetypes.Int64Value +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customInt64Value := NewCustomInt64Value(testCase.name) + + got, err := customInt64Value.renderValue() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/internal/schema/custom_number.go b/internal/schema/custom_number.go new file mode 100644 index 00000000..b695469b --- /dev/null +++ b/internal/schema/custom_number.go @@ -0,0 +1,345 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "bytes" + "text/template" +) + +type CustomNumberType struct { + Name FrameworkIdentifier + templates map[string]string +} + +func NewCustomNumberType(name string) CustomNumberType { + t := map[string]string{ + "equal": NumberTypeEqualTemplate, + "string": NumberTypeStringTemplate, + "type": NumberTypeTypeTemplate, + "typable": NumberTypeTypableTemplate, + "valueFromNumber": NumberTypeValueFromNumberTemplate, + "valueFromTerraform": NumberTypeValueFromTerraformTemplate, + "valueType": NumberTypeValueTypeTemplate, + } + + return CustomNumberType{ + Name: FrameworkIdentifier(name), + templates: t, + } +} + +func (c CustomNumberType) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + c.renderTypable, + c.renderType, + c.renderEqual, + c.renderString, + c.renderValueFromNumber, + c.renderValueFromTerraform, + c.renderValueType, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (c CustomNumberType) renderEqual() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["equal"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomNumberType) renderString() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["string"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomNumberType) renderType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["type"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomNumberType) renderTypable() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["typable"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomNumberType) renderValueFromNumber() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueFromNumber"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomNumberType) renderValueFromTerraform() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueFromTerraform"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomNumberType) renderValueType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueType"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type CustomNumberValue struct { + Name FrameworkIdentifier + templates map[string]string +} + +func NewCustomNumberValue(name string) CustomNumberValue { + t := map[string]string{ + "equal": NumberValueEqualTemplate, + "type": NumberValueTypeTemplate, + "valuable": NumberValueValuableTemplate, + "value": NumberValueValueTemplate, + } + + return CustomNumberValue{ + Name: FrameworkIdentifier(name), + templates: t, + } +} + +func (c CustomNumberValue) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + c.renderValuable, + c.renderValue, + c.renderEqual, + c.renderType, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (c CustomNumberValue) renderEqual() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["equal"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomNumberValue) renderType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["type"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomNumberValue) renderValuable() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valuable"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomNumberValue) renderValue() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["value"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/internal/schema/custom_number_test.go b/internal/schema/custom_number_test.go new file mode 100644 index 00000000..fcca5d5f --- /dev/null +++ b/internal/schema/custom_number_test.go @@ -0,0 +1,460 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestCustomNumberType_renderEqual(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`func (t ExampleType) Equal(o attr.Type) bool { +other, ok := o.(ExampleType) + +if !ok { +return false +} + +return t.NumberType.Equal(other.NumberType) +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberType := NewCustomNumberType(testCase.name) + + got, err := customNumberType.renderEqual() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomNumberType_renderString(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) String() string { +return "ExampleType" +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberType := NewCustomNumberType(testCase.name) + + got, err := customNumberType.renderString() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomNumberType_renderTypable(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`var _ basetypes.NumberTypable = ExampleType{}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberType := NewCustomNumberType(testCase.name) + + got, err := customNumberType.renderTypable() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomNumberType_renderType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`type ExampleType struct { +basetypes.NumberType +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberType := NewCustomNumberType(testCase.name) + + got, err := customNumberType.renderType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomNumberType_renderValueFromNumber(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + attrValues map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + attrValues: map[string]string{ + "bool_attribute": "basetypes.NumberValue", + }, + expected: []byte(` +func (t ExampleType) ValueFromNumber(ctx context.Context, in basetypes.NumberValue) (basetypes.NumberValuable, diag.Diagnostics) { +return ExampleValue{ +NumberValue: in, +}, nil +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberType := NewCustomNumberType(testCase.name) + + got, err := customNumberType.renderValueFromNumber() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomNumberType_renderValueFromTerraform(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +attrValue, err := t.NumberType.ValueFromTerraform(ctx, in) + +if err != nil { +return nil, err +} + +boolValue, ok := attrValue.(basetypes.NumberValue) + +if !ok { +return nil, fmt.Errorf("unexpected value type of %T", attrValue) +} + +boolValuable, diags := t.ValueFromNumber(ctx, boolValue) + +if diags.HasError() { +return nil, fmt.Errorf("unexpected error converting NumberValue to NumberValuable: %v", diags) +} + +return boolValuable, nil +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberType := NewCustomNumberType(testCase.name) + + got, err := customNumberType.renderValueFromTerraform() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomNumberType_renderValueType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) ValueType(ctx context.Context) attr.Value { +return ExampleValue{} +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberType := NewCustomNumberType(testCase.name) + + got, err := customNumberType.renderValueType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomNumberValue_renderEqual(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + attrValues map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + attrValues: map[string]string{ + "bool_attribute": "basetypes.NumberValue", + }, + expected: []byte(` +func (v ExampleValue) Equal(o attr.Value) bool { +other, ok := o.(ExampleValue) + +if !ok { +return false +} + +return v.NumberValue.Equal(other.NumberValue) +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberValue := NewCustomNumberValue(testCase.name) + + got, err := customNumberValue.renderEqual() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomNumberValue_renderType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (v ExampleValue) Type(ctx context.Context) attr.Type { +return ExampleType{ +} +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberValue := NewCustomNumberValue(testCase.name) + + got, err := customNumberValue.renderType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomNumberValue_renderValuable(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`var _ basetypes.NumberValuable = ExampleValue{}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberValue := NewCustomNumberValue(testCase.name) + + got, err := customNumberValue.renderValuable() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomNumberValue_renderValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`type ExampleValue struct { +basetypes.NumberValue +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customNumberValue := NewCustomNumberValue(testCase.name) + + got, err := customNumberValue.renderValue() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/internal/schema/custom_string.go b/internal/schema/custom_string.go new file mode 100644 index 00000000..c028cc51 --- /dev/null +++ b/internal/schema/custom_string.go @@ -0,0 +1,345 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "bytes" + "text/template" +) + +type CustomStringType struct { + Name FrameworkIdentifier + templates map[string]string +} + +func NewCustomStringType(name string) CustomStringType { + t := map[string]string{ + "equal": StringTypeEqualTemplate, + "string": StringTypeStringTemplate, + "type": StringTypeTypeTemplate, + "typable": StringTypeTypableTemplate, + "valueFromString": StringTypeValueFromStringTemplate, + "valueFromTerraform": StringTypeValueFromTerraformTemplate, + "valueType": StringTypeValueTypeTemplate, + } + + return CustomStringType{ + Name: FrameworkIdentifier(name), + templates: t, + } +} + +func (c CustomStringType) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + c.renderTypable, + c.renderType, + c.renderEqual, + c.renderString, + c.renderValueFromString, + c.renderValueFromTerraform, + c.renderValueType, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (c CustomStringType) renderEqual() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["equal"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomStringType) renderString() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["string"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomStringType) renderType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["type"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomStringType) renderTypable() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["typable"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomStringType) renderValueFromString() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueFromString"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomStringType) renderValueFromTerraform() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueFromTerraform"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomStringType) renderValueType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valueType"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type CustomStringValue struct { + Name FrameworkIdentifier + templates map[string]string +} + +func NewCustomStringValue(name string) CustomStringValue { + t := map[string]string{ + "equal": StringValueEqualTemplate, + "type": StringValueTypeTemplate, + "valuable": StringValueValuableTemplate, + "value": StringValueValueTemplate, + } + + return CustomStringValue{ + Name: FrameworkIdentifier(name), + templates: t, + } +} + +func (c CustomStringValue) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + c.renderValuable, + c.renderValue, + c.renderEqual, + c.renderType, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (c CustomStringValue) renderEqual() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["equal"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomStringValue) renderType() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["type"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomStringValue) renderValuable() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["valuable"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (c CustomStringValue) renderValue() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(c.templates["value"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + }{ + Name: c.Name.ToPascalCase(), + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/internal/schema/embed.go b/internal/schema/embed.go index 9cfb57d8..a96bcf6c 100644 --- a/internal/schema/embed.go +++ b/internal/schema/embed.go @@ -52,7 +52,142 @@ var BoolValueValueTemplate string //go:embed templates/bool_value_valuable.gotmpl var BoolValueValuableTemplate string -// Object +// Float64 From/To + +//go:embed templates/float64_from.gotmpl +var Float64FromTemplate string + +//go:embed templates/float64_to.gotmpl +var Float64ToTemplate string + +// Float64 Type + +//go:embed templates/float64_type_equal.gotmpl +var Float64TypeEqualTemplate string + +//go:embed templates/float64_type_string.gotmpl +var Float64TypeStringTemplate string + +//go:embed templates/float64_type_type.gotmpl +var Float64TypeTypeTemplate string + +//go:embed templates/float64_type_typable.gotmpl +var Float64TypeTypableTemplate string + +//go:embed templates/float64_type_value_from_float64.gotmpl +var Float64TypeValueFromFloat64Template string + +//go:embed templates/float64_type_value_from_terraform.gotmpl +var Float64TypeValueFromTerraformTemplate string + +//go:embed templates/float64_type_value_type.gotmpl +var Float64TypeValueTypeTemplate string + +// Float64 Value + +//go:embed templates/float64_value_equal.gotmpl +var Float64ValueEqualTemplate string + +//go:embed templates/float64_value_type.gotmpl +var Float64ValueTypeTemplate string + +//go:embed templates/float64_value_value.gotmpl +var Float64ValueValueTemplate string + +//go:embed templates/float64_value_valuable.gotmpl +var Float64ValueValuableTemplate string + +// Int64 From/To + +//go:embed templates/int64_from.gotmpl +var Int64FromTemplate string + +//go:embed templates/int64_to.gotmpl +var Int64ToTemplate string + +// Int64 Type + +//go:embed templates/int64_type_equal.gotmpl +var Int64TypeEqualTemplate string + +//go:embed templates/int64_type_string.gotmpl +var Int64TypeStringTemplate string + +//go:embed templates/int64_type_type.gotmpl +var Int64TypeTypeTemplate string + +//go:embed templates/int64_type_typable.gotmpl +var Int64TypeTypableTemplate string + +//go:embed templates/int64_type_value_from_int64.gotmpl +var Int64TypeValueFromInt64Template string + +//go:embed templates/int64_type_value_from_terraform.gotmpl +var Int64TypeValueFromTerraformTemplate string + +//go:embed templates/int64_type_value_type.gotmpl +var Int64TypeValueTypeTemplate string + +// Int64 Value + +//go:embed templates/int64_value_equal.gotmpl +var Int64ValueEqualTemplate string + +//go:embed templates/int64_value_type.gotmpl +var Int64ValueTypeTemplate string + +//go:embed templates/int64_value_value.gotmpl +var Int64ValueValueTemplate string + +//go:embed templates/int64_value_valuable.gotmpl +var Int64ValueValuableTemplate string + +// Number From/To + +//go:embed templates/number_from.gotmpl +var NumberFromTemplate string + +//go:embed templates/number_to.gotmpl +var NumberToTemplate string + +// Number Type + +//go:embed templates/number_type_equal.gotmpl +var NumberTypeEqualTemplate string + +//go:embed templates/number_type_string.gotmpl +var NumberTypeStringTemplate string + +//go:embed templates/number_type_type.gotmpl +var NumberTypeTypeTemplate string + +//go:embed templates/number_type_typable.gotmpl +var NumberTypeTypableTemplate string + +//go:embed templates/number_type_value_from_number.gotmpl +var NumberTypeValueFromNumberTemplate string + +//go:embed templates/number_type_value_from_terraform.gotmpl +var NumberTypeValueFromTerraformTemplate string + +//go:embed templates/number_type_value_type.gotmpl +var NumberTypeValueTypeTemplate string + +// Number Value + +//go:embed templates/number_value_equal.gotmpl +var NumberValueEqualTemplate string + +//go:embed templates/number_value_type.gotmpl +var NumberValueTypeTemplate string + +//go:embed templates/number_value_value.gotmpl +var NumberValueValueTemplate string + +//go:embed templates/number_value_valuable.gotmpl +var NumberValueValuableTemplate string + +// Object From/To //go:embed templates/object_from.gotmpl var ObjectFromTemplate string @@ -129,3 +264,48 @@ var ObjectValueValueTemplate string //go:embed templates/schema.gotmpl var SchemaGoTemplate string + +// String From/To + +//go:embed templates/string_from.gotmpl +var StringFromTemplate string + +//go:embed templates/string_to.gotmpl +var StringToTemplate string + +// String Type + +//go:embed templates/string_type_equal.gotmpl +var StringTypeEqualTemplate string + +//go:embed templates/string_type_string.gotmpl +var StringTypeStringTemplate string + +//go:embed templates/string_type_type.gotmpl +var StringTypeTypeTemplate string + +//go:embed templates/string_type_typable.gotmpl +var StringTypeTypableTemplate string + +//go:embed templates/string_type_value_from_string.gotmpl +var StringTypeValueFromStringTemplate string + +//go:embed templates/string_type_value_from_terraform.gotmpl +var StringTypeValueFromTerraformTemplate string + +//go:embed templates/string_type_value_type.gotmpl +var StringTypeValueTypeTemplate string + +// String Value + +//go:embed templates/string_value_equal.gotmpl +var StringValueEqualTemplate string + +//go:embed templates/string_value_type.gotmpl +var StringValueTypeTemplate string + +//go:embed templates/string_value_value.gotmpl +var StringValueValueTemplate string + +//go:embed templates/string_value_valuable.gotmpl +var StringValueValuableTemplate string diff --git a/internal/schema/templates/float64_from.gotmpl b/internal/schema/templates/float64_from.gotmpl new file mode 100644 index 00000000..df820abc --- /dev/null +++ b/internal/schema/templates/float64_from.gotmpl @@ -0,0 +1,14 @@ + +func (v {{.Name}}Value) From{{.AssocExtType.ToPascalCase}}(ctx context.Context, apiObject {{.AssocExtType.Type}}) ({{.Name}}Value, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return {{.Name}}Value{ +types.Float64Null(), +}, diags +} + +return {{.Name}}Value{ +types.Float64PointerValue(*apiObject), +}, diags +} diff --git a/internal/schema/templates/float64_to.gotmpl b/internal/schema/templates/float64_to.gotmpl new file mode 100644 index 00000000..874259ea --- /dev/null +++ b/internal/schema/templates/float64_to.gotmpl @@ -0,0 +1,20 @@ +func (v {{.Name}}Value) To{{.AssocExtType.ToPascalCase}}(ctx context.Context) ({{.AssocExtType.Type}}, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"{{.Name}}Value Value Is Unknown", +`"{{.Name}}Value" is unknown.`, +)) + +return nil, diags +} + +a := {{.AssocExtType.TypeReference}}(v.ValueFloat64Pointer()) + +return &a, diags +} \ No newline at end of file diff --git a/internal/schema/templates/float64_type_equal.gotmpl b/internal/schema/templates/float64_type_equal.gotmpl new file mode 100644 index 00000000..963a06bd --- /dev/null +++ b/internal/schema/templates/float64_type_equal.gotmpl @@ -0,0 +1,9 @@ +func (t {{.Name}}Type) Equal(o attr.Type) bool { +other, ok := o.({{.Name}}Type) + +if !ok { +return false +} + +return t.Float64Type.Equal(other.Float64Type) +} \ No newline at end of file diff --git a/internal/schema/templates/float64_type_string.gotmpl b/internal/schema/templates/float64_type_string.gotmpl new file mode 100644 index 00000000..f01b8ac3 --- /dev/null +++ b/internal/schema/templates/float64_type_string.gotmpl @@ -0,0 +1,4 @@ + +func (t {{.Name}}Type) String() string { +return "{{.Name}}Type" +} \ No newline at end of file diff --git a/internal/schema/templates/float64_type_typable.gotmpl b/internal/schema/templates/float64_type_typable.gotmpl new file mode 100644 index 00000000..58c70d7c --- /dev/null +++ b/internal/schema/templates/float64_type_typable.gotmpl @@ -0,0 +1 @@ +var _ basetypes.Float64Typable = {{.Name}}Type{} \ No newline at end of file diff --git a/internal/schema/templates/float64_type_type.gotmpl b/internal/schema/templates/float64_type_type.gotmpl new file mode 100644 index 00000000..37410119 --- /dev/null +++ b/internal/schema/templates/float64_type_type.gotmpl @@ -0,0 +1,3 @@ +type {{.Name}}Type struct { +basetypes.Float64Type +} \ No newline at end of file diff --git a/internal/schema/templates/float64_type_value_from_float64.gotmpl b/internal/schema/templates/float64_type_value_from_float64.gotmpl new file mode 100644 index 00000000..8825dbc4 --- /dev/null +++ b/internal/schema/templates/float64_type_value_from_float64.gotmpl @@ -0,0 +1,6 @@ + +func (t {{.Name}}Type) ValueFromFloat64(ctx context.Context, in basetypes.Float64Value) (basetypes.Float64Valuable, diag.Diagnostics) { +return {{.Name}}Value{ +Float64Value: in, +}, nil +} \ No newline at end of file diff --git a/internal/schema/templates/float64_type_value_from_terraform.gotmpl b/internal/schema/templates/float64_type_value_from_terraform.gotmpl new file mode 100644 index 00000000..f1e6afc0 --- /dev/null +++ b/internal/schema/templates/float64_type_value_from_terraform.gotmpl @@ -0,0 +1,22 @@ + +func (t {{.Name}}Type) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +attrValue, err := t.Float64Type.ValueFromTerraform(ctx, in) + +if err != nil { +return nil, err +} + +boolValue, ok := attrValue.(basetypes.Float64Value) + +if !ok { +return nil, fmt.Errorf("unexpected value type of %T", attrValue) +} + +boolValuable, diags := t.ValueFromFloat64(ctx, boolValue) + +if diags.HasError() { +return nil, fmt.Errorf("unexpected error converting Float64Value to Float64Valuable: %v", diags) +} + +return boolValuable, nil +} \ No newline at end of file diff --git a/internal/schema/templates/float64_type_value_type.gotmpl b/internal/schema/templates/float64_type_value_type.gotmpl new file mode 100644 index 00000000..1f7b7fea --- /dev/null +++ b/internal/schema/templates/float64_type_value_type.gotmpl @@ -0,0 +1,4 @@ + +func (t {{.Name}}Type) ValueType(ctx context.Context) attr.Value { +return {{.Name}}Value{} +} \ No newline at end of file diff --git a/internal/schema/templates/float64_value_equal.gotmpl b/internal/schema/templates/float64_value_equal.gotmpl new file mode 100644 index 00000000..a6c75d60 --- /dev/null +++ b/internal/schema/templates/float64_value_equal.gotmpl @@ -0,0 +1,10 @@ + +func (v {{.Name}}Value) Equal(o attr.Value) bool { +other, ok := o.({{.Name}}Value) + +if !ok { +return false +} + +return v.Float64Value.Equal(other.Float64Value) +} \ No newline at end of file diff --git a/internal/schema/templates/float64_value_type.gotmpl b/internal/schema/templates/float64_value_type.gotmpl new file mode 100644 index 00000000..751cd5c0 --- /dev/null +++ b/internal/schema/templates/float64_value_type.gotmpl @@ -0,0 +1,5 @@ + +func (v {{.Name}}Value) Type(ctx context.Context) attr.Type { +return {{.Name}}Type{ +} +} \ No newline at end of file diff --git a/internal/schema/templates/float64_value_valuable.gotmpl b/internal/schema/templates/float64_value_valuable.gotmpl new file mode 100644 index 00000000..016b8f65 --- /dev/null +++ b/internal/schema/templates/float64_value_valuable.gotmpl @@ -0,0 +1 @@ +var _ basetypes.Float64Valuable = {{.Name}}Value{} \ No newline at end of file diff --git a/internal/schema/templates/float64_value_value.gotmpl b/internal/schema/templates/float64_value_value.gotmpl new file mode 100644 index 00000000..fdaacfb7 --- /dev/null +++ b/internal/schema/templates/float64_value_value.gotmpl @@ -0,0 +1,3 @@ +type {{.Name}}Value struct { +basetypes.Float64Value +} \ No newline at end of file diff --git a/internal/schema/templates/int64_from.gotmpl b/internal/schema/templates/int64_from.gotmpl new file mode 100644 index 00000000..5ece67b5 --- /dev/null +++ b/internal/schema/templates/int64_from.gotmpl @@ -0,0 +1,14 @@ + +func (v {{.Name}}Value) From{{.AssocExtType.ToPascalCase}}(ctx context.Context, apiObject {{.AssocExtType.Type}}) ({{.Name}}Value, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return {{.Name}}Value{ +types.Int64Null(), +}, diags +} + +return {{.Name}}Value{ +types.Int64PointerValue(*apiObject), +}, diags +} diff --git a/internal/schema/templates/int64_to.gotmpl b/internal/schema/templates/int64_to.gotmpl new file mode 100644 index 00000000..29f60285 --- /dev/null +++ b/internal/schema/templates/int64_to.gotmpl @@ -0,0 +1,20 @@ +func (v {{.Name}}Value) To{{.AssocExtType.ToPascalCase}}(ctx context.Context) ({{.AssocExtType.Type}}, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"{{.Name}}Value Value Is Unknown", +`"{{.Name}}Value" is unknown.`, +)) + +return nil, diags +} + +a := {{.AssocExtType.TypeReference}}(v.ValueInt64Pointer()) + +return &a, diags +} \ No newline at end of file diff --git a/internal/schema/templates/int64_type_equal.gotmpl b/internal/schema/templates/int64_type_equal.gotmpl new file mode 100644 index 00000000..2f39bd1f --- /dev/null +++ b/internal/schema/templates/int64_type_equal.gotmpl @@ -0,0 +1,9 @@ +func (t {{.Name}}Type) Equal(o attr.Type) bool { +other, ok := o.({{.Name}}Type) + +if !ok { +return false +} + +return t.Int64Type.Equal(other.Int64Type) +} \ No newline at end of file diff --git a/internal/schema/templates/int64_type_string.gotmpl b/internal/schema/templates/int64_type_string.gotmpl new file mode 100644 index 00000000..f01b8ac3 --- /dev/null +++ b/internal/schema/templates/int64_type_string.gotmpl @@ -0,0 +1,4 @@ + +func (t {{.Name}}Type) String() string { +return "{{.Name}}Type" +} \ No newline at end of file diff --git a/internal/schema/templates/int64_type_typable.gotmpl b/internal/schema/templates/int64_type_typable.gotmpl new file mode 100644 index 00000000..4326600e --- /dev/null +++ b/internal/schema/templates/int64_type_typable.gotmpl @@ -0,0 +1 @@ +var _ basetypes.Int64Typable = {{.Name}}Type{} \ No newline at end of file diff --git a/internal/schema/templates/int64_type_type.gotmpl b/internal/schema/templates/int64_type_type.gotmpl new file mode 100644 index 00000000..ce3dd42e --- /dev/null +++ b/internal/schema/templates/int64_type_type.gotmpl @@ -0,0 +1,3 @@ +type {{.Name}}Type struct { +basetypes.Int64Type +} \ No newline at end of file diff --git a/internal/schema/templates/int64_type_value_from_int64.gotmpl b/internal/schema/templates/int64_type_value_from_int64.gotmpl new file mode 100644 index 00000000..ed5158c6 --- /dev/null +++ b/internal/schema/templates/int64_type_value_from_int64.gotmpl @@ -0,0 +1,6 @@ + +func (t {{.Name}}Type) ValueFromInt64(ctx context.Context, in basetypes.Int64Value) (basetypes.Int64Valuable, diag.Diagnostics) { +return {{.Name}}Value{ +Int64Value: in, +}, nil +} \ No newline at end of file diff --git a/internal/schema/templates/int64_type_value_from_terraform.gotmpl b/internal/schema/templates/int64_type_value_from_terraform.gotmpl new file mode 100644 index 00000000..0b497fd9 --- /dev/null +++ b/internal/schema/templates/int64_type_value_from_terraform.gotmpl @@ -0,0 +1,22 @@ + +func (t {{.Name}}Type) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +attrValue, err := t.Int64Type.ValueFromTerraform(ctx, in) + +if err != nil { +return nil, err +} + +boolValue, ok := attrValue.(basetypes.Int64Value) + +if !ok { +return nil, fmt.Errorf("unexpected value type of %T", attrValue) +} + +boolValuable, diags := t.ValueFromInt64(ctx, boolValue) + +if diags.HasError() { +return nil, fmt.Errorf("unexpected error converting Int64Value to Int64Valuable: %v", diags) +} + +return boolValuable, nil +} \ No newline at end of file diff --git a/internal/schema/templates/int64_type_value_type.gotmpl b/internal/schema/templates/int64_type_value_type.gotmpl new file mode 100644 index 00000000..1f7b7fea --- /dev/null +++ b/internal/schema/templates/int64_type_value_type.gotmpl @@ -0,0 +1,4 @@ + +func (t {{.Name}}Type) ValueType(ctx context.Context) attr.Value { +return {{.Name}}Value{} +} \ No newline at end of file diff --git a/internal/schema/templates/int64_value_equal.gotmpl b/internal/schema/templates/int64_value_equal.gotmpl new file mode 100644 index 00000000..5903da86 --- /dev/null +++ b/internal/schema/templates/int64_value_equal.gotmpl @@ -0,0 +1,10 @@ + +func (v {{.Name}}Value) Equal(o attr.Value) bool { +other, ok := o.({{.Name}}Value) + +if !ok { +return false +} + +return v.Int64Value.Equal(other.Int64Value) +} \ No newline at end of file diff --git a/internal/schema/templates/int64_value_type.gotmpl b/internal/schema/templates/int64_value_type.gotmpl new file mode 100644 index 00000000..751cd5c0 --- /dev/null +++ b/internal/schema/templates/int64_value_type.gotmpl @@ -0,0 +1,5 @@ + +func (v {{.Name}}Value) Type(ctx context.Context) attr.Type { +return {{.Name}}Type{ +} +} \ No newline at end of file diff --git a/internal/schema/templates/int64_value_valuable.gotmpl b/internal/schema/templates/int64_value_valuable.gotmpl new file mode 100644 index 00000000..a2245552 --- /dev/null +++ b/internal/schema/templates/int64_value_valuable.gotmpl @@ -0,0 +1 @@ +var _ basetypes.Int64Valuable = {{.Name}}Value{} \ No newline at end of file diff --git a/internal/schema/templates/int64_value_value.gotmpl b/internal/schema/templates/int64_value_value.gotmpl new file mode 100644 index 00000000..2258d505 --- /dev/null +++ b/internal/schema/templates/int64_value_value.gotmpl @@ -0,0 +1,3 @@ +type {{.Name}}Value struct { +basetypes.Int64Value +} \ No newline at end of file diff --git a/internal/schema/templates/number_from.gotmpl b/internal/schema/templates/number_from.gotmpl new file mode 100644 index 00000000..33439da7 --- /dev/null +++ b/internal/schema/templates/number_from.gotmpl @@ -0,0 +1,14 @@ + +func (v {{.Name}}Value) From{{.AssocExtType.ToPascalCase}}(ctx context.Context, apiObject {{.AssocExtType.Type}}) ({{.Name}}Value, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return {{.Name}}Value{ +types.NumberNull(), +}, diags +} + +return {{.Name}}Value{ +types.NumberValue(*apiObject), +}, diags +} diff --git a/internal/schema/templates/number_to.gotmpl b/internal/schema/templates/number_to.gotmpl new file mode 100644 index 00000000..62c41cf1 --- /dev/null +++ b/internal/schema/templates/number_to.gotmpl @@ -0,0 +1,20 @@ +func (v {{.Name}}Value) To{{.AssocExtType.ToPascalCase}}(ctx context.Context) ({{.AssocExtType.Type}}, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"{{.Name}}Value Value Is Unknown", +`"{{.Name}}Value" is unknown.`, +)) + +return nil, diags +} + +a := {{.AssocExtType.TypeReference}}(v.ValueBigFloat()) + +return &a, diags +} \ No newline at end of file diff --git a/internal/schema/templates/number_type_equal.gotmpl b/internal/schema/templates/number_type_equal.gotmpl new file mode 100644 index 00000000..be8f84fa --- /dev/null +++ b/internal/schema/templates/number_type_equal.gotmpl @@ -0,0 +1,9 @@ +func (t {{.Name}}Type) Equal(o attr.Type) bool { +other, ok := o.({{.Name}}Type) + +if !ok { +return false +} + +return t.NumberType.Equal(other.NumberType) +} \ No newline at end of file diff --git a/internal/schema/templates/number_type_string.gotmpl b/internal/schema/templates/number_type_string.gotmpl new file mode 100644 index 00000000..f01b8ac3 --- /dev/null +++ b/internal/schema/templates/number_type_string.gotmpl @@ -0,0 +1,4 @@ + +func (t {{.Name}}Type) String() string { +return "{{.Name}}Type" +} \ No newline at end of file diff --git a/internal/schema/templates/number_type_typable.gotmpl b/internal/schema/templates/number_type_typable.gotmpl new file mode 100644 index 00000000..9c8525ec --- /dev/null +++ b/internal/schema/templates/number_type_typable.gotmpl @@ -0,0 +1 @@ +var _ basetypes.NumberTypable = {{.Name}}Type{} \ No newline at end of file diff --git a/internal/schema/templates/number_type_type.gotmpl b/internal/schema/templates/number_type_type.gotmpl new file mode 100644 index 00000000..3f9d3dc7 --- /dev/null +++ b/internal/schema/templates/number_type_type.gotmpl @@ -0,0 +1,3 @@ +type {{.Name}}Type struct { +basetypes.NumberType +} \ No newline at end of file diff --git a/internal/schema/templates/number_type_value_from_number.gotmpl b/internal/schema/templates/number_type_value_from_number.gotmpl new file mode 100644 index 00000000..a2c7b7d4 --- /dev/null +++ b/internal/schema/templates/number_type_value_from_number.gotmpl @@ -0,0 +1,6 @@ + +func (t {{.Name}}Type) ValueFromNumber(ctx context.Context, in basetypes.NumberValue) (basetypes.NumberValuable, diag.Diagnostics) { +return {{.Name}}Value{ +NumberValue: in, +}, nil +} \ No newline at end of file diff --git a/internal/schema/templates/number_type_value_from_terraform.gotmpl b/internal/schema/templates/number_type_value_from_terraform.gotmpl new file mode 100644 index 00000000..d0f9d7bb --- /dev/null +++ b/internal/schema/templates/number_type_value_from_terraform.gotmpl @@ -0,0 +1,22 @@ + +func (t {{.Name}}Type) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +attrValue, err := t.NumberType.ValueFromTerraform(ctx, in) + +if err != nil { +return nil, err +} + +boolValue, ok := attrValue.(basetypes.NumberValue) + +if !ok { +return nil, fmt.Errorf("unexpected value type of %T", attrValue) +} + +boolValuable, diags := t.ValueFromNumber(ctx, boolValue) + +if diags.HasError() { +return nil, fmt.Errorf("unexpected error converting NumberValue to NumberValuable: %v", diags) +} + +return boolValuable, nil +} \ No newline at end of file diff --git a/internal/schema/templates/number_type_value_type.gotmpl b/internal/schema/templates/number_type_value_type.gotmpl new file mode 100644 index 00000000..1f7b7fea --- /dev/null +++ b/internal/schema/templates/number_type_value_type.gotmpl @@ -0,0 +1,4 @@ + +func (t {{.Name}}Type) ValueType(ctx context.Context) attr.Value { +return {{.Name}}Value{} +} \ No newline at end of file diff --git a/internal/schema/templates/number_value_equal.gotmpl b/internal/schema/templates/number_value_equal.gotmpl new file mode 100644 index 00000000..75110605 --- /dev/null +++ b/internal/schema/templates/number_value_equal.gotmpl @@ -0,0 +1,10 @@ + +func (v {{.Name}}Value) Equal(o attr.Value) bool { +other, ok := o.({{.Name}}Value) + +if !ok { +return false +} + +return v.NumberValue.Equal(other.NumberValue) +} \ No newline at end of file diff --git a/internal/schema/templates/number_value_type.gotmpl b/internal/schema/templates/number_value_type.gotmpl new file mode 100644 index 00000000..751cd5c0 --- /dev/null +++ b/internal/schema/templates/number_value_type.gotmpl @@ -0,0 +1,5 @@ + +func (v {{.Name}}Value) Type(ctx context.Context) attr.Type { +return {{.Name}}Type{ +} +} \ No newline at end of file diff --git a/internal/schema/templates/number_value_valuable.gotmpl b/internal/schema/templates/number_value_valuable.gotmpl new file mode 100644 index 00000000..bf1163c6 --- /dev/null +++ b/internal/schema/templates/number_value_valuable.gotmpl @@ -0,0 +1 @@ +var _ basetypes.NumberValuable = {{.Name}}Value{} \ No newline at end of file diff --git a/internal/schema/templates/number_value_value.gotmpl b/internal/schema/templates/number_value_value.gotmpl new file mode 100644 index 00000000..1513cdf1 --- /dev/null +++ b/internal/schema/templates/number_value_value.gotmpl @@ -0,0 +1,3 @@ +type {{.Name}}Value struct { +basetypes.NumberValue +} \ No newline at end of file diff --git a/internal/schema/templates/string_from.gotmpl b/internal/schema/templates/string_from.gotmpl new file mode 100644 index 00000000..8b4d91ed --- /dev/null +++ b/internal/schema/templates/string_from.gotmpl @@ -0,0 +1,14 @@ + +func (v {{.Name}}Value) From{{.AssocExtType.ToPascalCase}}(ctx context.Context, apiObject {{.AssocExtType.Type}}) ({{.Name}}Value, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return {{.Name}}Value{ +types.StringNull(), +}, diags +} + +return {{.Name}}Value{ +types.StringPointerValue(*apiObject), +}, diags +} diff --git a/internal/schema/templates/string_to.gotmpl b/internal/schema/templates/string_to.gotmpl new file mode 100644 index 00000000..324f8e97 --- /dev/null +++ b/internal/schema/templates/string_to.gotmpl @@ -0,0 +1,20 @@ +func (v {{.Name}}Value) To{{.AssocExtType.ToPascalCase}}(ctx context.Context) ({{.AssocExtType.Type}}, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"{{.Name}}Value Value Is Unknown", +`"{{.Name}}Value" is unknown.`, +)) + +return nil, diags +} + +a := {{.AssocExtType.TypeReference}}(v.ValueStringPointer()) + +return &a, diags +} \ No newline at end of file diff --git a/internal/schema/templates/string_type_equal.gotmpl b/internal/schema/templates/string_type_equal.gotmpl new file mode 100644 index 00000000..ac101aef --- /dev/null +++ b/internal/schema/templates/string_type_equal.gotmpl @@ -0,0 +1,9 @@ +func (t {{.Name}}Type) Equal(o attr.Type) bool { +other, ok := o.({{.Name}}Type) + +if !ok { +return false +} + +return t.StringType.Equal(other.StringType) +} \ No newline at end of file diff --git a/internal/schema/templates/string_type_string.gotmpl b/internal/schema/templates/string_type_string.gotmpl new file mode 100644 index 00000000..f01b8ac3 --- /dev/null +++ b/internal/schema/templates/string_type_string.gotmpl @@ -0,0 +1,4 @@ + +func (t {{.Name}}Type) String() string { +return "{{.Name}}Type" +} \ No newline at end of file diff --git a/internal/schema/templates/string_type_typable.gotmpl b/internal/schema/templates/string_type_typable.gotmpl new file mode 100644 index 00000000..5d8d5aae --- /dev/null +++ b/internal/schema/templates/string_type_typable.gotmpl @@ -0,0 +1 @@ +var _ basetypes.StringTypable = {{.Name}}Type{} \ No newline at end of file diff --git a/internal/schema/templates/string_type_type.gotmpl b/internal/schema/templates/string_type_type.gotmpl new file mode 100644 index 00000000..18e62918 --- /dev/null +++ b/internal/schema/templates/string_type_type.gotmpl @@ -0,0 +1,3 @@ +type {{.Name}}Type struct { +basetypes.StringType +} \ No newline at end of file diff --git a/internal/schema/templates/string_type_value_from_string.gotmpl b/internal/schema/templates/string_type_value_from_string.gotmpl new file mode 100644 index 00000000..d8abf943 --- /dev/null +++ b/internal/schema/templates/string_type_value_from_string.gotmpl @@ -0,0 +1,6 @@ + +func (t {{.Name}}Type) ValueFromString(ctx context.Context, in basetypes.StringValue) (basetypes.StringValuable, diag.Diagnostics) { +return {{.Name}}Value{ +StringValue: in, +}, nil +} \ No newline at end of file diff --git a/internal/schema/templates/string_type_value_from_terraform.gotmpl b/internal/schema/templates/string_type_value_from_terraform.gotmpl new file mode 100644 index 00000000..cac59c10 --- /dev/null +++ b/internal/schema/templates/string_type_value_from_terraform.gotmpl @@ -0,0 +1,22 @@ + +func (t {{.Name}}Type) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +attrValue, err := t.StringType.ValueFromTerraform(ctx, in) + +if err != nil { +return nil, err +} + +boolValue, ok := attrValue.(basetypes.StringValue) + +if !ok { +return nil, fmt.Errorf("unexpected value type of %T", attrValue) +} + +boolValuable, diags := t.ValueFromString(ctx, boolValue) + +if diags.HasError() { +return nil, fmt.Errorf("unexpected error converting StringValue to StringValuable: %v", diags) +} + +return boolValuable, nil +} \ No newline at end of file diff --git a/internal/schema/templates/string_type_value_type.gotmpl b/internal/schema/templates/string_type_value_type.gotmpl new file mode 100644 index 00000000..1f7b7fea --- /dev/null +++ b/internal/schema/templates/string_type_value_type.gotmpl @@ -0,0 +1,4 @@ + +func (t {{.Name}}Type) ValueType(ctx context.Context) attr.Value { +return {{.Name}}Value{} +} \ No newline at end of file diff --git a/internal/schema/templates/string_value_equal.gotmpl b/internal/schema/templates/string_value_equal.gotmpl new file mode 100644 index 00000000..572a2838 --- /dev/null +++ b/internal/schema/templates/string_value_equal.gotmpl @@ -0,0 +1,10 @@ + +func (v {{.Name}}Value) Equal(o attr.Value) bool { +other, ok := o.({{.Name}}Value) + +if !ok { +return false +} + +return v.StringValue.Equal(other.StringValue) +} \ No newline at end of file diff --git a/internal/schema/templates/string_value_type.gotmpl b/internal/schema/templates/string_value_type.gotmpl new file mode 100644 index 00000000..751cd5c0 --- /dev/null +++ b/internal/schema/templates/string_value_type.gotmpl @@ -0,0 +1,5 @@ + +func (v {{.Name}}Value) Type(ctx context.Context) attr.Type { +return {{.Name}}Type{ +} +} \ No newline at end of file diff --git a/internal/schema/templates/string_value_valuable.gotmpl b/internal/schema/templates/string_value_valuable.gotmpl new file mode 100644 index 00000000..aa7d1377 --- /dev/null +++ b/internal/schema/templates/string_value_valuable.gotmpl @@ -0,0 +1 @@ +var _ basetypes.StringValuable = {{.Name}}Value{} \ No newline at end of file diff --git a/internal/schema/templates/string_value_value.gotmpl b/internal/schema/templates/string_value_value.gotmpl new file mode 100644 index 00000000..d1bcf39d --- /dev/null +++ b/internal/schema/templates/string_value_value.gotmpl @@ -0,0 +1,3 @@ +type {{.Name}}Value struct { +basetypes.StringValue +} \ No newline at end of file diff --git a/internal/schema/to_from_float64.go b/internal/schema/to_from_float64.go new file mode 100644 index 00000000..44f2d1ac --- /dev/null +++ b/internal/schema/to_from_float64.go @@ -0,0 +1,99 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "bytes" + "text/template" +) + +type ToFromFloat64 struct { + Name FrameworkIdentifier + AssocExtType *AssocExtType + templates map[string]string +} + +func NewToFromFloat64(name string, assocExtType *AssocExtType) ToFromFloat64 { + t := map[string]string{ + "from": Float64FromTemplate, + "to": Float64ToTemplate, + } + + return ToFromFloat64{ + Name: FrameworkIdentifier(name), + AssocExtType: assocExtType, + templates: t, + } +} + +func (o ToFromFloat64) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + o.renderTo, + o.renderFrom, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (o ToFromFloat64) renderTo() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["to"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (o ToFromFloat64) renderFrom() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["from"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/internal/schema/to_from_float64_test.go b/internal/schema/to_from_float64_test.go new file mode 100644 index 00000000..f149b0f2 --- /dev/null +++ b/internal/schema/to_from_float64_test.go @@ -0,0 +1,133 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-codegen-spec/code" + "github.com/hashicorp/terraform-plugin-codegen-spec/schema" +) + +func TestToFromFloat64_renderFrom(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + expected: []byte(` +func (v ExampleValue) FromApisdkType(ctx context.Context, apiObject *apisdk.Type) (ExampleValue, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return ExampleValue{ +types.Float64Null(), +}, diags +} + +return ExampleValue{ +types.Float64PointerValue(*apiObject), +}, diags +} +`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromFloat64 := NewToFromFloat64(testCase.name, testCase.assocExtType) + + got, err := toFromFloat64.renderFrom() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestToFromFloat64_renderTo(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + expected: []byte(`func (v ExampleValue) ToApisdkType(ctx context.Context) (*apisdk.Type, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"ExampleValue Value Is Unknown", +` + "`" + `"ExampleValue" is unknown.` + "`" + `, +)) + +return nil, diags +} + +a := apisdk.Type(v.ValueFloat64Pointer()) + +return &a, diags +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromFloat64 := NewToFromFloat64(testCase.name, testCase.assocExtType) + + got, err := toFromFloat64.renderTo() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/internal/schema/to_from_int64.go b/internal/schema/to_from_int64.go new file mode 100644 index 00000000..82beddb5 --- /dev/null +++ b/internal/schema/to_from_int64.go @@ -0,0 +1,99 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "bytes" + "text/template" +) + +type ToFromInt64 struct { + Name FrameworkIdentifier + AssocExtType *AssocExtType + templates map[string]string +} + +func NewToFromInt64(name string, assocExtType *AssocExtType) ToFromInt64 { + t := map[string]string{ + "from": Int64FromTemplate, + "to": Int64ToTemplate, + } + + return ToFromInt64{ + Name: FrameworkIdentifier(name), + AssocExtType: assocExtType, + templates: t, + } +} + +func (o ToFromInt64) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + o.renderTo, + o.renderFrom, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (o ToFromInt64) renderTo() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["to"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (o ToFromInt64) renderFrom() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["from"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/internal/schema/to_from_int64_test.go b/internal/schema/to_from_int64_test.go new file mode 100644 index 00000000..02af2fa1 --- /dev/null +++ b/internal/schema/to_from_int64_test.go @@ -0,0 +1,133 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-codegen-spec/code" + "github.com/hashicorp/terraform-plugin-codegen-spec/schema" +) + +func TestToFromInt64_renderFrom(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + expected: []byte(` +func (v ExampleValue) FromApisdkType(ctx context.Context, apiObject *apisdk.Type) (ExampleValue, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return ExampleValue{ +types.Int64Null(), +}, diags +} + +return ExampleValue{ +types.Int64PointerValue(*apiObject), +}, diags +} +`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromInt64 := NewToFromInt64(testCase.name, testCase.assocExtType) + + got, err := toFromInt64.renderFrom() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestToFromInt64_renderTo(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + expected: []byte(`func (v ExampleValue) ToApisdkType(ctx context.Context) (*apisdk.Type, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"ExampleValue Value Is Unknown", +` + "`" + `"ExampleValue" is unknown.` + "`" + `, +)) + +return nil, diags +} + +a := apisdk.Type(v.ValueInt64Pointer()) + +return &a, diags +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromInt64 := NewToFromInt64(testCase.name, testCase.assocExtType) + + got, err := toFromInt64.renderTo() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/internal/schema/to_from_number.go b/internal/schema/to_from_number.go new file mode 100644 index 00000000..3a78cb90 --- /dev/null +++ b/internal/schema/to_from_number.go @@ -0,0 +1,99 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "bytes" + "text/template" +) + +type ToFromNumber struct { + Name FrameworkIdentifier + AssocExtType *AssocExtType + templates map[string]string +} + +func NewToFromNumber(name string, assocExtType *AssocExtType) ToFromNumber { + t := map[string]string{ + "from": NumberFromTemplate, + "to": NumberToTemplate, + } + + return ToFromNumber{ + Name: FrameworkIdentifier(name), + AssocExtType: assocExtType, + templates: t, + } +} + +func (o ToFromNumber) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + o.renderTo, + o.renderFrom, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (o ToFromNumber) renderTo() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["to"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (o ToFromNumber) renderFrom() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["from"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/internal/schema/to_from_number_test.go b/internal/schema/to_from_number_test.go new file mode 100644 index 00000000..4eaa4ffd --- /dev/null +++ b/internal/schema/to_from_number_test.go @@ -0,0 +1,133 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-codegen-spec/code" + "github.com/hashicorp/terraform-plugin-codegen-spec/schema" +) + +func TestToFromNumber_renderFrom(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + expected: []byte(` +func (v ExampleValue) FromApisdkType(ctx context.Context, apiObject *apisdk.Type) (ExampleValue, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return ExampleValue{ +types.NumberNull(), +}, diags +} + +return ExampleValue{ +types.NumberValue(*apiObject), +}, diags +} +`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromNumber := NewToFromNumber(testCase.name, testCase.assocExtType) + + got, err := toFromNumber.renderFrom() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestToFromNumber_renderTo(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + expected: []byte(`func (v ExampleValue) ToApisdkType(ctx context.Context) (*apisdk.Type, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"ExampleValue Value Is Unknown", +` + "`" + `"ExampleValue" is unknown.` + "`" + `, +)) + +return nil, diags +} + +a := apisdk.Type(v.ValueBigFloat()) + +return &a, diags +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromNumber := NewToFromNumber(testCase.name, testCase.assocExtType) + + got, err := toFromNumber.renderTo() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/internal/schema/to_from_string.go b/internal/schema/to_from_string.go new file mode 100644 index 00000000..64c10125 --- /dev/null +++ b/internal/schema/to_from_string.go @@ -0,0 +1,99 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "bytes" + "text/template" +) + +type ToFromString struct { + Name FrameworkIdentifier + AssocExtType *AssocExtType + templates map[string]string +} + +func NewToFromString(name string, assocExtType *AssocExtType) ToFromString { + t := map[string]string{ + "from": StringFromTemplate, + "to": StringToTemplate, + } + + return ToFromString{ + Name: FrameworkIdentifier(name), + AssocExtType: assocExtType, + templates: t, + } +} + +func (o ToFromString) Render() ([]byte, error) { + var buf bytes.Buffer + + renderFuncs := []func() ([]byte, error){ + o.renderTo, + o.renderFrom, + } + + for _, f := range renderFuncs { + b, err := f() + + if err != nil { + return nil, err + } + + buf.Write([]byte("\n")) + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +func (o ToFromString) renderTo() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["to"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (o ToFromString) renderFrom() ([]byte, error) { + var buf bytes.Buffer + + t, err := template.New("").Parse(o.templates["from"]) + + if err != nil { + return nil, err + } + + err = t.Execute(&buf, struct { + Name string + AssocExtType *AssocExtType + }{ + Name: o.Name.ToPascalCase(), + AssocExtType: o.AssocExtType, + }) + + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} From ac34c1a70f09d5ca5373e425021038cfe67030da Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 17 Oct 2023 14:54:00 +0100 Subject: [PATCH 14/19] Setting up generation of custom type and value types and to/from functions for provider and resource bool, float64, int64, number, and string attributes --- internal/provider_convert/bool_attribute.go | 7 +- .../provider_convert/float64_attribute.go | 7 +- internal/provider_convert/int64_attribute.go | 7 +- internal/provider_convert/number_attribute.go | 7 +- internal/provider_convert/string_attribute.go | 7 +- internal/provider_generate/bool_attribute.go | 73 ++++++++++++- internal/provider_generate/embed.go | 21 +++- .../provider_generate/float64_attribute.go | 72 ++++++++++++- internal/provider_generate/int64_attribute.go | 72 ++++++++++++- .../provider_generate/number_attribute.go | 101 +++++++++++++----- .../provider_generate/string_attribute.go | 72 ++++++++++++- .../templates/attribute.gotmpl | 22 ++++ .../templates/bool_attribute.gotmpl | 3 + .../templates/float64_attribute.gotmpl | 3 + .../templates/int64_attribute.gotmpl | 3 + .../templates/number_attribute.gotmpl | 3 + .../templates/string_attribute.gotmpl | 3 + internal/resource_convert/bool_attribute.go | 11 +- .../resource_convert/float64_attribute.go | 11 +- internal/resource_convert/int64_attribute.go | 11 +- internal/resource_convert/number_attribute.go | 11 +- internal/resource_convert/string_attribute.go | 11 +- internal/resource_generate/bool_attribute.go | 72 ++++++++++++- internal/resource_generate/embed.go | 21 +++- .../resource_generate/float64_attribute.go | 71 +++++++++++- internal/resource_generate/int64_attribute.go | 71 +++++++++++- .../resource_generate/number_attribute.go | 72 ++++++++++++- .../resource_generate/string_attribute.go | 71 +++++++++++- .../templates/attribute.gotmpl | 26 +++++ .../templates/bool_attribute.gotmpl | 3 + .../templates/float64_attribute.gotmpl | 3 + .../templates/int64_attribute.gotmpl | 3 + .../templates/number_attribute.gotmpl | 3 + .../templates/string_attribute.gotmpl | 3 + 34 files changed, 861 insertions(+), 96 deletions(-) create mode 100644 internal/provider_generate/templates/attribute.gotmpl create mode 100644 internal/resource_generate/templates/attribute.gotmpl diff --git a/internal/provider_convert/bool_attribute.go b/internal/provider_convert/bool_attribute.go index d8d9a832..266603ba 100644 --- a/internal/provider_convert/bool_attribute.go +++ b/internal/provider_convert/bool_attribute.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/provider_generate" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func convertBoolAttribute(a *provider.BoolAttribute) (provider_generate.GeneratorBoolAttribute, error) { @@ -26,7 +27,9 @@ func convertBoolAttribute(a *provider.BoolAttribute) (provider_generate.Generato MarkdownDescription: description(a.Description), DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Validators: a.Validators, + + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Validators: a.Validators, }, nil } diff --git a/internal/provider_convert/float64_attribute.go b/internal/provider_convert/float64_attribute.go index 375e3f1b..d3aa8408 100644 --- a/internal/provider_convert/float64_attribute.go +++ b/internal/provider_convert/float64_attribute.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/provider_generate" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func convertFloat64Attribute(a *provider.Float64Attribute) (provider_generate.GeneratorFloat64Attribute, error) { @@ -26,7 +27,9 @@ func convertFloat64Attribute(a *provider.Float64Attribute) (provider_generate.Ge MarkdownDescription: description(a.Description), DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Validators: a.Validators, + + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Validators: a.Validators, }, nil } diff --git a/internal/provider_convert/int64_attribute.go b/internal/provider_convert/int64_attribute.go index 9e11c98c..fc8756b9 100644 --- a/internal/provider_convert/int64_attribute.go +++ b/internal/provider_convert/int64_attribute.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/provider_generate" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func convertInt64Attribute(a *provider.Int64Attribute) (provider_generate.GeneratorInt64Attribute, error) { @@ -26,7 +27,9 @@ func convertInt64Attribute(a *provider.Int64Attribute) (provider_generate.Genera MarkdownDescription: description(a.Description), DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Validators: a.Validators, + + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Validators: a.Validators, }, nil } diff --git a/internal/provider_convert/number_attribute.go b/internal/provider_convert/number_attribute.go index c7d3fbf8..b8f9519a 100644 --- a/internal/provider_convert/number_attribute.go +++ b/internal/provider_convert/number_attribute.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/provider_generate" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func convertNumberAttribute(a *provider.NumberAttribute) (provider_generate.GeneratorNumberAttribute, error) { @@ -26,7 +27,9 @@ func convertNumberAttribute(a *provider.NumberAttribute) (provider_generate.Gene MarkdownDescription: description(a.Description), DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Validators: a.Validators, + + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Validators: a.Validators, }, nil } diff --git a/internal/provider_convert/string_attribute.go b/internal/provider_convert/string_attribute.go index fd931460..397ef4b4 100644 --- a/internal/provider_convert/string_attribute.go +++ b/internal/provider_convert/string_attribute.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/provider_generate" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func convertStringAttribute(a *provider.StringAttribute) (provider_generate.GeneratorStringAttribute, error) { @@ -26,7 +27,9 @@ func convertStringAttribute(a *provider.StringAttribute) (provider_generate.Gene MarkdownDescription: description(a.Description), DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Validators: a.Validators, + + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Validators: a.Validators, }, nil } diff --git a/internal/provider_generate/bool_attribute.go b/internal/provider_generate/bool_attribute.go index b1a50e1d..47dc5fd5 100644 --- a/internal/provider_generate/bool_attribute.go +++ b/internal/provider_generate/bool_attribute.go @@ -4,6 +4,8 @@ package provider_generate import ( + "bytes" + "fmt" "strings" "text/template" @@ -17,6 +19,7 @@ import ( type GeneratorBoolAttribute struct { schema.BoolAttribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -38,6 +41,12 @@ func (g GeneratorBoolAttribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -61,6 +70,7 @@ func (g GeneratorBoolAttribute) Equal(ga generatorschema.GeneratorAttribute) boo func (g GeneratorBoolAttribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string GeneratorBoolAttribute GeneratorBoolAttribute } @@ -69,12 +79,20 @@ func (g GeneratorBoolAttribute) Schema(name generatorschema.FrameworkIdentifier) GeneratorBoolAttribute: g, } - t, err := template.New("bool_attribute").Parse(boolAttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("bool_attribute").Parse(boolAttributeTemplate) + if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -95,9 +113,58 @@ func (g GeneratorBoolAttribute) ModelField(name generatorschema.FrameworkIdentif ValueType: model.BoolValueType, } - 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 GeneratorBoolAttribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + boolType := generatorschema.NewCustomBoolType(name) + + b, err := boolType.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + boolValue := generatorschema.NewCustomBoolValue(name) + + b, err = boolValue.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorBoolAttribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromBool(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/embed.go b/internal/provider_generate/embed.go index 9f7117ff..87d684fe 100644 --- a/internal/provider_generate/embed.go +++ b/internal/provider_generate/embed.go @@ -10,13 +10,13 @@ import ( ) //go:embed templates/bool_attribute.gotmpl -var boolAttributeGoTemplate string +var boolAttributeTemplate string //go:embed templates/float64_attribute.gotmpl -var float64AttributeGoTemplate string +var float64AttributeTemplate string //go:embed templates/int64_attribute.gotmpl -var int64AttributeGoTemplate string +var int64AttributeTemplate string //go:embed templates/list_attribute.gotmpl var listAttributeGoTemplate string @@ -31,7 +31,7 @@ var mapAttributeGoTemplate string var mapNestedAttributeGoTemplate string //go:embed templates/number_attribute.gotmpl -var numberAttributeGoTemplate string +var numberAttributeTemplate string //go:embed templates/object_attribute.gotmpl var objectAttributeGoTemplate string @@ -46,7 +46,7 @@ var setNestedAttributeGoTemplate string var singleNestedAttributeGoTemplate string //go:embed templates/string_attribute.gotmpl -var stringAttributeGoTemplate string +var stringAttributeTemplate string //go:embed templates/list_nested_block.gotmpl var listNestedBlockGoTemplate string @@ -78,3 +78,14 @@ func addCommonBlockTemplate(t *template.Template) (*template.Template, error) { return t.New("common_block").Funcs(commonTemplateFuncs).Parse(commonBlockGoTemplate) } + +//go:embed templates/attribute.gotmpl +var attributeTemplate string + +func addAttributeTemplate(t *template.Template) (*template.Template, error) { + templateFuncs := template.FuncMap{ + "quote": strconv.Quote, + } + + return t.New("attribute").Funcs(templateFuncs).Parse(attributeTemplate) +} diff --git a/internal/provider_generate/float64_attribute.go b/internal/provider_generate/float64_attribute.go index 266c25e5..128a1340 100644 --- a/internal/provider_generate/float64_attribute.go +++ b/internal/provider_generate/float64_attribute.go @@ -4,6 +4,8 @@ package provider_generate import ( + "bytes" + "fmt" "strings" "text/template" @@ -17,6 +19,7 @@ import ( type GeneratorFloat64Attribute struct { schema.Float64Attribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -38,6 +41,12 @@ func (g GeneratorFloat64Attribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -61,6 +70,7 @@ func (g GeneratorFloat64Attribute) Equal(ga generatorschema.GeneratorAttribute) func (g GeneratorFloat64Attribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string GeneratorFloat64Attribute GeneratorFloat64Attribute } @@ -69,12 +79,19 @@ func (g GeneratorFloat64Attribute) Schema(name generatorschema.FrameworkIdentifi GeneratorFloat64Attribute: g, } - t, err := template.New("float64_attribute").Parse(float64AttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("float64_attribute").Parse(float64AttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -95,9 +112,58 @@ func (g GeneratorFloat64Attribute) ModelField(name generatorschema.FrameworkIden ValueType: model.Float64ValueType, } - 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 GeneratorFloat64Attribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + float64Type := generatorschema.NewCustomFloat64Type(name) + + b, err := float64Type.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + float64Value := generatorschema.NewCustomFloat64Value(name) + + b, err = float64Value.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorFloat64Attribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromFloat64(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/int64_attribute.go b/internal/provider_generate/int64_attribute.go index bdd413c6..e9845c6f 100644 --- a/internal/provider_generate/int64_attribute.go +++ b/internal/provider_generate/int64_attribute.go @@ -4,6 +4,8 @@ package provider_generate import ( + "bytes" + "fmt" "strings" "text/template" @@ -17,6 +19,7 @@ import ( type GeneratorInt64Attribute struct { schema.Int64Attribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -38,6 +41,12 @@ func (g GeneratorInt64Attribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -61,6 +70,7 @@ func (g GeneratorInt64Attribute) Equal(ga generatorschema.GeneratorAttribute) bo func (g GeneratorInt64Attribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string GeneratorInt64Attribute GeneratorInt64Attribute } @@ -69,12 +79,19 @@ func (g GeneratorInt64Attribute) Schema(name generatorschema.FrameworkIdentifier GeneratorInt64Attribute: g, } - t, err := template.New("int64_attribute").Parse(int64AttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("int64_attribute").Parse(int64AttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -95,9 +112,58 @@ func (g GeneratorInt64Attribute) ModelField(name generatorschema.FrameworkIdenti ValueType: model.Int64ValueType, } - 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 GeneratorInt64Attribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + int64Type := generatorschema.NewCustomInt64Type(name) + + b, err := int64Type.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + int64Value := generatorschema.NewCustomInt64Value(name) + + b, err = int64Value.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorInt64Attribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromInt64(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/number_attribute.go b/internal/provider_generate/number_attribute.go index 042e6dc3..0f744abb 100644 --- a/internal/provider_generate/number_attribute.go +++ b/internal/provider_generate/number_attribute.go @@ -4,10 +4,11 @@ package provider_generate import ( + "bytes" + "fmt" "strings" "text/template" - "github.com/hashicorp/terraform-plugin-codegen-spec/code" specschema "github.com/hashicorp/terraform-plugin-codegen-spec/schema" "github.com/hashicorp/terraform-plugin-framework/provider/schema" @@ -18,6 +19,7 @@ import ( type GeneratorNumberAttribute struct { schema.NumberAttribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -31,36 +33,20 @@ func (g GeneratorNumberAttribute) GeneratorSchemaType() generatorschema.Type { func (g GeneratorNumberAttribute) Imports() *generatorschema.Imports { imports := generatorschema.NewImports() - if g.CustomType != nil { - if g.CustomType.HasImport() { - imports.Add(*g.CustomType.Import) - } - } else { - imports.Add(code.Import{ - Path: generatorschema.TypesImport, - }) - } + customTypeImports := generatorschema.CustomTypeImports(g.CustomType) + imports.Append(customTypeImports) for _, v := range g.Validators { - if v.Custom == nil { - continue - } - - if !v.Custom.HasImport() { - continue - } - - for _, i := range v.Custom.Imports { - if len(i.Path) > 0 { - imports.Add(code.Import{ - Path: generatorschema.ValidatorImport, - }) + customValidatorImports := generatorschema.CustomValidatorImports(v.Custom) + imports.Append(customValidatorImports) + } - imports.Add(i) - } - } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) } + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -84,6 +70,7 @@ func (g GeneratorNumberAttribute) Equal(ga generatorschema.GeneratorAttribute) b func (g GeneratorNumberAttribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string GeneratorNumberAttribute GeneratorNumberAttribute } @@ -92,12 +79,19 @@ func (g GeneratorNumberAttribute) Schema(name generatorschema.FrameworkIdentifie GeneratorNumberAttribute: g, } - t, err := template.New("number_attribute").Parse(numberAttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("number_attribute").Parse(numberAttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -118,9 +112,58 @@ func (g GeneratorNumberAttribute) ModelField(name generatorschema.FrameworkIdent ValueType: model.NumberValueType, } - 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 GeneratorNumberAttribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + numberType := generatorschema.NewCustomNumberType(name) + + b, err := numberType.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + numberValue := generatorschema.NewCustomNumberValue(name) + + b, err = numberValue.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorNumberAttribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromNumber(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/string_attribute.go b/internal/provider_generate/string_attribute.go index 74d683c4..37bd15ca 100644 --- a/internal/provider_generate/string_attribute.go +++ b/internal/provider_generate/string_attribute.go @@ -4,6 +4,8 @@ package provider_generate import ( + "bytes" + "fmt" "strings" "text/template" @@ -17,6 +19,7 @@ import ( type GeneratorStringAttribute struct { schema.StringAttribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -38,6 +41,12 @@ func (g GeneratorStringAttribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -61,6 +70,7 @@ func (g GeneratorStringAttribute) Equal(ga generatorschema.GeneratorAttribute) b func (g GeneratorStringAttribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string GeneratorStringAttribute GeneratorStringAttribute } @@ -69,12 +79,19 @@ func (g GeneratorStringAttribute) Schema(name generatorschema.FrameworkIdentifie GeneratorStringAttribute: g, } - t, err := template.New("string_attribute").Parse(stringAttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("string_attribute").Parse(stringAttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -95,9 +112,58 @@ func (g GeneratorStringAttribute) ModelField(name generatorschema.FrameworkIdent ValueType: model.StringValueType, } - 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 GeneratorStringAttribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + stringType := generatorschema.NewCustomStringType(name) + + b, err := stringType.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + stringValue := generatorschema.NewCustomStringValue(name) + + b, err = stringValue.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorStringAttribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromString(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/provider_generate/templates/attribute.gotmpl b/internal/provider_generate/templates/attribute.gotmpl new file mode 100644 index 00000000..c7b6ba8f --- /dev/null +++ b/internal/provider_generate/templates/attribute.gotmpl @@ -0,0 +1,22 @@ +{{define "common_attribute"}} + +{{- if .Required}} +Required: {{.Required}}, +{{- end}} + +{{- if .Optional}} +Optional: {{.Optional}}, +{{- end}} + +{{- if .Sensitive }} +Sensitive: {{.Sensitive}}, +{{- end}} + +{{- if .Description }} +Description: {{ .Description | quote }}, +MarkdownDescription: {{.Description | quote }}, +{{- end}} + +{{- if .DeprecationMessage }} +DeprecationMessage: {{ .DeprecationMessage | quote }},{{- end}} +{{- end}} \ No newline at end of file diff --git a/internal/provider_generate/templates/bool_attribute.gotmpl b/internal/provider_generate/templates/bool_attribute.gotmpl index 98d9d2b6..8ac85743 100644 --- a/internal/provider_generate/templates/bool_attribute.gotmpl +++ b/internal/provider_generate/templates/bool_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.BoolAttribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorBoolAttribute }} {{- if gt (len .GeneratorBoolAttribute.Validators) 0 }} Validators: []validator.Bool{ diff --git a/internal/provider_generate/templates/float64_attribute.gotmpl b/internal/provider_generate/templates/float64_attribute.gotmpl index d6530c7f..752c64e6 100644 --- a/internal/provider_generate/templates/float64_attribute.gotmpl +++ b/internal/provider_generate/templates/float64_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.Float64Attribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorFloat64Attribute }} {{- if gt (len .GeneratorFloat64Attribute.Validators) 0 }} Validators: []validator.Float64{ diff --git a/internal/provider_generate/templates/int64_attribute.gotmpl b/internal/provider_generate/templates/int64_attribute.gotmpl index d0ce7c04..2f65cbb2 100644 --- a/internal/provider_generate/templates/int64_attribute.gotmpl +++ b/internal/provider_generate/templates/int64_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.Int64Attribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorInt64Attribute }} {{- if gt (len .GeneratorInt64Attribute.Validators) 0 }} Validators: []validator.Int64{ diff --git a/internal/provider_generate/templates/number_attribute.gotmpl b/internal/provider_generate/templates/number_attribute.gotmpl index 98425de0..e089ecd0 100644 --- a/internal/provider_generate/templates/number_attribute.gotmpl +++ b/internal/provider_generate/templates/number_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.NumberAttribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorNumberAttribute }} {{- if gt (len .GeneratorNumberAttribute.Validators) 0 }} Validators: []validator.Number{ diff --git a/internal/provider_generate/templates/string_attribute.gotmpl b/internal/provider_generate/templates/string_attribute.gotmpl index fab62020..ebb12b19 100644 --- a/internal/provider_generate/templates/string_attribute.gotmpl +++ b/internal/provider_generate/templates/string_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.StringAttribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorStringAttribute }} {{- if gt (len .GeneratorStringAttribute.Validators) 0 }} Validators: []validator.String{ diff --git a/internal/resource_convert/bool_attribute.go b/internal/resource_convert/bool_attribute.go index d0358952..5578ab09 100644 --- a/internal/resource_convert/bool_attribute.go +++ b/internal/resource_convert/bool_attribute.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/resource_generate" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func convertBoolAttribute(a *resource.BoolAttribute) (resource_generate.GeneratorBoolAttribute, error) { @@ -27,9 +28,11 @@ func convertBoolAttribute(a *resource.BoolAttribute) (resource_generate.Generato MarkdownDescription: description(a.Description), DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Default: a.Default, - PlanModifiers: a.PlanModifiers, - Validators: a.Validators, + + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Default: a.Default, + PlanModifiers: a.PlanModifiers, + Validators: a.Validators, }, nil } diff --git a/internal/resource_convert/float64_attribute.go b/internal/resource_convert/float64_attribute.go index b3d25efe..595d6a41 100644 --- a/internal/resource_convert/float64_attribute.go +++ b/internal/resource_convert/float64_attribute.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/resource_generate" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func convertFloat64Attribute(a *resource.Float64Attribute) (resource_generate.GeneratorFloat64Attribute, error) { @@ -27,9 +28,11 @@ func convertFloat64Attribute(a *resource.Float64Attribute) (resource_generate.Ge MarkdownDescription: description(a.Description), DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Default: a.Default, - PlanModifiers: a.PlanModifiers, - Validators: a.Validators, + + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Default: a.Default, + PlanModifiers: a.PlanModifiers, + Validators: a.Validators, }, nil } diff --git a/internal/resource_convert/int64_attribute.go b/internal/resource_convert/int64_attribute.go index 86e406bb..97fec33a 100644 --- a/internal/resource_convert/int64_attribute.go +++ b/internal/resource_convert/int64_attribute.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/resource_generate" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func convertInt64Attribute(a *resource.Int64Attribute) (resource_generate.GeneratorInt64Attribute, error) { @@ -27,9 +28,11 @@ func convertInt64Attribute(a *resource.Int64Attribute) (resource_generate.Genera MarkdownDescription: description(a.Description), DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Default: a.Default, - PlanModifiers: a.PlanModifiers, - Validators: a.Validators, + + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Default: a.Default, + PlanModifiers: a.PlanModifiers, + Validators: a.Validators, }, nil } diff --git a/internal/resource_convert/number_attribute.go b/internal/resource_convert/number_attribute.go index 0b88e5c2..acb84a0b 100644 --- a/internal/resource_convert/number_attribute.go +++ b/internal/resource_convert/number_attribute.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/resource_generate" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func convertNumberAttribute(a *resource.NumberAttribute) (resource_generate.GeneratorNumberAttribute, error) { @@ -27,9 +28,11 @@ func convertNumberAttribute(a *resource.NumberAttribute) (resource_generate.Gene MarkdownDescription: description(a.Description), DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Default: a.Default, - PlanModifiers: a.PlanModifiers, - Validators: a.Validators, + + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Default: a.Default, + PlanModifiers: a.PlanModifiers, + Validators: a.Validators, }, nil } diff --git a/internal/resource_convert/string_attribute.go b/internal/resource_convert/string_attribute.go index 9c2741bc..4cb027bd 100644 --- a/internal/resource_convert/string_attribute.go +++ b/internal/resource_convert/string_attribute.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/resource_generate" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func convertStringAttribute(a *resource.StringAttribute) (resource_generate.GeneratorStringAttribute, error) { @@ -27,9 +28,11 @@ func convertStringAttribute(a *resource.StringAttribute) (resource_generate.Gene MarkdownDescription: description(a.Description), DeprecationMessage: deprecationMessage(a.DeprecationMessage), }, - CustomType: a.CustomType, - Default: a.Default, - PlanModifiers: a.PlanModifiers, - Validators: a.Validators, + + AssociatedExternalType: generatorschema.NewAssocExtType(a.AssociatedExternalType), + CustomType: a.CustomType, + Default: a.Default, + PlanModifiers: a.PlanModifiers, + Validators: a.Validators, }, nil } diff --git a/internal/resource_generate/bool_attribute.go b/internal/resource_generate/bool_attribute.go index be89d290..12ef3495 100644 --- a/internal/resource_generate/bool_attribute.go +++ b/internal/resource_generate/bool_attribute.go @@ -4,6 +4,7 @@ package resource_generate import ( + "bytes" "fmt" "strings" "text/template" @@ -19,6 +20,7 @@ import ( type GeneratorBoolAttribute struct { schema.BoolAttribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -58,6 +60,12 @@ func (g GeneratorBoolAttribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -105,6 +113,7 @@ func boolDefault(d *specschema.BoolDefault) string { func (g GeneratorBoolAttribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string Default string GeneratorBoolAttribute GeneratorBoolAttribute } @@ -115,12 +124,20 @@ func (g GeneratorBoolAttribute) Schema(name generatorschema.FrameworkIdentifier) GeneratorBoolAttribute: g, } - t, err := template.New("bool_attribute").Parse(boolAttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("bool_attribute").Parse(boolAttributeTemplate) + if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -141,9 +158,58 @@ func (g GeneratorBoolAttribute) ModelField(name generatorschema.FrameworkIdentif ValueType: model.BoolValueType, } - 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 GeneratorBoolAttribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + boolType := generatorschema.NewCustomBoolType(name) + + b, err := boolType.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + boolValue := generatorschema.NewCustomBoolValue(name) + + b, err = boolValue.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorBoolAttribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromBool(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/embed.go b/internal/resource_generate/embed.go index 29510ec9..e9c19e7e 100644 --- a/internal/resource_generate/embed.go +++ b/internal/resource_generate/embed.go @@ -10,13 +10,13 @@ import ( ) //go:embed templates/bool_attribute.gotmpl -var boolAttributeGoTemplate string +var boolAttributeTemplate string //go:embed templates/float64_attribute.gotmpl -var float64AttributeGoTemplate string +var float64AttributeTemplate string //go:embed templates/int64_attribute.gotmpl -var int64AttributeGoTemplate string +var int64AttributeTemplate string //go:embed templates/list_attribute.gotmpl var listAttributeGoTemplate string @@ -31,7 +31,7 @@ var mapAttributeGoTemplate string var mapNestedAttributeGoTemplate string //go:embed templates/number_attribute.gotmpl -var numberAttributeGoTemplate string +var numberAttributeTemplate string //go:embed templates/object_attribute.gotmpl var objectAttributeGoTemplate string @@ -46,7 +46,7 @@ var setNestedAttributeGoTemplate string var singleNestedAttributeGoTemplate string //go:embed templates/string_attribute.gotmpl -var stringAttributeGoTemplate string +var stringAttributeTemplate string //go:embed templates/list_nested_block.gotmpl var listNestedBlockGoTemplate string @@ -78,3 +78,14 @@ func addCommonBlockTemplate(t *template.Template) (*template.Template, error) { return t.New("common_block").Funcs(commonTemplateFuncs).Parse(commonBlockGoTemplate) } + +//go:embed templates/attribute.gotmpl +var attributeTemplate string + +func addAttributeTemplate(t *template.Template) (*template.Template, error) { + templateFuncs := template.FuncMap{ + "quote": strconv.Quote, + } + + return t.New("attribute").Funcs(templateFuncs).Parse(attributeTemplate) +} diff --git a/internal/resource_generate/float64_attribute.go b/internal/resource_generate/float64_attribute.go index 0a8e97a0..228fc36b 100644 --- a/internal/resource_generate/float64_attribute.go +++ b/internal/resource_generate/float64_attribute.go @@ -4,6 +4,7 @@ package resource_generate import ( + "bytes" "fmt" "strconv" "strings" @@ -20,6 +21,7 @@ import ( type GeneratorFloat64Attribute struct { schema.Float64Attribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -59,6 +61,12 @@ func (g GeneratorFloat64Attribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -106,6 +114,7 @@ func float64Default(d *specschema.Float64Default) string { func (g GeneratorFloat64Attribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string Default string GeneratorFloat64Attribute GeneratorFloat64Attribute } @@ -116,12 +125,19 @@ func (g GeneratorFloat64Attribute) Schema(name generatorschema.FrameworkIdentifi GeneratorFloat64Attribute: g, } - t, err := template.New("float64_attribute").Parse(float64AttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("float64_attribute").Parse(float64AttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -142,9 +158,58 @@ func (g GeneratorFloat64Attribute) ModelField(name generatorschema.FrameworkIden ValueType: model.Float64ValueType, } - 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 GeneratorFloat64Attribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + float64Type := generatorschema.NewCustomFloat64Type(name) + + b, err := float64Type.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + float64Value := generatorschema.NewCustomFloat64Value(name) + + b, err = float64Value.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorFloat64Attribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromFloat64(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/int64_attribute.go b/internal/resource_generate/int64_attribute.go index 97d5d93d..6e7099d7 100644 --- a/internal/resource_generate/int64_attribute.go +++ b/internal/resource_generate/int64_attribute.go @@ -4,6 +4,7 @@ package resource_generate import ( + "bytes" "fmt" "strings" "text/template" @@ -19,6 +20,7 @@ import ( type GeneratorInt64Attribute struct { schema.Int64Attribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -58,6 +60,12 @@ func (g GeneratorInt64Attribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -105,6 +113,7 @@ func int64Default(d *specschema.Int64Default) string { func (g GeneratorInt64Attribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string Default string GeneratorInt64Attribute GeneratorInt64Attribute } @@ -115,12 +124,19 @@ func (g GeneratorInt64Attribute) Schema(name generatorschema.FrameworkIdentifier GeneratorInt64Attribute: g, } - t, err := template.New("int64_attribute").Parse(int64AttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("int64_attribute").Parse(int64AttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -141,9 +157,58 @@ func (g GeneratorInt64Attribute) ModelField(name generatorschema.FrameworkIdenti ValueType: model.Int64ValueType, } - 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 GeneratorInt64Attribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + int64Type := generatorschema.NewCustomInt64Type(name) + + b, err := int64Type.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + int64Value := generatorschema.NewCustomInt64Value(name) + + b, err = int64Value.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorInt64Attribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromInt64(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/number_attribute.go b/internal/resource_generate/number_attribute.go index 438d5db2..69e6e040 100644 --- a/internal/resource_generate/number_attribute.go +++ b/internal/resource_generate/number_attribute.go @@ -4,6 +4,8 @@ package resource_generate import ( + "bytes" + "fmt" "strings" "text/template" @@ -17,6 +19,7 @@ import ( type GeneratorNumberAttribute struct { schema.NumberAttribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -50,6 +53,12 @@ func (g GeneratorNumberAttribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -94,6 +103,7 @@ func (g GeneratorNumberAttribute) Schema(name generatorschema.FrameworkIdentifie type attribute struct { Name string Default string + CustomType string GeneratorNumberAttribute GeneratorNumberAttribute } @@ -103,12 +113,19 @@ func (g GeneratorNumberAttribute) Schema(name generatorschema.FrameworkIdentifie GeneratorNumberAttribute: g, } - t, err := template.New("number_attribute").Parse(numberAttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("number_attribute").Parse(numberAttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -129,9 +146,58 @@ func (g GeneratorNumberAttribute) ModelField(name generatorschema.FrameworkIdent ValueType: model.NumberValueType, } - 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 GeneratorNumberAttribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + numberType := generatorschema.NewCustomNumberType(name) + + b, err := numberType.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + numberValue := generatorschema.NewCustomNumberValue(name) + + b, err = numberValue.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorNumberAttribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromNumber(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/string_attribute.go b/internal/resource_generate/string_attribute.go index 38c58bcc..77c25aae 100644 --- a/internal/resource_generate/string_attribute.go +++ b/internal/resource_generate/string_attribute.go @@ -4,6 +4,7 @@ package resource_generate import ( + "bytes" "fmt" "strings" "text/template" @@ -19,6 +20,7 @@ import ( type GeneratorStringAttribute struct { schema.StringAttribute + AssociatedExternalType *generatorschema.AssocExtType // The "specschema" types are used instead of the types within the attribute // because support for extracting custom import information is required. CustomType *specschema.CustomType @@ -58,6 +60,12 @@ func (g GeneratorStringAttribute) Imports() *generatorschema.Imports { imports.Append(customValidatorImports) } + if g.AssociatedExternalType != nil { + imports.Append(generatorschema.AssociatedExternalTypeImports()) + } + + imports.Append(g.AssociatedExternalType.Imports()) + return imports } @@ -105,6 +113,7 @@ func stringDefault(d *specschema.StringDefault) string { func (g GeneratorStringAttribute) Schema(name generatorschema.FrameworkIdentifier) (string, error) { type attribute struct { Name string + CustomType string Default string GeneratorStringAttribute GeneratorStringAttribute } @@ -115,12 +124,19 @@ func (g GeneratorStringAttribute) Schema(name generatorschema.FrameworkIdentifie GeneratorStringAttribute: g, } - t, err := template.New("string_attribute").Parse(stringAttributeGoTemplate) + switch { + case g.CustomType != nil: + a.CustomType = g.CustomType.Type + case g.AssociatedExternalType != nil: + a.CustomType = fmt.Sprintf("%sType{}", name.ToPascalCase()) + } + + t, err := template.New("string_attribute").Parse(stringAttributeTemplate) if err != nil { return "", err } - if _, err = addCommonAttributeTemplate(t); err != nil { + if _, err = addAttributeTemplate(t); err != nil { return "", err } @@ -141,9 +157,58 @@ func (g GeneratorStringAttribute) ModelField(name generatorschema.FrameworkIdent ValueType: model.StringValueType, } - 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 GeneratorStringAttribute) CustomTypeAndValue(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + var buf bytes.Buffer + + stringType := generatorschema.NewCustomStringType(name) + + b, err := stringType.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + stringValue := generatorschema.NewCustomStringValue(name) + + b, err = stringValue.Render() + + if err != nil { + return nil, err + } + + buf.Write(b) + + return buf.Bytes(), nil +} + +func (g GeneratorStringAttribute) ToFromFunctions(name string) ([]byte, error) { + if g.AssociatedExternalType == nil { + return nil, nil + } + + toFrom := generatorschema.NewToFromString(name, g.AssociatedExternalType) + + b, err := toFrom.Render() + + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/internal/resource_generate/templates/attribute.gotmpl b/internal/resource_generate/templates/attribute.gotmpl new file mode 100644 index 00000000..0726b444 --- /dev/null +++ b/internal/resource_generate/templates/attribute.gotmpl @@ -0,0 +1,26 @@ +{{define "common_attribute"}} + +{{- if .Required}} +Required: {{.Required}}, +{{- end}} + +{{- if .Optional}} +Optional: {{.Optional}}, +{{- end}} + +{{- if .Computed}} +Computed: {{.Computed}}, +{{- end}} + +{{- if .Sensitive }} +Sensitive: {{.Sensitive}}, +{{- end}} + +{{- if .Description }} +Description: {{ .Description | quote }}, +MarkdownDescription: {{.Description | quote }}, +{{- end}} + +{{- if .DeprecationMessage }} +DeprecationMessage: {{ .DeprecationMessage | quote }},{{- end}} +{{- end}} diff --git a/internal/resource_generate/templates/bool_attribute.gotmpl b/internal/resource_generate/templates/bool_attribute.gotmpl index 743e7dc5..3290e87f 100644 --- a/internal/resource_generate/templates/bool_attribute.gotmpl +++ b/internal/resource_generate/templates/bool_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.BoolAttribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorBoolAttribute }} {{- if gt (len .GeneratorBoolAttribute.PlanModifiers) 0 }} PlanModifiers: []planmodifier.Bool{ diff --git a/internal/resource_generate/templates/float64_attribute.gotmpl b/internal/resource_generate/templates/float64_attribute.gotmpl index 8fadacc4..cb54d308 100644 --- a/internal/resource_generate/templates/float64_attribute.gotmpl +++ b/internal/resource_generate/templates/float64_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.Float64Attribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorFloat64Attribute }} {{- if gt (len .GeneratorFloat64Attribute.PlanModifiers) 0 }} PlanModifiers: []planmodifier.Float64{ diff --git a/internal/resource_generate/templates/int64_attribute.gotmpl b/internal/resource_generate/templates/int64_attribute.gotmpl index bb5d1c2c..90941cba 100644 --- a/internal/resource_generate/templates/int64_attribute.gotmpl +++ b/internal/resource_generate/templates/int64_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.Int64Attribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorInt64Attribute }} {{- if gt (len .GeneratorInt64Attribute.PlanModifiers) 0 }} PlanModifiers: []planmodifier.Int64{ diff --git a/internal/resource_generate/templates/number_attribute.gotmpl b/internal/resource_generate/templates/number_attribute.gotmpl index 430395a7..4a0b2d54 100644 --- a/internal/resource_generate/templates/number_attribute.gotmpl +++ b/internal/resource_generate/templates/number_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.NumberAttribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorNumberAttribute }} {{- if gt (len .GeneratorNumberAttribute.PlanModifiers) 0 }} PlanModifiers: []planmodifier.Number{ diff --git a/internal/resource_generate/templates/string_attribute.gotmpl b/internal/resource_generate/templates/string_attribute.gotmpl index 14af19f0..cb8c2b00 100644 --- a/internal/resource_generate/templates/string_attribute.gotmpl +++ b/internal/resource_generate/templates/string_attribute.gotmpl @@ -1,5 +1,8 @@ "{{.Name}}": schema.StringAttribute{ +{{- if .CustomType}} +CustomType: {{.CustomType}}, +{{- end}} {{- template "common_attribute" .GeneratorStringAttribute }} {{- if gt (len .GeneratorStringAttribute.PlanModifiers) 0 }} PlanModifiers: []planmodifier.String{ From 422cfb4f0a992829f9cfd0c4d786b4f5a8047a1d Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 17 Oct 2023 16:04:47 +0100 Subject: [PATCH 15/19] Adding test coverage for associated external type --- .../bool_attribute_test.go | 166 ++++++++++++++ .../float64_attribute_test.go | 63 ++++++ .../int64_attribute_test.go | 63 ++++++ .../number_attribute_test.go | 63 ++++++ .../string_attribute_test.go | 63 ++++++ .../provider_generate/bool_attribute_test.go | 204 ++++++++++++++++-- .../float64_attribute_test.go | 85 +++++++- .../provider_generate/int64_attribute_test.go | 85 +++++++- .../number_attribute_test.go | 85 +++++++- .../string_attribute_test.go | 85 +++++++- .../resource_generate/bool_attribute_test.go | 166 ++++++++++++++ .../float64_attribute_test.go | 63 ++++++ .../resource_generate/int64_attribute_test.go | 63 ++++++ .../number_attribute_test.go | 63 ++++++ .../string_attribute_test.go | 63 ++++++ 15 files changed, 1317 insertions(+), 63 deletions(-) diff --git a/internal/datasource_generate/bool_attribute_test.go b/internal/datasource_generate/bool_attribute_test.go index d61db957..fb7f8609 100644 --- a/internal/datasource_generate/bool_attribute_test.go +++ b/internal/datasource_generate/bool_attribute_test.go @@ -141,6 +141,110 @@ func TestGeneratorBoolAttribute_Imports(t *testing.T) { }, }, }, + "associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + }, + 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: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Import: &code.Import{ + Path: "github.com/api", + }, + Type: "*api.BoolAttribute", + }, + }, + }, + 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: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Import: &code.Import{ + Path: "github.com/api", + }, + Type: "*api.BoolAttribute", + }, + }, + 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 { @@ -178,6 +282,37 @@ CustomType: my_custom_type, },`, }, + "associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + }, + expected: ` +"bool_attribute": schema.BoolAttribute{ +CustomType: BoolAttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"bool_attribute": schema.BoolAttribute{ +CustomType: my_custom_type, +},`, + }, + "required": { input: GeneratorBoolAttribute{ BoolAttribute: schema.BoolAttribute{ @@ -331,6 +466,37 @@ func TestGeneratorBoolAttribute_ModelField(t *testing.T) { TfsdkName: "bool_attribute", }, }, + "associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + }, + expected: model.Field{ + Name: "BoolAttribute", + ValueType: "BoolAttributeValue", + TfsdkName: "bool_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "BoolAttribute", + ValueType: "my_custom_value_type", + TfsdkName: "bool_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/datasource_generate/float64_attribute_test.go b/internal/datasource_generate/float64_attribute_test.go index 5d7fe12f..27189830 100644 --- a/internal/datasource_generate/float64_attribute_test.go +++ b/internal/datasource_generate/float64_attribute_test.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorFloat64Attribute_Schema(t *testing.T) { @@ -33,6 +34,37 @@ CustomType: my_custom_type, },`, }, + "associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + }, + expected: ` +"float64_attribute": schema.Float64Attribute{ +CustomType: Float64AttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"float64_attribute": schema.Float64Attribute{ +CustomType: my_custom_type, +},`, + }, + "required": { input: GeneratorFloat64Attribute{ Float64Attribute: schema.Float64Attribute{ @@ -178,6 +210,37 @@ func TestGeneratorFloat64Attribute_ModelField(t *testing.T) { TfsdkName: "float64_attribute", }, }, + "associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + }, + expected: model.Field{ + Name: "Float64Attribute", + ValueType: "Float64AttributeValue", + TfsdkName: "float64_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "Float64Attribute", + ValueType: "my_custom_value_type", + TfsdkName: "float64_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/datasource_generate/int64_attribute_test.go b/internal/datasource_generate/int64_attribute_test.go index fc62a99a..27bb1c0c 100644 --- a/internal/datasource_generate/int64_attribute_test.go +++ b/internal/datasource_generate/int64_attribute_test.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorInt64Attribute_Schema(t *testing.T) { @@ -33,6 +34,37 @@ CustomType: my_custom_type, },`, }, + "associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + }, + expected: ` +"int64_attribute": schema.Int64Attribute{ +CustomType: Int64AttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"int64_attribute": schema.Int64Attribute{ +CustomType: my_custom_type, +},`, + }, + "required": { input: GeneratorInt64Attribute{ Int64Attribute: schema.Int64Attribute{ @@ -178,6 +210,37 @@ func TestGeneratorInt64Attribute_ModelField(t *testing.T) { TfsdkName: "int64_attribute", }, }, + "associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + }, + expected: model.Field{ + Name: "Int64Attribute", + ValueType: "Int64AttributeValue", + TfsdkName: "int64_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "Int64Attribute", + ValueType: "my_custom_value_type", + TfsdkName: "int64_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/datasource_generate/number_attribute_test.go b/internal/datasource_generate/number_attribute_test.go index 77863520..d247db77 100644 --- a/internal/datasource_generate/number_attribute_test.go +++ b/internal/datasource_generate/number_attribute_test.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorNumberAttribute_Schema(t *testing.T) { @@ -33,6 +34,37 @@ CustomType: my_custom_type, },`, }, + "associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + }, + expected: ` +"number_attribute": schema.NumberAttribute{ +CustomType: NumberAttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"number_attribute": schema.NumberAttribute{ +CustomType: my_custom_type, +},`, + }, + "required": { input: GeneratorNumberAttribute{ NumberAttribute: schema.NumberAttribute{ @@ -178,6 +210,37 @@ func TestGeneratorNumberAttribute_ModelField(t *testing.T) { TfsdkName: "number_attribute", }, }, + "associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + }, + expected: model.Field{ + Name: "NumberAttribute", + ValueType: "NumberAttributeValue", + TfsdkName: "number_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "NumberAttribute", + ValueType: "my_custom_value_type", + TfsdkName: "number_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/datasource_generate/string_attribute_test.go b/internal/datasource_generate/string_attribute_test.go index dd9239a0..39b6f173 100644 --- a/internal/datasource_generate/string_attribute_test.go +++ b/internal/datasource_generate/string_attribute_test.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorStringAttribute_Schema(t *testing.T) { @@ -33,6 +34,37 @@ CustomType: my_custom_type, },`, }, + "associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + }, + expected: ` +"string_attribute": schema.StringAttribute{ +CustomType: StringAttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"string_attribute": schema.StringAttribute{ +CustomType: my_custom_type, +},`, + }, + "required": { input: GeneratorStringAttribute{ StringAttribute: schema.StringAttribute{ @@ -178,6 +210,37 @@ func TestGeneratorStringAttribute_ModelField(t *testing.T) { TfsdkName: "string_attribute", }, }, + "associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + }, + expected: model.Field{ + Name: "StringAttribute", + ValueType: "StringAttributeValue", + TfsdkName: "string_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "StringAttribute", + ValueType: "my_custom_value_type", + TfsdkName: "string_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/provider_generate/bool_attribute_test.go b/internal/provider_generate/bool_attribute_test.go index b52c9c4e..4cfa9fae 100644 --- a/internal/provider_generate/bool_attribute_test.go +++ b/internal/provider_generate/bool_attribute_test.go @@ -141,6 +141,110 @@ func TestGeneratorBoolAttribute_Imports(t *testing.T) { }, }, }, + "associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + }, + 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: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Import: &code.Import{ + Path: "github.com/api", + }, + Type: "*api.BoolAttribute", + }, + }, + }, + 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: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Import: &code.Import{ + Path: "github.com/api", + }, + Type: "*api.BoolAttribute", + }, + }, + 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 { @@ -162,53 +266,84 @@ func TestGeneratorBoolAttribute_Schema(t *testing.T) { t.Parallel() testCases := map[string]struct { - boolAttribute GeneratorBoolAttribute - expectedAttribute string - expectedError error + input GeneratorBoolAttribute + expected string + expectedError error }{ "custom-type": { - boolAttribute: GeneratorBoolAttribute{ + input: GeneratorBoolAttribute{ + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"bool_attribute": schema.BoolAttribute{ +CustomType: my_custom_type, +},`, + }, + + "associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + }, + expected: ` +"bool_attribute": schema.BoolAttribute{ +CustomType: BoolAttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, CustomType: &specschema.CustomType{ Type: "my_custom_type", }, }, - expectedAttribute: ` + expected: ` "bool_attribute": schema.BoolAttribute{ CustomType: my_custom_type, },`, }, "required": { - boolAttribute: GeneratorBoolAttribute{ + input: GeneratorBoolAttribute{ BoolAttribute: schema.BoolAttribute{ Required: true, }, }, - expectedAttribute: ` + expected: ` "bool_attribute": schema.BoolAttribute{ Required: true, },`, }, "optional": { - boolAttribute: GeneratorBoolAttribute{ + input: GeneratorBoolAttribute{ BoolAttribute: schema.BoolAttribute{ Optional: true, }, }, - expectedAttribute: ` + expected: ` "bool_attribute": schema.BoolAttribute{ Optional: true, },`, }, "sensitive": { - boolAttribute: GeneratorBoolAttribute{ + input: GeneratorBoolAttribute{ BoolAttribute: schema.BoolAttribute{ Sensitive: true, }, }, - expectedAttribute: ` + expected: ` "bool_attribute": schema.BoolAttribute{ Sensitive: true, },`, @@ -216,12 +351,12 @@ Sensitive: true, // TODO: Do we need separate description and markdown description? "description": { - boolAttribute: GeneratorBoolAttribute{ + input: GeneratorBoolAttribute{ BoolAttribute: schema.BoolAttribute{ Description: "description", }, }, - expectedAttribute: ` + expected: ` "bool_attribute": schema.BoolAttribute{ Description: "description", MarkdownDescription: "description", @@ -229,19 +364,19 @@ MarkdownDescription: "description", }, "deprecation-message": { - boolAttribute: GeneratorBoolAttribute{ + input: GeneratorBoolAttribute{ BoolAttribute: schema.BoolAttribute{ DeprecationMessage: "deprecated", }, }, - expectedAttribute: ` + expected: ` "bool_attribute": schema.BoolAttribute{ DeprecationMessage: "deprecated", },`, }, "validators": { - boolAttribute: GeneratorBoolAttribute{ + input: GeneratorBoolAttribute{ Validators: specschema.BoolValidators{ { Custom: &specschema.CustomValidator{ @@ -255,7 +390,7 @@ DeprecationMessage: "deprecated", }, }, }, - expectedAttribute: ` + expected: ` "bool_attribute": schema.BoolAttribute{ Validators: []validator.Bool{ my_validator.Validate(), @@ -271,13 +406,13 @@ my_other_validator.Validate(), t.Run(name, func(t *testing.T) { t.Parallel() - got, err := testCase.boolAttribute.Schema("bool_attribute") + got, err := testCase.input.Schema("bool_attribute") if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { t.Errorf("unexpected error: %s", diff) } - if diff := cmp.Diff(got, testCase.expectedAttribute); diff != "" { + if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -311,6 +446,37 @@ func TestGeneratorBoolAttribute_ModelField(t *testing.T) { TfsdkName: "bool_attribute", }, }, + "associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + }, + expected: model.Field{ + Name: "BoolAttribute", + ValueType: "BoolAttributeValue", + TfsdkName: "bool_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "BoolAttribute", + ValueType: "my_custom_value_type", + TfsdkName: "bool_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/provider_generate/float64_attribute_test.go b/internal/provider_generate/float64_attribute_test.go index 22102dc0..a29fd059 100644 --- a/internal/provider_generate/float64_attribute_test.go +++ b/internal/provider_generate/float64_attribute_test.go @@ -11,15 +11,16 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorFloat64Attribute_Schema(t *testing.T) { t.Parallel() testCases := map[string]struct { - input GeneratorFloat64Attribute - expectedAttribute string - expectedError error + input GeneratorFloat64Attribute + expected string + expectedError error }{ "custom-type": { input: GeneratorFloat64Attribute{ @@ -27,7 +28,38 @@ func TestGeneratorFloat64Attribute_Schema(t *testing.T) { Type: "my_custom_type", }, }, - expectedAttribute: ` + expected: ` +"float64_attribute": schema.Float64Attribute{ +CustomType: my_custom_type, +},`, + }, + + "associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + }, + expected: ` +"float64_attribute": schema.Float64Attribute{ +CustomType: Float64AttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` "float64_attribute": schema.Float64Attribute{ CustomType: my_custom_type, },`, @@ -39,7 +71,7 @@ CustomType: my_custom_type, Required: true, }, }, - expectedAttribute: ` + expected: ` "float64_attribute": schema.Float64Attribute{ Required: true, },`, @@ -51,7 +83,7 @@ Required: true, Optional: true, }, }, - expectedAttribute: ` + expected: ` "float64_attribute": schema.Float64Attribute{ Optional: true, },`, @@ -63,7 +95,7 @@ Optional: true, Sensitive: true, }, }, - expectedAttribute: ` + expected: ` "float64_attribute": schema.Float64Attribute{ Sensitive: true, },`, @@ -76,7 +108,7 @@ Sensitive: true, Description: "description", }, }, - expectedAttribute: ` + expected: ` "float64_attribute": schema.Float64Attribute{ Description: "description", MarkdownDescription: "description", @@ -89,7 +121,7 @@ MarkdownDescription: "description", DeprecationMessage: "deprecated", }, }, - expectedAttribute: ` + expected: ` "float64_attribute": schema.Float64Attribute{ DeprecationMessage: "deprecated", },`, @@ -110,7 +142,7 @@ DeprecationMessage: "deprecated", }, }, }, - expectedAttribute: ` + expected: ` "float64_attribute": schema.Float64Attribute{ Validators: []validator.Float64{ my_validator.Validate(), @@ -132,7 +164,7 @@ my_other_validator.Validate(), t.Errorf("unexpected error: %s", diff) } - if diff := cmp.Diff(got, testCase.expectedAttribute); diff != "" { + if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -166,6 +198,37 @@ func TestGeneratorFloat64Attribute_ModelField(t *testing.T) { TfsdkName: "float64_attribute", }, }, + "associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + }, + expected: model.Field{ + Name: "Float64Attribute", + ValueType: "Float64AttributeValue", + TfsdkName: "float64_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "Float64Attribute", + ValueType: "my_custom_value_type", + TfsdkName: "float64_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/provider_generate/int64_attribute_test.go b/internal/provider_generate/int64_attribute_test.go index bdaff45e..43c474c4 100644 --- a/internal/provider_generate/int64_attribute_test.go +++ b/internal/provider_generate/int64_attribute_test.go @@ -11,15 +11,16 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorInt64Attribute_Schema(t *testing.T) { t.Parallel() testCases := map[string]struct { - input GeneratorInt64Attribute - expectedAttribute string - expectedError error + input GeneratorInt64Attribute + expected string + expectedError error }{ "custom-type": { input: GeneratorInt64Attribute{ @@ -27,7 +28,38 @@ func TestGeneratorInt64Attribute_Schema(t *testing.T) { Type: "my_custom_type", }, }, - expectedAttribute: ` + expected: ` +"int64_attribute": schema.Int64Attribute{ +CustomType: my_custom_type, +},`, + }, + + "associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + }, + expected: ` +"int64_attribute": schema.Int64Attribute{ +CustomType: Int64AttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` "int64_attribute": schema.Int64Attribute{ CustomType: my_custom_type, },`, @@ -39,7 +71,7 @@ CustomType: my_custom_type, Required: true, }, }, - expectedAttribute: ` + expected: ` "int64_attribute": schema.Int64Attribute{ Required: true, },`, @@ -51,7 +83,7 @@ Required: true, Optional: true, }, }, - expectedAttribute: ` + expected: ` "int64_attribute": schema.Int64Attribute{ Optional: true, },`, @@ -63,7 +95,7 @@ Optional: true, Sensitive: true, }, }, - expectedAttribute: ` + expected: ` "int64_attribute": schema.Int64Attribute{ Sensitive: true, },`, @@ -76,7 +108,7 @@ Sensitive: true, Description: "description", }, }, - expectedAttribute: ` + expected: ` "int64_attribute": schema.Int64Attribute{ Description: "description", MarkdownDescription: "description", @@ -89,7 +121,7 @@ MarkdownDescription: "description", DeprecationMessage: "deprecated", }, }, - expectedAttribute: ` + expected: ` "int64_attribute": schema.Int64Attribute{ DeprecationMessage: "deprecated", },`, @@ -110,7 +142,7 @@ DeprecationMessage: "deprecated", }, }, }, - expectedAttribute: ` + expected: ` "int64_attribute": schema.Int64Attribute{ Validators: []validator.Int64{ my_validator.Validate(), @@ -132,7 +164,7 @@ my_other_validator.Validate(), t.Errorf("unexpected error: %s", diff) } - if diff := cmp.Diff(got, testCase.expectedAttribute); diff != "" { + if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -166,6 +198,37 @@ func TestGeneratorInt64Attribute_ModelField(t *testing.T) { TfsdkName: "int64_attribute", }, }, + "associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + }, + expected: model.Field{ + Name: "Int64Attribute", + ValueType: "Int64AttributeValue", + TfsdkName: "int64_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "Int64Attribute", + ValueType: "my_custom_value_type", + TfsdkName: "int64_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/provider_generate/number_attribute_test.go b/internal/provider_generate/number_attribute_test.go index 5113b15e..1be108d7 100644 --- a/internal/provider_generate/number_attribute_test.go +++ b/internal/provider_generate/number_attribute_test.go @@ -11,15 +11,16 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorNumberAttribute_Schema(t *testing.T) { t.Parallel() testCases := map[string]struct { - input GeneratorNumberAttribute - expectedAttribute string - expectedError error + input GeneratorNumberAttribute + expected string + expectedError error }{ "custom-type": { input: GeneratorNumberAttribute{ @@ -27,7 +28,38 @@ func TestGeneratorNumberAttribute_Schema(t *testing.T) { Type: "my_custom_type", }, }, - expectedAttribute: ` + expected: ` +"number_attribute": schema.NumberAttribute{ +CustomType: my_custom_type, +},`, + }, + + "associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + }, + expected: ` +"number_attribute": schema.NumberAttribute{ +CustomType: NumberAttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` "number_attribute": schema.NumberAttribute{ CustomType: my_custom_type, },`, @@ -39,7 +71,7 @@ CustomType: my_custom_type, Required: true, }, }, - expectedAttribute: ` + expected: ` "number_attribute": schema.NumberAttribute{ Required: true, },`, @@ -51,7 +83,7 @@ Required: true, Optional: true, }, }, - expectedAttribute: ` + expected: ` "number_attribute": schema.NumberAttribute{ Optional: true, },`, @@ -63,7 +95,7 @@ Optional: true, Sensitive: true, }, }, - expectedAttribute: ` + expected: ` "number_attribute": schema.NumberAttribute{ Sensitive: true, },`, @@ -76,7 +108,7 @@ Sensitive: true, Description: "description", }, }, - expectedAttribute: ` + expected: ` "number_attribute": schema.NumberAttribute{ Description: "description", MarkdownDescription: "description", @@ -89,7 +121,7 @@ MarkdownDescription: "description", DeprecationMessage: "deprecated", }, }, - expectedAttribute: ` + expected: ` "number_attribute": schema.NumberAttribute{ DeprecationMessage: "deprecated", },`, @@ -110,7 +142,7 @@ DeprecationMessage: "deprecated", }, }, }, - expectedAttribute: ` + expected: ` "number_attribute": schema.NumberAttribute{ Validators: []validator.Number{ my_validator.Validate(), @@ -132,7 +164,7 @@ my_other_validator.Validate(), t.Errorf("unexpected error: %s", diff) } - if diff := cmp.Diff(got, testCase.expectedAttribute); diff != "" { + if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -166,6 +198,37 @@ func TestGeneratorNumberAttribute_ModelField(t *testing.T) { TfsdkName: "number_attribute", }, }, + "associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + }, + expected: model.Field{ + Name: "NumberAttribute", + ValueType: "NumberAttributeValue", + TfsdkName: "number_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "NumberAttribute", + ValueType: "my_custom_value_type", + TfsdkName: "number_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/provider_generate/string_attribute_test.go b/internal/provider_generate/string_attribute_test.go index aadb6251..f866a535 100644 --- a/internal/provider_generate/string_attribute_test.go +++ b/internal/provider_generate/string_attribute_test.go @@ -11,15 +11,16 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorStringAttribute_Schema(t *testing.T) { t.Parallel() testCases := map[string]struct { - input GeneratorStringAttribute - expectedAttribute string - expectedError error + input GeneratorStringAttribute + expected string + expectedError error }{ "custom-type": { input: GeneratorStringAttribute{ @@ -27,7 +28,38 @@ func TestGeneratorStringAttribute_Schema(t *testing.T) { Type: "my_custom_type", }, }, - expectedAttribute: ` + expected: ` +"string_attribute": schema.StringAttribute{ +CustomType: my_custom_type, +},`, + }, + + "associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + }, + expected: ` +"string_attribute": schema.StringAttribute{ +CustomType: StringAttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` "string_attribute": schema.StringAttribute{ CustomType: my_custom_type, },`, @@ -39,7 +71,7 @@ CustomType: my_custom_type, Required: true, }, }, - expectedAttribute: ` + expected: ` "string_attribute": schema.StringAttribute{ Required: true, },`, @@ -51,7 +83,7 @@ Required: true, Optional: true, }, }, - expectedAttribute: ` + expected: ` "string_attribute": schema.StringAttribute{ Optional: true, },`, @@ -63,7 +95,7 @@ Optional: true, Sensitive: true, }, }, - expectedAttribute: ` + expected: ` "string_attribute": schema.StringAttribute{ Sensitive: true, },`, @@ -76,7 +108,7 @@ Sensitive: true, Description: "description", }, }, - expectedAttribute: ` + expected: ` "string_attribute": schema.StringAttribute{ Description: "description", MarkdownDescription: "description", @@ -89,7 +121,7 @@ MarkdownDescription: "description", DeprecationMessage: "deprecated", }, }, - expectedAttribute: ` + expected: ` "string_attribute": schema.StringAttribute{ DeprecationMessage: "deprecated", },`, @@ -110,7 +142,7 @@ DeprecationMessage: "deprecated", }, }, }, - expectedAttribute: ` + expected: ` "string_attribute": schema.StringAttribute{ Validators: []validator.String{ my_validator.Validate(), @@ -132,7 +164,7 @@ my_other_validator.Validate(), t.Errorf("unexpected error: %s", diff) } - if diff := cmp.Diff(got, testCase.expectedAttribute); diff != "" { + if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) } }) @@ -166,6 +198,37 @@ func TestGeneratorStringAttribute_ModelField(t *testing.T) { TfsdkName: "string_attribute", }, }, + "associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + }, + expected: model.Field{ + Name: "StringAttribute", + ValueType: "StringAttributeValue", + TfsdkName: "string_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "StringAttribute", + ValueType: "my_custom_value_type", + TfsdkName: "string_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/resource_generate/bool_attribute_test.go b/internal/resource_generate/bool_attribute_test.go index 5d14ae6d..8134b23e 100644 --- a/internal/resource_generate/bool_attribute_test.go +++ b/internal/resource_generate/bool_attribute_test.go @@ -309,6 +309,110 @@ func TestGeneratorBoolAttribute_Imports(t *testing.T) { }, }, }, + "associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + }, + 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: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Import: &code.Import{ + Path: "github.com/api", + }, + Type: "*api.BoolAttribute", + }, + }, + }, + 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: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Import: &code.Import{ + Path: "github.com/api", + }, + Type: "*api.BoolAttribute", + }, + }, + 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 { @@ -346,6 +450,37 @@ CustomType: my_custom_type, },`, }, + "associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + }, + expected: ` +"bool_attribute": schema.BoolAttribute{ +CustomType: BoolAttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"bool_attribute": schema.BoolAttribute{ +CustomType: my_custom_type, +},`, + }, + "required": { input: GeneratorBoolAttribute{ BoolAttribute: schema.BoolAttribute{ @@ -541,6 +676,37 @@ func TestGeneratorBoolAttribute_ModelField(t *testing.T) { TfsdkName: "bool_attribute", }, }, + "associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + }, + expected: model.Field{ + Name: "BoolAttribute", + ValueType: "BoolAttributeValue", + TfsdkName: "bool_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorBoolAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.BoolAttribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "BoolAttribute", + ValueType: "my_custom_value_type", + TfsdkName: "bool_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/resource_generate/float64_attribute_test.go b/internal/resource_generate/float64_attribute_test.go index 68086f61..91653650 100644 --- a/internal/resource_generate/float64_attribute_test.go +++ b/internal/resource_generate/float64_attribute_test.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorFloat64Attribute_Schema(t *testing.T) { @@ -33,6 +34,37 @@ CustomType: my_custom_type, },`, }, + "associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + }, + expected: ` +"float64_attribute": schema.Float64Attribute{ +CustomType: Float64AttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"float64_attribute": schema.Float64Attribute{ +CustomType: my_custom_type, +},`, + }, + "required": { input: GeneratorFloat64Attribute{ Float64Attribute: schema.Float64Attribute{ @@ -228,6 +260,37 @@ func TestGeneratorFloat64Attribute_ModelField(t *testing.T) { TfsdkName: "float64_attribute", }, }, + "associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + }, + expected: model.Field{ + Name: "Float64Attribute", + ValueType: "Float64AttributeValue", + TfsdkName: "float64_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorFloat64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Float64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "Float64Attribute", + ValueType: "my_custom_value_type", + TfsdkName: "float64_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/resource_generate/int64_attribute_test.go b/internal/resource_generate/int64_attribute_test.go index 0fc2347d..08aeb9da 100644 --- a/internal/resource_generate/int64_attribute_test.go +++ b/internal/resource_generate/int64_attribute_test.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorInt64Attribute_Schema(t *testing.T) { @@ -33,6 +34,37 @@ CustomType: my_custom_type, },`, }, + "associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + }, + expected: ` +"int64_attribute": schema.Int64Attribute{ +CustomType: Int64AttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"int64_attribute": schema.Int64Attribute{ +CustomType: my_custom_type, +},`, + }, + "required": { input: GeneratorInt64Attribute{ Int64Attribute: schema.Int64Attribute{ @@ -228,6 +260,37 @@ func TestGeneratorInt64Attribute_ModelField(t *testing.T) { TfsdkName: "int64_attribute", }, }, + "associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + }, + expected: model.Field{ + Name: "Int64Attribute", + ValueType: "Int64AttributeValue", + TfsdkName: "int64_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorInt64Attribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.Int64Attribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "Int64Attribute", + ValueType: "my_custom_value_type", + TfsdkName: "int64_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/resource_generate/number_attribute_test.go b/internal/resource_generate/number_attribute_test.go index ca9db436..64afea61 100644 --- a/internal/resource_generate/number_attribute_test.go +++ b/internal/resource_generate/number_attribute_test.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorNumberAttribute_Schema(t *testing.T) { @@ -33,6 +34,37 @@ CustomType: my_custom_type, },`, }, + "associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + }, + expected: ` +"number_attribute": schema.NumberAttribute{ +CustomType: NumberAttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"number_attribute": schema.NumberAttribute{ +CustomType: my_custom_type, +},`, + }, + "required": { input: GeneratorNumberAttribute{ NumberAttribute: schema.NumberAttribute{ @@ -216,6 +248,37 @@ func TestGeneratorNumberAttribute_ModelField(t *testing.T) { TfsdkName: "number_attribute", }, }, + "associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + }, + expected: model.Field{ + Name: "NumberAttribute", + ValueType: "NumberAttributeValue", + TfsdkName: "number_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorNumberAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.NumberAttribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "NumberAttribute", + ValueType: "my_custom_value_type", + TfsdkName: "number_attribute", + }, + }, } for name, testCase := range testCases { diff --git a/internal/resource_generate/string_attribute_test.go b/internal/resource_generate/string_attribute_test.go index 85f1fe35..08466734 100644 --- a/internal/resource_generate/string_attribute_test.go +++ b/internal/resource_generate/string_attribute_test.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-codegen-framework/internal/model" + generatorschema "github.com/hashicorp/terraform-plugin-codegen-framework/internal/schema" ) func TestGeneratorStringAttribute_Schema(t *testing.T) { @@ -33,6 +34,37 @@ CustomType: my_custom_type, },`, }, + "associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + }, + expected: ` +"string_attribute": schema.StringAttribute{ +CustomType: StringAttributeType{}, +},`, + }, + + "custom-type-overriding-associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + CustomType: &specschema.CustomType{ + Type: "my_custom_type", + }, + }, + expected: ` +"string_attribute": schema.StringAttribute{ +CustomType: my_custom_type, +},`, + }, + "required": { input: GeneratorStringAttribute{ StringAttribute: schema.StringAttribute{ @@ -228,6 +260,37 @@ func TestGeneratorStringAttribute_ModelField(t *testing.T) { TfsdkName: "string_attribute", }, }, + "associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + }, + expected: model.Field{ + Name: "StringAttribute", + ValueType: "StringAttributeValue", + TfsdkName: "string_attribute", + }, + }, + "custom-type-overriding-associated-external-type": { + input: GeneratorStringAttribute{ + AssociatedExternalType: &generatorschema.AssocExtType{ + AssociatedExternalType: &specschema.AssociatedExternalType{ + Type: "*api.StringAttribute", + }, + }, + CustomType: &specschema.CustomType{ + ValueType: "my_custom_value_type", + }, + }, + expected: model.Field{ + Name: "StringAttribute", + ValueType: "my_custom_value_type", + TfsdkName: "string_attribute", + }, + }, } for name, testCase := range testCases { From cc6db53563d17d5ee5cfb22a696ccd76bcaec5fe Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 17 Oct 2023 17:49:31 +0100 Subject: [PATCH 16/19] Temporarily using sha for codegen-spec --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 90955135..c0b5ca20 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/google/go-cmp v0.6.0 - github.com/hashicorp/terraform-plugin-codegen-spec v0.1.0 + github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1-0.20231017164028-264c2bd37f5f github.com/hashicorp/terraform-plugin-framework v1.4.0 github.com/mattn/go-colorable v0.1.12 github.com/mitchellh/cli v1.1.5 diff --git a/go.sum b/go.sum index 9334ca5a..f745f6e1 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+ github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/terraform-plugin-codegen-spec v0.1.0 h1:flL5dprli2h54RxewQi6po02am0zXDRq6nsV6c4WQ/I= -github.com/hashicorp/terraform-plugin-codegen-spec v0.1.0/go.mod h1:PQn6bDD8UWoAVJoHXqFk2i/RmLbeQBjbiP38i+E+YIw= +github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1-0.20231017164028-264c2bd37f5f h1:9n4VInWqA3iiM0AfvanmfXFaiomZt8XwYUqkChRevj8= +github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1-0.20231017164028-264c2bd37f5f/go.mod h1:PQn6bDD8UWoAVJoHXqFk2i/RmLbeQBjbiP38i+E+YIw= github.com/hashicorp/terraform-plugin-framework v1.4.0 h1:WKbtCRtNrjsh10eA7NZvC/Qyr7zp77j+D21aDO5th9c= github.com/hashicorp/terraform-plugin-framework v1.4.0/go.mod h1:XC0hPcQbBvlbxwmjxuV/8sn8SbZRg4XwGMs22f+kqV0= github.com/hashicorp/terraform-plugin-go v0.19.0 h1:BuZx/6Cp+lkmiG0cOBk6Zps0Cb2tmqQpDM3iAtnhDQU= From 82297afa126cc2095403594d2bac595f14f34eaa Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 18 Oct 2023 09:47:46 +0100 Subject: [PATCH 17/19] Adding changelog (#70) --- .changes/unreleased/ENHANCEMENTS-20231018-094607.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changes/unreleased/ENHANCEMENTS-20231018-094607.yaml diff --git a/.changes/unreleased/ENHANCEMENTS-20231018-094607.yaml b/.changes/unreleased/ENHANCEMENTS-20231018-094607.yaml new file mode 100644 index 00000000..acda3bc7 --- /dev/null +++ b/.changes/unreleased/ENHANCEMENTS-20231018-094607.yaml @@ -0,0 +1,6 @@ +kind: ENHANCEMENTS +body: Adds code generation for Bool, Float64, Int64, Number, and String attributes + that have an associated external type +time: 2023-10-18T09:46:07.467187+01:00 +custom: + Issue: "59" From 71f0603103af7cd98f404f7762dd492d58c1cf7b Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 19 Oct 2023 07:59:42 +0100 Subject: [PATCH 18/19] Adding tests for custom string type and value, and to/from methods (#70) --- internal/schema/custom_string_test.go | 460 +++++++++++++++++++++++++ internal/schema/to_from_string_test.go | 133 +++++++ 2 files changed, 593 insertions(+) create mode 100644 internal/schema/custom_string_test.go create mode 100644 internal/schema/to_from_string_test.go diff --git a/internal/schema/custom_string_test.go b/internal/schema/custom_string_test.go new file mode 100644 index 00000000..b17b2e5c --- /dev/null +++ b/internal/schema/custom_string_test.go @@ -0,0 +1,460 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestCustomStringType_renderEqual(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`func (t ExampleType) Equal(o attr.Type) bool { +other, ok := o.(ExampleType) + +if !ok { +return false +} + +return t.StringType.Equal(other.StringType) +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringType := NewCustomStringType(testCase.name) + + got, err := customStringType.renderEqual() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomStringType_renderString(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) String() string { +return "ExampleType" +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringType := NewCustomStringType(testCase.name) + + got, err := customStringType.renderString() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomStringType_renderTypable(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`var _ basetypes.StringTypable = ExampleType{}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringType := NewCustomStringType(testCase.name) + + got, err := customStringType.renderTypable() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomStringType_renderType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`type ExampleType struct { +basetypes.StringType +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringType := NewCustomStringType(testCase.name) + + got, err := customStringType.renderType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomStringType_renderValueFromString(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + attrValues map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + attrValues: map[string]string{ + "bool_attribute": "basetypes.StringValue", + }, + expected: []byte(` +func (t ExampleType) ValueFromString(ctx context.Context, in basetypes.StringValue) (basetypes.StringValuable, diag.Diagnostics) { +return ExampleValue{ +StringValue: in, +}, nil +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringType := NewCustomStringType(testCase.name) + + got, err := customStringType.renderValueFromString() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomStringType_renderValueFromTerraform(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +attrValue, err := t.StringType.ValueFromTerraform(ctx, in) + +if err != nil { +return nil, err +} + +boolValue, ok := attrValue.(basetypes.StringValue) + +if !ok { +return nil, fmt.Errorf("unexpected value type of %T", attrValue) +} + +boolValuable, diags := t.ValueFromString(ctx, boolValue) + +if diags.HasError() { +return nil, fmt.Errorf("unexpected error converting StringValue to StringValuable: %v", diags) +} + +return boolValuable, nil +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringType := NewCustomStringType(testCase.name) + + got, err := customStringType.renderValueFromTerraform() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomStringType_renderValueType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (t ExampleType) ValueType(ctx context.Context) attr.Value { +return ExampleValue{} +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringType := NewCustomStringType(testCase.name) + + got, err := customStringType.renderValueType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomStringValue_renderEqual(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + attrValues map[string]string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + attrValues: map[string]string{ + "bool_attribute": "basetypes.StringValue", + }, + expected: []byte(` +func (v ExampleValue) Equal(o attr.Value) bool { +other, ok := o.(ExampleValue) + +if !ok { +return false +} + +return v.StringValue.Equal(other.StringValue) +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringValue := NewCustomStringValue(testCase.name) + + got, err := customStringValue.renderEqual() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomStringValue_renderType(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(` +func (v ExampleValue) Type(ctx context.Context) attr.Type { +return ExampleType{ +} +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringValue := NewCustomStringValue(testCase.name) + + got, err := customStringValue.renderType() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomStringValue_renderValuable(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`var _ basetypes.StringValuable = ExampleValue{}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringValue := NewCustomStringValue(testCase.name) + + got, err := customStringValue.renderValuable() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestCustomStringValue_renderValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + expected []byte + expectedError error + }{ + "default": { + name: "Example", + expected: []byte(`type ExampleValue struct { +basetypes.StringValue +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + customStringValue := NewCustomStringValue(testCase.name) + + got, err := customStringValue.renderValue() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/internal/schema/to_from_string_test.go b/internal/schema/to_from_string_test.go new file mode 100644 index 00000000..3366aa30 --- /dev/null +++ b/internal/schema/to_from_string_test.go @@ -0,0 +1,133 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package schema + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-codegen-spec/code" + "github.com/hashicorp/terraform-plugin-codegen-spec/schema" +) + +func TestToFromString_renderFrom(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + expected: []byte(` +func (v ExampleValue) FromApisdkType(ctx context.Context, apiObject *apisdk.Type) (ExampleValue, diag.Diagnostics) { +var diags diag.Diagnostics + +if apiObject == nil { +return ExampleValue{ +types.StringNull(), +}, diags +} + +return ExampleValue{ +types.StringPointerValue(*apiObject), +}, diags +} +`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromString := NewToFromString(testCase.name, testCase.assocExtType) + + got, err := toFromString.renderFrom() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestToFromString_renderTo(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + name string + assocExtType *AssocExtType + expected []byte + expectedError error + }{ + "default": { + name: "Example", + assocExtType: &AssocExtType{ + &schema.AssociatedExternalType{ + Import: &code.Import{ + Path: "example.com/apisdk", + }, + Type: "*apisdk.Type", + }, + }, + expected: []byte(`func (v ExampleValue) ToApisdkType(ctx context.Context) (*apisdk.Type, diag.Diagnostics) { +var diags diag.Diagnostics + +if v.IsNull() { +return nil, diags +} + +if v.IsUnknown() { +diags.Append(diag.NewErrorDiagnostic( +"ExampleValue Value Is Unknown", +` + "`" + `"ExampleValue" is unknown.` + "`" + `, +)) + +return nil, diags +} + +a := apisdk.Type(v.ValueStringPointer()) + +return &a, diags +}`), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + toFromString := NewToFromString(testCase.name, testCase.assocExtType) + + got, err := toFromString.renderTo() + + if diff := cmp.Diff(err, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected error: %s", diff) + } + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} From 480283bf07301531f1595fe1077a1576fc2d3db1 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 19 Oct 2023 08:08:46 +0100 Subject: [PATCH 19/19] Using latest codegen-spec SHA from main (#70) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c0b5ca20..c2d70b7b 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/google/go-cmp v0.6.0 - github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1-0.20231017164028-264c2bd37f5f + github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1-0.20231019064449-867ccf6fb279 github.com/hashicorp/terraform-plugin-framework v1.4.0 github.com/mattn/go-colorable v0.1.12 github.com/mitchellh/cli v1.1.5 diff --git a/go.sum b/go.sum index f745f6e1..6494d33a 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+ github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1-0.20231017164028-264c2bd37f5f h1:9n4VInWqA3iiM0AfvanmfXFaiomZt8XwYUqkChRevj8= -github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1-0.20231017164028-264c2bd37f5f/go.mod h1:PQn6bDD8UWoAVJoHXqFk2i/RmLbeQBjbiP38i+E+YIw= +github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1-0.20231019064449-867ccf6fb279 h1:9D8ydY5s8Fw76pqCFtwlm9X7wVJdFLMK2FAqyQoOZT0= +github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1-0.20231019064449-867ccf6fb279/go.mod h1:PQn6bDD8UWoAVJoHXqFk2i/RmLbeQBjbiP38i+E+YIw= github.com/hashicorp/terraform-plugin-framework v1.4.0 h1:WKbtCRtNrjsh10eA7NZvC/Qyr7zp77j+D21aDO5th9c= github.com/hashicorp/terraform-plugin-framework v1.4.0/go.mod h1:XC0hPcQbBvlbxwmjxuV/8sn8SbZRg4XwGMs22f+kqV0= github.com/hashicorp/terraform-plugin-go v0.19.0 h1:BuZx/6Cp+lkmiG0cOBk6Zps0Cb2tmqQpDM3iAtnhDQU=