diff --git a/internal/datasource/list_nested_attribute.go b/internal/datasource/list_nested_attribute.go index d56cbc88..dc5f7e23 100644 --- a/internal/datasource/list_nested_attribute.go +++ b/internal/datasource/list_nested_attribute.go @@ -170,7 +170,13 @@ func (g GeneratorListNestedAttribute) GetAttributes() schema.GeneratorAttributes return g.NestedObject.Attributes } -func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -223,7 +229,7 @@ func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, e // CustomTypeAndValue interface. for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/datasource/list_nested_block.go b/internal/datasource/list_nested_block.go index 18f614c9..9d84e660 100644 --- a/internal/datasource/list_nested_block.go +++ b/internal/datasource/list_nested_block.go @@ -181,7 +181,13 @@ func (g GeneratorListNestedBlock) GetBlocks() schema.GeneratorBlocks { return g.NestedObject.Blocks } -func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorListNestedBlock) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -285,7 +291,7 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -297,13 +303,15 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error for _, k := range blockKeys { if c, ok := g.NestedObject.Blocks[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err } buf.Write(b) + + continue } } diff --git a/internal/datasource/map_nested_attribute.go b/internal/datasource/map_nested_attribute.go index 6c3e6c2c..a1014562 100644 --- a/internal/datasource/map_nested_attribute.go +++ b/internal/datasource/map_nested_attribute.go @@ -170,7 +170,13 @@ func (g GeneratorMapNestedAttribute) GetAttributes() schema.GeneratorAttributes return g.NestedObject.Attributes } -func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -223,7 +229,7 @@ func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, er // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/datasource/set_nested_attribute.go b/internal/datasource/set_nested_attribute.go index 41a477c1..68d78739 100644 --- a/internal/datasource/set_nested_attribute.go +++ b/internal/datasource/set_nested_attribute.go @@ -170,7 +170,13 @@ func (g GeneratorSetNestedAttribute) GetAttributes() schema.GeneratorAttributes return g.NestedObject.Attributes } -func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -223,7 +229,7 @@ func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, er // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/datasource/set_nested_block.go b/internal/datasource/set_nested_block.go index 4a2c6d93..4e4f56fc 100644 --- a/internal/datasource/set_nested_block.go +++ b/internal/datasource/set_nested_block.go @@ -181,7 +181,13 @@ func (g GeneratorSetNestedBlock) GetBlocks() schema.GeneratorBlocks { return g.NestedObject.Blocks } -func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -285,7 +291,7 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -297,13 +303,15 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) for _, k := range blockKeys { if c, ok := g.NestedObject.Blocks[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err } buf.Write(b) + + continue } } diff --git a/internal/datasource/single_nested_attribute.go b/internal/datasource/single_nested_attribute.go index cfaa8e5f..ff6dff3b 100644 --- a/internal/datasource/single_nested_attribute.go +++ b/internal/datasource/single_nested_attribute.go @@ -163,7 +163,13 @@ func (g GeneratorSingleNestedAttribute) GetAttributes() schema.GeneratorAttribut return g.Attributes } -func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.Attributes.AttrValues() @@ -216,7 +222,7 @@ func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/datasource/single_nested_block.go b/internal/datasource/single_nested_block.go index 6107caab..38b8068f 100644 --- a/internal/datasource/single_nested_block.go +++ b/internal/datasource/single_nested_block.go @@ -194,7 +194,13 @@ func (g GeneratorSingleNestedBlock) GetBlocks() schema.GeneratorBlocks { return g.Blocks } -func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.Attributes.AttrValues() @@ -298,7 +304,7 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -310,7 +316,7 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err for _, k := range blockKeys { if c, ok := g.Blocks[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/provider/list_nested_attribute.go b/internal/provider/list_nested_attribute.go index f8fd788c..547c7532 100644 --- a/internal/provider/list_nested_attribute.go +++ b/internal/provider/list_nested_attribute.go @@ -170,7 +170,13 @@ func (g GeneratorListNestedAttribute) GetAttributes() schema.GeneratorAttributes return g.NestedObject.Attributes } -func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -223,7 +229,7 @@ func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, e // CustomTypeAndValue interface. for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/provider/list_nested_block.go b/internal/provider/list_nested_block.go index 4eb2515e..13c703a1 100644 --- a/internal/provider/list_nested_block.go +++ b/internal/provider/list_nested_block.go @@ -181,7 +181,13 @@ func (g GeneratorListNestedBlock) GetBlocks() schema.GeneratorBlocks { return g.NestedObject.Blocks } -func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorListNestedBlock) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -285,7 +291,7 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -297,13 +303,15 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error for _, k := range blockKeys { if c, ok := g.NestedObject.Blocks[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err } buf.Write(b) + + continue } } diff --git a/internal/provider/map_nested_attribute.go b/internal/provider/map_nested_attribute.go index a2671708..1fe12ddd 100644 --- a/internal/provider/map_nested_attribute.go +++ b/internal/provider/map_nested_attribute.go @@ -170,7 +170,13 @@ func (g GeneratorMapNestedAttribute) GetAttributes() schema.GeneratorAttributes return g.NestedObject.Attributes } -func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -223,7 +229,7 @@ func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, er // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/provider/set_nested_attribute.go b/internal/provider/set_nested_attribute.go index 1d169c79..488c861a 100644 --- a/internal/provider/set_nested_attribute.go +++ b/internal/provider/set_nested_attribute.go @@ -170,7 +170,13 @@ func (g GeneratorSetNestedAttribute) GetAttributes() schema.GeneratorAttributes return g.NestedObject.Attributes } -func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -223,7 +229,7 @@ func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, er // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/provider/set_nested_block.go b/internal/provider/set_nested_block.go index eb0ad1a8..38dc665f 100644 --- a/internal/provider/set_nested_block.go +++ b/internal/provider/set_nested_block.go @@ -181,7 +181,13 @@ func (g GeneratorSetNestedBlock) GetBlocks() schema.GeneratorBlocks { return g.NestedObject.Blocks } -func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -285,7 +291,7 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -297,13 +303,15 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) for _, k := range blockKeys { if c, ok := g.NestedObject.Blocks[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err } buf.Write(b) + + continue } } diff --git a/internal/provider/single_nested_attribute.go b/internal/provider/single_nested_attribute.go index 831b0cd3..4c6daf8c 100644 --- a/internal/provider/single_nested_attribute.go +++ b/internal/provider/single_nested_attribute.go @@ -163,7 +163,13 @@ func (g GeneratorSingleNestedAttribute) GetAttributes() schema.GeneratorAttribut return g.Attributes } -func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.Attributes.AttrValues() @@ -216,7 +222,7 @@ func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/provider/single_nested_block.go b/internal/provider/single_nested_block.go index d493fa20..26cb92a3 100644 --- a/internal/provider/single_nested_block.go +++ b/internal/provider/single_nested_block.go @@ -194,7 +194,13 @@ func (g GeneratorSingleNestedBlock) GetBlocks() schema.GeneratorBlocks { return g.Blocks } -func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.Attributes.AttrValues() @@ -298,7 +304,7 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -310,7 +316,7 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err for _, k := range blockKeys { if c, ok := g.Blocks[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/resource/bool_attribute.go b/internal/resource/bool_attribute.go index 28481431..761a051c 100644 --- a/internal/resource/bool_attribute.go +++ b/internal/resource/bool_attribute.go @@ -159,7 +159,13 @@ func (g GeneratorBoolAttribute) ModelField(name generatorschema.FrameworkIdentif return field, nil } -func (g GeneratorBoolAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorBoolAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource/float64_attribute.go b/internal/resource/float64_attribute.go index d5673c69..be1e1423 100644 --- a/internal/resource/float64_attribute.go +++ b/internal/resource/float64_attribute.go @@ -159,7 +159,13 @@ func (g GeneratorFloat64Attribute) ModelField(name generatorschema.FrameworkIden return field, nil } -func (g GeneratorFloat64Attribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorFloat64Attribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource/int64_attribute.go b/internal/resource/int64_attribute.go index dc9fa4d4..ffceb7e8 100644 --- a/internal/resource/int64_attribute.go +++ b/internal/resource/int64_attribute.go @@ -159,7 +159,13 @@ func (g GeneratorInt64Attribute) ModelField(name generatorschema.FrameworkIdenti return field, nil } -func (g GeneratorInt64Attribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorInt64Attribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource/list_attribute.go b/internal/resource/list_attribute.go index 557e3432..f5fdbefa 100644 --- a/internal/resource/list_attribute.go +++ b/internal/resource/list_attribute.go @@ -187,7 +187,13 @@ func (g GeneratorListAttribute) ModelField(name generatorschema.FrameworkIdentif return field, nil } -func (g GeneratorListAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorListAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource/list_nested_attribute.go b/internal/resource/list_nested_attribute.go index baa3570b..f3caec8a 100644 --- a/internal/resource/list_nested_attribute.go +++ b/internal/resource/list_nested_attribute.go @@ -194,7 +194,13 @@ func (g GeneratorListNestedAttribute) GetAttributes() schema.GeneratorAttributes return g.NestedObject.Attributes } -func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -247,7 +253,7 @@ func (g GeneratorListNestedAttribute) CustomTypeAndValue(name string) ([]byte, e // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/resource/list_nested_block.go b/internal/resource/list_nested_block.go index 1ed6ceed..5e729a51 100644 --- a/internal/resource/list_nested_block.go +++ b/internal/resource/list_nested_block.go @@ -194,7 +194,13 @@ func (g GeneratorListNestedBlock) GetBlocks() schema.GeneratorBlocks { return g.NestedObject.Blocks } -func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorListNestedBlock) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -298,7 +304,7 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -310,7 +316,7 @@ func (g GeneratorListNestedBlock) CustomTypeAndValue(name string) ([]byte, error for _, k := range blockKeys { if c, ok := g.NestedObject.Blocks[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/resource/map_attribute.go b/internal/resource/map_attribute.go index 297ef9bb..8601cf70 100644 --- a/internal/resource/map_attribute.go +++ b/internal/resource/map_attribute.go @@ -187,7 +187,13 @@ func (g GeneratorMapAttribute) ModelField(name generatorschema.FrameworkIdentifi return field, nil } -func (g GeneratorMapAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorMapAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource/map_nested_attribute.go b/internal/resource/map_nested_attribute.go index d4fa1fdc..3f9f3214 100644 --- a/internal/resource/map_nested_attribute.go +++ b/internal/resource/map_nested_attribute.go @@ -194,7 +194,13 @@ func (g GeneratorMapNestedAttribute) GetAttributes() schema.GeneratorAttributes return g.NestedObject.Attributes } -func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -247,7 +253,7 @@ func (g GeneratorMapNestedAttribute) CustomTypeAndValue(name string) ([]byte, er // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/resource/number_attribute.go b/internal/resource/number_attribute.go index 4982b961..77a1f2fe 100644 --- a/internal/resource/number_attribute.go +++ b/internal/resource/number_attribute.go @@ -159,7 +159,13 @@ func (g GeneratorNumberAttribute) ModelField(name generatorschema.FrameworkIdent return field, nil } -func (g GeneratorNumberAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorNumberAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource/object_attribute.go b/internal/resource/object_attribute.go index d7c8b0fd..1d2db097 100644 --- a/internal/resource/object_attribute.go +++ b/internal/resource/object_attribute.go @@ -194,7 +194,13 @@ func (g GeneratorObjectAttribute) ModelField(name generatorschema.FrameworkIdent return field, nil } -func (g GeneratorObjectAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorObjectAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource/set_attribute.go b/internal/resource/set_attribute.go index 0515d8bf..1cb60102 100644 --- a/internal/resource/set_attribute.go +++ b/internal/resource/set_attribute.go @@ -187,7 +187,13 @@ func (g GeneratorSetAttribute) ModelField(name generatorschema.FrameworkIdentifi return field, nil } -func (g GeneratorSetAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSetAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/resource/set_nested_attribute.go b/internal/resource/set_nested_attribute.go index 4258003c..a7e9db06 100644 --- a/internal/resource/set_nested_attribute.go +++ b/internal/resource/set_nested_attribute.go @@ -194,7 +194,13 @@ func (g GeneratorSetNestedAttribute) GetAttributes() schema.GeneratorAttributes return g.NestedObject.Attributes } -func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -247,7 +253,7 @@ func (g GeneratorSetNestedAttribute) CustomTypeAndValue(name string) ([]byte, er // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/resource/set_nested_block.go b/internal/resource/set_nested_block.go index 64b4250d..0addb471 100644 --- a/internal/resource/set_nested_block.go +++ b/internal/resource/set_nested_block.go @@ -194,7 +194,13 @@ func (g GeneratorSetNestedBlock) GetBlocks() schema.GeneratorBlocks { return g.NestedObject.Blocks } -func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.NestedObject.Attributes.AttrValues() @@ -298,7 +304,7 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.NestedObject.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -310,13 +316,15 @@ func (g GeneratorSetNestedBlock) CustomTypeAndValue(name string) ([]byte, error) for _, k := range blockKeys { if c, ok := g.NestedObject.Blocks[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err } buf.Write(b) + + continue } } diff --git a/internal/resource/single_nested_attribute.go b/internal/resource/single_nested_attribute.go index 60b3f6bd..e1419f9d 100644 --- a/internal/resource/single_nested_attribute.go +++ b/internal/resource/single_nested_attribute.go @@ -185,7 +185,13 @@ func (g GeneratorSingleNestedAttribute) GetAttributes() schema.GeneratorAttribut return g.Attributes } -func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.Attributes.AttrValues() @@ -238,7 +244,7 @@ func (g GeneratorSingleNestedAttribute) CustomTypeAndValue(name string) ([]byte, // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/resource/single_nested_block.go b/internal/resource/single_nested_block.go index 972390e6..408f8a85 100644 --- a/internal/resource/single_nested_block.go +++ b/internal/resource/single_nested_block.go @@ -205,7 +205,13 @@ func (g GeneratorSingleNestedBlock) GetBlocks() schema.GeneratorBlocks { return g.Blocks } -func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + var buf bytes.Buffer attributeAttrValues, err := g.Attributes.AttrValues() @@ -309,7 +315,7 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err // CustomTypeAndValue interface (i.e, nested attributes). for _, k := range attributeKeys { if c, ok := g.Attributes[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -321,7 +327,7 @@ func (g GeneratorSingleNestedBlock) CustomTypeAndValue(name string) ([]byte, err for _, k := range blockKeys { if c, ok := g.Blocks[k].(schema.CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err diff --git a/internal/resource/string_attribute.go b/internal/resource/string_attribute.go index 5bea3434..46ce4560 100644 --- a/internal/resource/string_attribute.go +++ b/internal/resource/string_attribute.go @@ -159,7 +159,13 @@ func (g GeneratorStringAttribute) ModelField(name generatorschema.FrameworkIdent return field, nil } -func (g GeneratorStringAttribute) CustomTypeAndValue(name string) ([]byte, error) { +func (g GeneratorStringAttribute) CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) { + if _, ok := generated[name]; ok { + return nil, nil + } + + generated[name] = struct{}{} + if g.AssociatedExternalType == nil { return nil, nil } diff --git a/internal/schema/attributes.go b/internal/schema/attributes.go index 101d0ab5..1c3bcdc3 100644 --- a/internal/schema/attributes.go +++ b/internal/schema/attributes.go @@ -83,7 +83,7 @@ func (g GeneratorAttributes) AttrTypes() (map[string]string, error) { case GeneratorSetNestedAttribute: attrTypes[k] = fmt.Sprintf("basetypes.SetType{\nElemType: %sValue{}.Type(ctx),\n}", name.ToPascalCase()) case GeneratorSingleNestedAttribute: - attrTypes[k] = fmt.Sprintf("basetypes.ObjectType{\nAttrTypes: %sValue{}.AttributeTypes(ctx),\n}", name.ToPascalCase()) + attrTypes[k] = fmt.Sprintf("%sType{\nbasetypes.ObjectType{\nAttrTypes: %sValue{}.AttributeTypes(ctx),\n},\n}", name.ToPascalCase(), name.ToPascalCase()) } } @@ -111,7 +111,7 @@ func (g GeneratorAttributes) AttrValues() (map[string]string, error) { case GeneratorSetNestedAttribute: attrValues[k] = "basetypes.SetValue" case GeneratorSingleNestedAttribute: - attrValues[k] = "basetypes.ObjectValue" + attrValues[k] = fmt.Sprintf("%sValue", FrameworkIdentifier(k).ToPascalCase()) } } diff --git a/internal/schema/attrtypes.go b/internal/schema/attrtypes.go index 178d1962..1c533e23 100644 --- a/internal/schema/attrtypes.go +++ b/internal/schema/attrtypes.go @@ -64,7 +64,8 @@ func GetAttrTypes(attrTypes specschema.ObjectAttributeTypes) string { if v.Object.CustomType != nil { aTypes.WriteString(fmt.Sprintf("%s{\nAttrTypes: map[string]attr.Type{\n%s\n},\n}", v.Object.CustomType.Type, GetAttrTypes(v.Object.AttributeTypes))) } else { - aTypes.WriteString(fmt.Sprintf("types.ObjectType{\nAttrTypes: map[string]attr.Type{\n%s\n},\n}", GetAttrTypes(v.Object.AttributeTypes))) + typeName := FrameworkIdentifier(v.Name).ToPascalCase() + aTypes.WriteString(fmt.Sprintf("%sType{\nbasetypes.ObjectType{\nAttrTypes: %sValue{}.AttributeTypes(ctx),\n},\n}", typeName, typeName)) } case v.Set != nil: if v.Set.CustomType != nil { diff --git a/internal/schema/custom_nested_object_test.go b/internal/schema/custom_nested_object_test.go index ad4e77a4..d3906a79 100644 --- a/internal/schema/custom_nested_object_test.go +++ b/internal/schema/custom_nested_object_test.go @@ -1032,37 +1032,15 @@ return objVal, diags attrTypes: map[string]string{ "list_nested_attribute": "basetypes.ListType{}", }, + expected: []byte(` func (v ExampleValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics -listNestedAttribute := types.ListValueMust( -ListNestedAttributeType{ -basetypes.ObjectType{ -AttrTypes: ListNestedAttributeValue{}.AttributeTypes(ctx), -}, -}, -v.ListNestedAttribute.Elements(), -) +var listNestedAttribute attr.Value -if v.ListNestedAttribute.IsNull() { -listNestedAttribute = types.ListNull( -ListNestedAttributeType{ -basetypes.ObjectType{ -AttrTypes: ListNestedAttributeValue{}.AttributeTypes(ctx), -}, -}, -) -} - -if v.ListNestedAttribute.IsUnknown() { -listNestedAttribute = types.ListUnknown( -ListNestedAttributeType{ -basetypes.ObjectType{ -AttrTypes: ListNestedAttributeValue{}.AttributeTypes(ctx), -}, -}, -) +{ + listNestedAttribute = v.ListNestedAttribute } @@ -1099,33 +1077,10 @@ return objVal, diags func (v ExampleValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics -mapNestedAttribute := types.MapValueMust( -MapNestedAttributeType{ -basetypes.ObjectType{ -AttrTypes: MapNestedAttributeValue{}.AttributeTypes(ctx), -}, -}, -v.MapNestedAttribute.Elements(), -) - -if v.MapNestedAttribute.IsNull() { -mapNestedAttribute = types.MapNull( -MapNestedAttributeType{ -basetypes.ObjectType{ -AttrTypes: MapNestedAttributeValue{}.AttributeTypes(ctx), -}, -}, -) -} +var mapNestedAttribute attr.Value -if v.MapNestedAttribute.IsUnknown() { -mapNestedAttribute = types.MapUnknown( -MapNestedAttributeType{ -basetypes.ObjectType{ -AttrTypes: MapNestedAttributeValue{}.AttributeTypes(ctx), -}, -}, -) +{ + mapNestedAttribute = v.MapNestedAttribute } @@ -1162,33 +1117,10 @@ return objVal, diags func (v ExampleValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics -setNestedAttribute := types.SetValueMust( -SetNestedAttributeType{ -basetypes.ObjectType{ -AttrTypes: SetNestedAttributeValue{}.AttributeTypes(ctx), -}, -}, -v.SetNestedAttribute.Elements(), -) - -if v.SetNestedAttribute.IsNull() { -setNestedAttribute = types.SetNull( -SetNestedAttributeType{ -basetypes.ObjectType{ -AttrTypes: SetNestedAttributeValue{}.AttributeTypes(ctx), -}, -}, -) -} +var setNestedAttribute attr.Value -if v.SetNestedAttribute.IsUnknown() { -setNestedAttribute = types.SetUnknown( -SetNestedAttributeType{ -basetypes.ObjectType{ -AttrTypes: SetNestedAttributeValue{}.AttributeTypes(ctx), -}, -}, -) +{ + setNestedAttribute = v.SetNestedAttribute } @@ -1258,33 +1190,10 @@ return objVal, diags func (v ExampleValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics -exampleType := types.ListValueMust( -TypeType{ -basetypes.ObjectType{ -AttrTypes: TypeValue{}.AttributeTypes(ctx), -}, -}, -v.ExampleType.Elements(), -) - -if v.ExampleType.IsNull() { -exampleType = types.ListNull( -TypeType{ -basetypes.ObjectType{ -AttrTypes: TypeValue{}.AttributeTypes(ctx), -}, -}, -) -} +var exampleType attr.Value -if v.ExampleType.IsUnknown() { -exampleType = types.ListUnknown( -TypeType{ -basetypes.ObjectType{ -AttrTypes: TypeValue{}.AttributeTypes(ctx), -}, -}, -) +{ + exampleType = v.ExampleType } diff --git a/internal/schema/schema.go b/internal/schema/schema.go index f9b287da..a5d85faa 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -247,6 +247,8 @@ func (g GeneratorSchema) Models(name string) ([]model.Model, error) { func (g GeneratorSchema) CustomTypeValueBytes() ([]byte, error) { var buf bytes.Buffer + generated := make(map[string]struct{}) + attributeKeys := g.Attributes.SortedKeys() for _, k := range attributeKeys { @@ -255,7 +257,7 @@ func (g GeneratorSchema) CustomTypeValueBytes() ([]byte, error) { } if c, ok := g.Attributes[k].(CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -273,7 +275,7 @@ func (g GeneratorSchema) CustomTypeValueBytes() ([]byte, error) { } if c, ok := g.Blocks[k].(CustomTypeAndValue); ok { - b, err := c.CustomTypeAndValue(k) + b, err := c.CustomTypeAndValue(k, generated) if err != nil { return nil, err @@ -282,7 +284,6 @@ func (g GeneratorSchema) CustomTypeValueBytes() ([]byte, error) { buf.Write(b) } } - if buf.Len() > 0 { buf.WriteString("\n") } @@ -443,11 +444,12 @@ func AttrTypesString(attrTypes specschema.ObjectAttributeTypes) (string, error) case v.Number != nil: attrTypesStr = append(attrTypesStr, fmt.Sprintf("%q: types.NumberType", v.Name)) case v.Object != nil: - objAttrTypesStr, err := AttrTypesString(v.Object.AttributeTypes) - if err != nil { - return "", err + if v.Object.CustomType != nil { + attrTypesStr = append(attrTypesStr, fmt.Sprintf("%q: %s", v.Name, v.Object.CustomType.Type)) + } else { + typeName := FrameworkIdentifier(v.Name).ToPascalCase() + attrTypesStr = append(attrTypesStr, fmt.Sprintf("%q: %sType{\nbasetypes.ObjectType{\nAttrTypes: %sValue{}.AttributeTypes(ctx),\n},\n}", v.Name, typeName, typeName)) } - attrTypesStr = append(attrTypesStr, fmt.Sprintf("%q: types.ObjectType{\nAttrTypes: map[string]attr.Type{\n%s,\n}\n}", v.Name, objAttrTypesStr)) case v.Set != nil: elemType, err := ElementTypeString(v.Set.ElementType) if err != nil { diff --git a/internal/schema/templates/nested_object_value_to_object_value.gotmpl b/internal/schema/templates/nested_object_value_to_object_value.gotmpl index ddf98ccd..34116827 100644 --- a/internal/schema/templates/nested_object_value_to_object_value.gotmpl +++ b/internal/schema/templates/nested_object_value_to_object_value.gotmpl @@ -3,62 +3,18 @@ func (v {{.Name}}Value) ToObjectValue(ctx context.Context) (basetypes.ObjectValu var diags diag.Diagnostics {{- range $key, $value := .AttributeTypes }} {{- if eq $value "ListNested" "MapNested" "SetNested"}} -{{- $typesType := "List"}} -{{- if eq $value "MapNested"}} -{{- $typesType = "Map"}} -{{- else if eq $value "SetNested"}} -{{- $typesType = "Set"}} -{{- end}} -{{$key.ToPrefixCamelCase $.Name}} := types.{{$typesType}}ValueMust( -{{$key.ToPascalCase}}Type{ -basetypes.ObjectType{ -AttrTypes: {{$key.ToPascalCase}}Value{}.AttributeTypes(ctx), -}, -}, -v.{{$key.ToPrefixPascalCase $.Name}}.Elements(), -) - -if v.{{$key.ToPrefixPascalCase $.Name}}.IsNull() { -{{$key.ToPrefixCamelCase $.Name}} = types.{{$typesType}}Null( -{{$key.ToPascalCase}}Type{ -basetypes.ObjectType{ -AttrTypes: {{$key.ToPascalCase}}Value{}.AttributeTypes(ctx), -}, -}, -) -} +var {{$key.ToPrefixCamelCase $.Name}} attr.Value -if v.{{$key.ToPrefixPascalCase $.Name}}.IsUnknown() { -{{$key.ToPrefixCamelCase $.Name}} = types.{{$typesType}}Unknown( -{{$key.ToPascalCase}}Type{ -basetypes.ObjectType{ -AttrTypes: {{$key.ToPascalCase}}Value{}.AttributeTypes(ctx), -}, -}, -) +{ + {{$key.ToPrefixCamelCase $.Name}} = v.{{$key.ToPrefixPascalCase $.Name}} } {{else if eq $value "SingleNested"}} -var {{$key.ToCamelCase}} basetypes.ObjectValue - -if v.{{$key.ToPascalCase}}.IsNull() { -{{$key.ToCamelCase}} = types.ObjectNull( -{{$key.ToPascalCase}}Value{}.AttributeTypes(ctx), -) -} - -if v.{{$key.ToPascalCase}}.IsUnknown() { -{{$key.ToCamelCase}} = types.ObjectUnknown( -{{$key.ToPascalCase}}Value{}.AttributeTypes(ctx), -) -} +var {{$key.ToCamelCase}} attr.Value -if !v.{{$key.ToPascalCase}}.IsNull() && !v.{{$key.ToPascalCase}}.IsUnknown() { -{{$key.ToCamelCase}} = types.ObjectValueMust( -{{$key.ToPascalCase}}Value{}.AttributeTypes(ctx), -v.{{$key.ToPascalCase}}.Attributes(), -) +{ + {{$key.ToCamelCase}} = v.{{$key.ToPascalCase}} } {{end}} {{- end}} diff --git a/internal/schema/types.go b/internal/schema/types.go index 3521d347..2074119c 100644 --- a/internal/schema/types.go +++ b/internal/schema/types.go @@ -23,7 +23,7 @@ type Blocks interface { } type CustomTypeAndValue interface { - CustomTypeAndValue(name string) ([]byte, error) + CustomTypeAndValue(name string, generated map[string]struct{}) ([]byte, error) } type Elements interface {