Skip to content

Commit 3eb2eb7

Browse files
committed
add dynamic attribute to list schemas
1 parent 0b84476 commit 3eb2eb7

File tree

2 files changed

+661
-0
lines changed

2 files changed

+661
-0
lines changed

list/schema/dynamic_attribute.go

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package schema
5+
6+
import (
7+
"github.com/hashicorp/terraform-plugin-go/tftypes"
8+
9+
"github.com/hashicorp/terraform-plugin-framework/attr"
10+
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
11+
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema/fwxschema"
12+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
13+
"github.com/hashicorp/terraform-plugin-framework/types"
14+
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
15+
)
16+
17+
// Ensure the implementation satisifies the desired interfaces.
18+
var (
19+
_ Attribute = DynamicAttribute{}
20+
_ fwxschema.AttributeWithDynamicValidators = DynamicAttribute{}
21+
)
22+
23+
// DynamicAttribute represents a schema attribute that is a dynamic, rather
24+
// than a single static type. Static types are always preferable over dynamic
25+
// types in Terraform as practitioners will receive less helpful configuration
26+
// assistance from validation error diagnostics and editor integrations. When
27+
// retrieving the value for this attribute, use types.Dynamic as the value type
28+
// unless the CustomType field is set.
29+
//
30+
// The concrete value type for a dynamic is determined at runtime in this order:
31+
// 1. By Terraform, if defined in the configuration (if Required or Optional).
32+
// 2. By the provider (if Computed).
33+
//
34+
// Once the concrete value type has been determined, it must remain consistent between
35+
// plan and apply or Terraform will return an error.
36+
type DynamicAttribute struct {
37+
// CustomType enables the use of a custom attribute type in place of the
38+
// default basetypes.DynamicType. When retrieving data, the basetypes.DynamicValuable
39+
// associated with this custom type must be used in place of types.Dynamic.
40+
CustomType basetypes.DynamicTypable
41+
42+
// Required indicates whether the practitioner must enter a value for
43+
// this attribute or not. Required and Optional cannot both be true.
44+
Required bool
45+
46+
// Optional indicates whether the practitioner can choose to enter a value
47+
// for this attribute or not. Optional and Required cannot both be true.
48+
Optional bool
49+
50+
// Description is used in various tooling, like the language server, to
51+
// give practitioners more information about what this attribute is,
52+
// what it's for, and how it should be used. It should be written as
53+
// plain text, with no special formatting.
54+
Description string
55+
56+
// MarkdownDescription is used in various tooling, like the
57+
// documentation generator, to give practitioners more information
58+
// about what this attribute is, what it's for, and how it should be
59+
// used. It should be formatted using Markdown.
60+
MarkdownDescription string
61+
62+
// DeprecationMessage defines warning diagnostic details to display when
63+
// practitioner configurations use this Attribute. The warning diagnostic
64+
// summary is automatically set to "Attribute Deprecated" along with
65+
// configuration source file and line information.
66+
//
67+
// Set this field to a practitioner actionable message such as:
68+
//
69+
// - "Configure other_attribute instead. This attribute will be removed
70+
// in the next major version of the provider."
71+
// - "Remove this attribute's configuration as it no longer is used and
72+
// the attribute will be removed in the next major version of the
73+
// provider."
74+
//
75+
// In Terraform 1.2.7 and later, this warning diagnostic is displayed any
76+
// time a practitioner attempts to configure a value for this attribute and
77+
// certain scenarios where this attribute is referenced.
78+
//
79+
// In Terraform 1.2.6 and earlier, this warning diagnostic is only
80+
// displayed when the Attribute is Required or Optional, and if the
81+
// practitioner configuration sets the value to a known or unknown value
82+
// (which may eventually be null). It has no effect when the Attribute is
83+
// Computed-only (read-only; not Required or Optional).
84+
//
85+
// Across any Terraform version, there are no warnings raised for
86+
// practitioner configuration values set directly to null, as there is no
87+
// way for the framework to differentiate between an unset and null
88+
// configuration due to how Terraform sends configuration information
89+
// across the protocol.
90+
//
91+
// Additional information about deprecation enhancements for read-only
92+
// attributes can be found in:
93+
//
94+
// - https://github.com/hashicorp/terraform/issues/7569
95+
//
96+
DeprecationMessage string
97+
98+
// Validators define value validation functionality for the attribute. All
99+
// elements of the slice of AttributeValidator are run, regardless of any
100+
// previous error diagnostics.
101+
//
102+
// Many common use case validators can be found in the
103+
// github.com/hashicorp/terraform-plugin-framework-validators Go module.
104+
//
105+
// If the Type field points to a custom type that implements the
106+
// xattr.TypeWithValidate interface, the validators defined in this field
107+
// are run in addition to the validation defined by the type.
108+
Validators []validator.Dynamic
109+
}
110+
111+
// ApplyTerraform5AttributePathStep always returns an error as it is not
112+
// possible to step further into a DynamicAttribute.
113+
func (a DynamicAttribute) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) {
114+
return a.GetType().ApplyTerraform5AttributePathStep(step)
115+
}
116+
117+
// Equal returns true if the given Attribute is a DynamicAttribute
118+
// and all fields are equal.
119+
func (a DynamicAttribute) Equal(o fwschema.Attribute) bool {
120+
if _, ok := o.(DynamicAttribute); !ok {
121+
return false
122+
}
123+
124+
return fwschema.AttributesEqual(a, o)
125+
}
126+
127+
// GetDeprecationMessage returns the DeprecationMessage field value.
128+
func (a DynamicAttribute) GetDeprecationMessage() string {
129+
return a.DeprecationMessage
130+
}
131+
132+
// GetDescription returns the Description field value.
133+
func (a DynamicAttribute) GetDescription() string {
134+
return a.Description
135+
}
136+
137+
// GetMarkdownDescription returns the MarkdownDescription field value.
138+
func (a DynamicAttribute) GetMarkdownDescription() string {
139+
return a.MarkdownDescription
140+
}
141+
142+
// GetType returns types.DynamicType or the CustomType field value if defined.
143+
func (a DynamicAttribute) GetType() attr.Type {
144+
if a.CustomType != nil {
145+
return a.CustomType
146+
}
147+
148+
return types.DynamicType
149+
}
150+
151+
// IsComputed returns false because it does not apply to ListResource schemas.
152+
func (a DynamicAttribute) IsComputed() bool {
153+
return false
154+
}
155+
156+
// IsOptional returns the Optional field value.
157+
func (a DynamicAttribute) IsOptional() bool {
158+
return a.Optional
159+
}
160+
161+
// IsRequired returns the Required field value.
162+
func (a DynamicAttribute) IsRequired() bool {
163+
return a.Required
164+
}
165+
166+
// IsSensitive returns false because it does not apply to ListResource schemas.
167+
func (a DynamicAttribute) IsSensitive() bool {
168+
return false
169+
}
170+
171+
// IsWriteOnly returns false as write-only attributes are not relevant to ephemeral resource schemas,
172+
// as these schemas describe data that is explicitly not saved to any artifact.
173+
func (a DynamicAttribute) IsWriteOnly() bool {
174+
return false
175+
}
176+
177+
// DynamicValidators returns the Validators field value.
178+
func (a DynamicAttribute) DynamicValidators() []validator.Dynamic {
179+
return a.Validators
180+
}
181+
182+
// IsRequiredForImport returns false as this behavior is only relevant
183+
// for managed resource identity schema attributes.
184+
func (a DynamicAttribute) IsRequiredForImport() bool {
185+
return false
186+
}
187+
188+
// IsOptionalForImport returns false as this behavior is only relevant
189+
// for managed resource identity schema attributes.
190+
func (a DynamicAttribute) IsOptionalForImport() bool {
191+
return false
192+
}

0 commit comments

Comments
 (0)