Skip to content

Commit ab19251

Browse files
committed
Add object type.
1 parent ffefbe4 commit ab19251

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed

types/object.go

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package types
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-framework/attr"
7+
"github.com/hashicorp/terraform-plugin-go/tftypes"
8+
)
9+
10+
// ObjectType is an AttributeType representing a object
11+
type ObjectType struct {
12+
AttributeTypes map[string]attr.Type
13+
}
14+
15+
// TerraformType returns the tftypes.Type that should be used to
16+
// represent this type. This constrains what user input will be
17+
// accepted and what kind of data can be set in state. The framework
18+
// will use this to translate the AttributeType to something Terraform
19+
// can understand.
20+
func (o ObjectType) TerraformType(ctx context.Context) tftypes.Type {
21+
var attributeTypes map[string]tftypes.Type
22+
for k, v := range o.AttributeTypes {
23+
attributeTypes[k] = v.TerraformType(ctx)
24+
}
25+
return tftypes.Object{
26+
AttributeTypes: attributeTypes,
27+
}
28+
}
29+
30+
// ValueFromTerraform returns an AttributeValue given a tftypes.Value.
31+
// This is meant to convert the tftypes.Value into a more convenient Go
32+
// type for the provider to consume the data with.
33+
func (o ObjectType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
34+
object := &Object{
35+
AttributeTypes: o.AttributeTypes,
36+
}
37+
err := object.SetTerraformValue(ctx, in)
38+
return object, err
39+
}
40+
41+
// Equal returns true if `candidate` is also an ObjectType and has the same
42+
// AttributeTypes.
43+
func (o ObjectType) Equal(candidate attr.Type) bool {
44+
other, ok := candidate.(ObjectType)
45+
if !ok {
46+
return false
47+
}
48+
if len(other.AttributeTypes) != len(o.AttributeTypes) {
49+
return false
50+
}
51+
for k, v := range o.AttributeTypes {
52+
attr, ok := other.AttributeTypes[k]
53+
if !ok {
54+
return false
55+
}
56+
if !v.Equal(attr) {
57+
return false
58+
}
59+
}
60+
return true
61+
}
62+
63+
// Object represents an object
64+
type Object struct {
65+
// Unknown will be set to true if the entire object is an unknown value.
66+
// If only some of the elements in the object are unknown, their known or
67+
// unknown status will be represented however that AttributeValue
68+
// surfaces that information. The Object's Unknown property only tracks
69+
// if the number of elements in a Object is known, not whether the
70+
// elements that are in the object are known.
71+
Unknown bool
72+
73+
// Null will be set to true if the object is null, either because it was
74+
// omitted from the configuration, state, or plan, or because it was
75+
// explicitly set to null.
76+
Null bool
77+
78+
Attributes map[string]attr.Value
79+
80+
AttributeTypes map[string]attr.Type
81+
}
82+
83+
// ToTerraformValue returns the data contained in the AttributeValue as
84+
// a Go type that tftypes.NewValue will accept.
85+
func (o *Object) ToTerraformValue(ctx context.Context) (interface{}, error) {
86+
if o.Unknown {
87+
return tftypes.UnknownValue, nil
88+
}
89+
if o.Null {
90+
return nil, nil
91+
}
92+
var vals map[string]tftypes.Value
93+
94+
for k, v := range o.Attributes {
95+
val, err := v.ToTerraformValue(ctx)
96+
if err != nil {
97+
return nil, err
98+
}
99+
err = tftypes.ValidateValue(o.AttributeTypes[k].TerraformType(ctx), val)
100+
if err != nil {
101+
return nil, err
102+
}
103+
vals[k] = tftypes.NewValue(o.AttributeTypes[k].TerraformType(ctx), val)
104+
}
105+
return vals, nil
106+
}
107+
108+
// Equal must return true if the AttributeValue is considered
109+
// semantically equal to the AttributeValue passed as an argument.
110+
func (o *Object) Equal(c attr.Value) bool {
111+
other, ok := c.(*Object)
112+
if !ok {
113+
return false
114+
}
115+
if o.Unknown != other.Unknown {
116+
return false
117+
}
118+
if o.Null != other.Null {
119+
return false
120+
}
121+
if len(o.AttributeTypes) != len(other.AttributeTypes) {
122+
return false
123+
}
124+
for k, v := range o.AttributeTypes {
125+
attr, ok := other.AttributeTypes[k]
126+
if !ok {
127+
return false
128+
}
129+
if !v.Equal(attr) {
130+
return false
131+
}
132+
}
133+
if len(o.Attributes) != len(other.Attributes) {
134+
return false
135+
}
136+
for k, v := range o.Attributes {
137+
attr, ok := other.Attributes[k]
138+
if !ok {
139+
return false
140+
}
141+
if !v.Equal(attr) {
142+
return false
143+
}
144+
}
145+
146+
return true
147+
}
148+
149+
// SetTerraformValue updates `o` to reflect the data stored in `in`.
150+
func (o *Object) SetTerraformValue(ctx context.Context, in tftypes.Value) error {
151+
o.Unknown = false
152+
o.Null = false
153+
o.Attributes = nil
154+
if !in.IsKnown() {
155+
o.Unknown = true
156+
return nil
157+
}
158+
if in.IsNull() {
159+
o.Null = true
160+
return nil
161+
}
162+
attributes := map[string]attr.Value{}
163+
164+
val := map[string]tftypes.Value{}
165+
err := in.As(&val)
166+
if err != nil {
167+
return err
168+
}
169+
170+
for k, v := range val {
171+
a, err := o.AttributeTypes[k].ValueFromTerraform(ctx, v)
172+
if err != nil {
173+
return err
174+
}
175+
attributes[k] = a
176+
}
177+
o.Attributes = attributes
178+
return nil
179+
}

0 commit comments

Comments
 (0)