Skip to content

Commit 334f285

Browse files
committed
Support overriding nested attributes
1 parent 91bb667 commit 334f285

File tree

10 files changed

+294
-80
lines changed

10 files changed

+294
-80
lines changed

internal/explorer/config_explorer.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,18 @@ func (e configExplorer) FindResources() (map[string]Resource, error) {
8181
continue
8282
}
8383

84+
parameters, err := extractParameters(e.spec.Paths, resourceConfig.Read.Path)
85+
if err != nil {
86+
errResult = errors.Join(errResult, fmt.Errorf("failed to extract '%s.delete': %w", name, err))
87+
continue
88+
}
89+
8490
resources[name] = Resource{
8591
CreateOp: createOp,
8692
ReadOp: readOp,
8793
UpdateOp: updateOp,
8894
DeleteOp: deleteOp,
95+
Parameters: parameters,
8996
SchemaOptions: extractSchemaOptions(resourceConfig.SchemaOptions),
9097
}
9198
}
@@ -103,8 +110,16 @@ func (e configExplorer) FindDataSources() (map[string]DataSource, error) {
103110
errResult = errors.Join(errResult, fmt.Errorf("failed to extract '%s.read': %w", name, err))
104111
continue
105112
}
113+
114+
parameters, err := extractParameters(e.spec.Paths, dataSourceConfig.Read.Path)
115+
if err != nil {
116+
errResult = errors.Join(errResult, fmt.Errorf("failed to extract '%s.delete': %w", name, err))
117+
continue
118+
}
119+
106120
dataSources[name] = DataSource{
107121
ReadOp: readOp,
122+
Parameters: parameters,
108123
SchemaOptions: extractSchemaOptions(dataSourceConfig.SchemaOptions),
109124
}
110125
}
@@ -145,6 +160,17 @@ func extractOp(paths *high.Paths, oasLocation *config.OpenApiSpecLocation) (*hig
145160
}
146161
}
147162

163+
func extractParameters(paths *high.Paths, path string) ([]*high.Parameter, error) {
164+
// No need to search OAS if not defined
165+
if paths.PathItems.GetOrZero(path) == nil {
166+
return nil, fmt.Errorf("path '%s' not found in OpenAPI spec", path)
167+
}
168+
169+
pathItem, _ := paths.PathItems.Get(path)
170+
171+
return pathItem.Parameters, nil
172+
}
173+
148174
func extractSchemaProxy(document high.Document, componentRef string) (*highbase.SchemaProxy, error) {
149175
// find the reference using the root document.Index
150176
indexRef := document.Index.FindComponentInRoot(componentRef)

internal/explorer/explorer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ type Resource struct {
2121
ReadOp *high.Operation
2222
UpdateOp *high.Operation
2323
DeleteOp *high.Operation
24+
Parameters []*high.Parameter
2425
SchemaOptions SchemaOptions
2526
}
2627

2728
// DataSource contains a Read operation and schema options for configuration.
2829
type DataSource struct {
2930
ReadOp *high.Operation
31+
Parameters []*high.Parameter
3032
SchemaOptions SchemaOptions
3133
}
3234

internal/mapper/attrmapper/data_source_attributes.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer"
1111
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
12+
"github.com/hashicorp/terraform-plugin-codegen-spec/schema"
1213
)
1314

1415
type DataSourceAttribute interface {
@@ -20,6 +21,7 @@ type DataSourceAttribute interface {
2021

2122
type DataSourceNestedAttribute interface {
2223
ApplyNestedOverride([]string, explorer.Override) (DataSourceAttribute, error)
24+
NestedMerge([]string, DataSourceAttribute, schema.ComputedOptionalRequired) (DataSourceAttribute, error)
2325
}
2426

2527
type DataSourceAttributes []DataSourceAttribute
@@ -58,6 +60,46 @@ func (targetSlice DataSourceAttributes) Merge(mergeSlices ...DataSourceAttribute
5860
return targetSlice, errResult
5961
}
6062

63+
func (targetSlice DataSourceAttributes) MergeAttribute(path []string, attribute DataSourceAttribute, intermediateComputability schema.ComputedOptionalRequired) (DataSourceAttributes, error) {
64+
var errResult error
65+
if len(path) == 0 {
66+
return targetSlice, errResult
67+
}
68+
for i, target := range targetSlice {
69+
if target.GetName() == path[0] {
70+
71+
if len(path) > 1 {
72+
nestedTarget, ok := target.(DataSourceNestedAttribute)
73+
if !ok {
74+
// TODO: error? there is a nested override for an attribute that is not a nested type
75+
break
76+
}
77+
78+
// The attribute we need to override is deeper nested, move up
79+
nextPath := path[1:]
80+
81+
overriddenTarget, err := nestedTarget.NestedMerge(nextPath, attribute, intermediateComputability)
82+
errResult = errors.Join(errResult, err)
83+
84+
targetSlice[i] = overriddenTarget
85+
86+
} else {
87+
// No more path to traverse, apply merge, bidirectional
88+
overriddenTarget, err := attribute.Merge(target)
89+
errResult = errors.Join(errResult, err)
90+
overriddenTarget, err = overriddenTarget.Merge(attribute)
91+
errResult = errors.Join(errResult, err)
92+
93+
targetSlice[i] = overriddenTarget
94+
}
95+
96+
break
97+
}
98+
}
99+
100+
return targetSlice, errResult
101+
}
102+
61103
func (attributes DataSourceAttributes) ToSpec() []datasource.Attribute {
62104
specAttributes := make([]datasource.Attribute, 0, len(attributes))
63105
for _, attribute := range attributes {

internal/mapper/attrmapper/list_nested.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
1010
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1111
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
12+
"github.com/hashicorp/terraform-plugin-codegen-spec/schema"
1213
)
1314

1415
type ResourceListNestedAttribute struct {
@@ -50,6 +51,16 @@ func (a *ResourceListNestedAttribute) ApplyNestedOverride(path []string, overrid
5051
return a, err
5152
}
5253

54+
func (a *ResourceListNestedAttribute) NestedMerge(path []string, attribute ResourceAttribute, intermediateComputability schema.ComputedOptionalRequired) (ResourceAttribute, error) {
55+
var err error
56+
a.NestedObject.Attributes, err = a.NestedObject.Attributes.MergeAttribute(path, attribute, intermediateComputability)
57+
if err == nil {
58+
a.ComputedOptionalRequired = intermediateComputability
59+
}
60+
61+
return a, err
62+
}
63+
5364
func (a *ResourceListNestedAttribute) ToSpec() resource.Attribute {
5465
a.ListNestedAttribute.NestedObject = resource.NestedAttributeObject{
5566
Attributes: a.NestedObject.Attributes.ToSpec(),
@@ -100,6 +111,16 @@ func (a *DataSourceListNestedAttribute) ApplyNestedOverride(path []string, overr
100111
return a, err
101112
}
102113

114+
func (a *DataSourceListNestedAttribute) NestedMerge(path []string, attribute DataSourceAttribute, intermediateComputability schema.ComputedOptionalRequired) (DataSourceAttribute, error) {
115+
var err error
116+
a.NestedObject.Attributes, err = a.NestedObject.Attributes.MergeAttribute(path, attribute, intermediateComputability)
117+
if err == nil {
118+
a.ComputedOptionalRequired = intermediateComputability
119+
}
120+
121+
return a, err
122+
}
123+
103124
func (a *DataSourceListNestedAttribute) ToSpec() datasource.Attribute {
104125
a.ListNestedAttribute.NestedObject = datasource.NestedAttributeObject{
105126
Attributes: a.NestedObject.Attributes.ToSpec(),

internal/mapper/attrmapper/map_nested.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
1010
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1111
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
12+
"github.com/hashicorp/terraform-plugin-codegen-spec/schema"
1213
)
1314

1415
type ResourceMapNestedAttribute struct {
@@ -50,6 +51,16 @@ func (a *ResourceMapNestedAttribute) ApplyNestedOverride(path []string, override
5051
return a, err
5152
}
5253

54+
func (a *ResourceMapNestedAttribute) NestedMerge(path []string, attribute ResourceAttribute, intermediateComputability schema.ComputedOptionalRequired) (ResourceAttribute, error) {
55+
var err error
56+
a.NestedObject.Attributes, err = a.NestedObject.Attributes.MergeAttribute(path, attribute, intermediateComputability)
57+
if err == nil {
58+
a.ComputedOptionalRequired = intermediateComputability
59+
}
60+
61+
return a, err
62+
}
63+
5364
func (a *ResourceMapNestedAttribute) ToSpec() resource.Attribute {
5465
a.MapNestedAttribute.NestedObject = resource.NestedAttributeObject{
5566
Attributes: a.NestedObject.Attributes.ToSpec(),
@@ -100,6 +111,16 @@ func (a *DataSourceMapNestedAttribute) ApplyNestedOverride(path []string, overri
100111
return a, err
101112
}
102113

114+
func (a *DataSourceMapNestedAttribute) NestedMerge(path []string, attribute DataSourceAttribute, intermediateComputability schema.ComputedOptionalRequired) (DataSourceAttribute, error) {
115+
var err error
116+
a.NestedObject.Attributes, err = a.NestedObject.Attributes.MergeAttribute(path, attribute, intermediateComputability)
117+
if err == nil {
118+
a.ComputedOptionalRequired = intermediateComputability
119+
}
120+
121+
return a, err
122+
}
123+
103124
func (a *DataSourceMapNestedAttribute) ToSpec() datasource.Attribute {
104125
a.MapNestedAttribute.NestedObject = datasource.NestedAttributeObject{
105126
Attributes: a.NestedObject.Attributes.ToSpec(),

internal/mapper/attrmapper/resource_attributes.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer"
1111
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
12+
"github.com/hashicorp/terraform-plugin-codegen-spec/schema"
1213
)
1314

1415
type ResourceAttribute interface {
@@ -20,6 +21,7 @@ type ResourceAttribute interface {
2021

2122
type ResourceNestedAttribute interface {
2223
ApplyNestedOverride([]string, explorer.Override) (ResourceAttribute, error)
24+
NestedMerge([]string, ResourceAttribute, schema.ComputedOptionalRequired) (ResourceAttribute, error)
2325
}
2426

2527
type ResourceAttributes []ResourceAttribute
@@ -58,6 +60,46 @@ func (targetSlice ResourceAttributes) Merge(mergeSlices ...ResourceAttributes) (
5860
return targetSlice, errResult
5961
}
6062

63+
func (targetSlice ResourceAttributes) MergeAttribute(path []string, attribute ResourceAttribute, intermediateComputability schema.ComputedOptionalRequired) (ResourceAttributes, error) {
64+
var errResult error
65+
if len(path) == 0 {
66+
return targetSlice, errResult
67+
}
68+
for i, target := range targetSlice {
69+
if target.GetName() == path[0] {
70+
71+
if len(path) > 1 {
72+
nestedTarget, ok := target.(ResourceNestedAttribute)
73+
if !ok {
74+
// TODO: error? there is a nested override for an attribute that is not a nested type
75+
break
76+
}
77+
78+
// The attribute we need to override is deeper nested, move up
79+
nextPath := path[1:]
80+
81+
overriddenTarget, err := nestedTarget.NestedMerge(nextPath, attribute, intermediateComputability)
82+
errResult = errors.Join(errResult, err)
83+
84+
targetSlice[i] = overriddenTarget
85+
86+
} else {
87+
// No more path to traverse, apply merge, bidirectional
88+
overriddenTarget, err := attribute.Merge(target)
89+
errResult = errors.Join(errResult, err)
90+
overriddenTarget, err = overriddenTarget.Merge(attribute)
91+
errResult = errors.Join(errResult, err)
92+
93+
targetSlice[i] = overriddenTarget
94+
}
95+
96+
break
97+
}
98+
}
99+
100+
return targetSlice, errResult
101+
}
102+
61103
func (attributes ResourceAttributes) ToSpec() []resource.Attribute {
62104
specAttributes := make([]resource.Attribute, 0, len(attributes))
63105
for _, attribute := range attributes {

internal/mapper/attrmapper/set_nested.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
1010
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1111
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
12+
"github.com/hashicorp/terraform-plugin-codegen-spec/schema"
1213
)
1314

1415
type ResourceSetNestedAttribute struct {
@@ -50,6 +51,16 @@ func (a *ResourceSetNestedAttribute) ApplyNestedOverride(path []string, override
5051
return a, err
5152
}
5253

54+
func (a *ResourceSetNestedAttribute) NestedMerge(path []string, attribute ResourceAttribute, intermediateComputability schema.ComputedOptionalRequired) (ResourceAttribute, error) {
55+
var err error
56+
a.NestedObject.Attributes, err = a.NestedObject.Attributes.MergeAttribute(path, attribute, intermediateComputability)
57+
if err == nil {
58+
a.ComputedOptionalRequired = intermediateComputability
59+
}
60+
61+
return a, err
62+
}
63+
5364
func (a *ResourceSetNestedAttribute) ToSpec() resource.Attribute {
5465
a.SetNestedAttribute.NestedObject = resource.NestedAttributeObject{
5566
Attributes: a.NestedObject.Attributes.ToSpec(),
@@ -100,6 +111,16 @@ func (a *DataSourceSetNestedAttribute) ApplyNestedOverride(path []string, overri
100111
return a, err
101112
}
102113

114+
func (a *DataSourceSetNestedAttribute) NestedMerge(path []string, attribute DataSourceAttribute, intermediateComputability schema.ComputedOptionalRequired) (DataSourceAttribute, error) {
115+
var err error
116+
a.NestedObject.Attributes, err = a.NestedObject.Attributes.MergeAttribute(path, attribute, intermediateComputability)
117+
if err == nil {
118+
a.ComputedOptionalRequired = intermediateComputability
119+
}
120+
121+
return a, err
122+
}
123+
103124
func (a *DataSourceSetNestedAttribute) ToSpec() datasource.Attribute {
104125
a.SetNestedAttribute.NestedObject = datasource.NestedAttributeObject{
105126
Attributes: a.NestedObject.Attributes.ToSpec(),

internal/mapper/attrmapper/single_nested.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
1010
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1111
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
12+
"github.com/hashicorp/terraform-plugin-codegen-spec/schema"
1213
)
1314

1415
type ResourceSingleNestedAttribute struct {
@@ -50,6 +51,16 @@ func (a *ResourceSingleNestedAttribute) ApplyNestedOverride(path []string, overr
5051
return a, err
5152
}
5253

54+
func (a *ResourceSingleNestedAttribute) NestedMerge(path []string, attribute ResourceAttribute, intermediateComputability schema.ComputedOptionalRequired) (ResourceAttribute, error) {
55+
var err error
56+
a.Attributes, err = a.Attributes.MergeAttribute(path, attribute, intermediateComputability)
57+
if err == nil {
58+
a.ComputedOptionalRequired = intermediateComputability
59+
}
60+
61+
return a, err
62+
}
63+
5364
func (a *ResourceSingleNestedAttribute) ToSpec() resource.Attribute {
5465
a.SingleNestedAttribute.Attributes = a.Attributes.ToSpec()
5566

@@ -98,6 +109,16 @@ func (a *DataSourceSingleNestedAttribute) ApplyNestedOverride(path []string, ove
98109
return a, err
99110
}
100111

112+
func (a *DataSourceSingleNestedAttribute) NestedMerge(path []string, attribute DataSourceAttribute, intermediateComputability schema.ComputedOptionalRequired) (DataSourceAttribute, error) {
113+
var err error
114+
a.Attributes, err = a.Attributes.MergeAttribute(path, attribute, intermediateComputability)
115+
if err == nil {
116+
a.ComputedOptionalRequired = intermediateComputability
117+
}
118+
119+
return a, err
120+
}
121+
101122
func (a *DataSourceSingleNestedAttribute) ToSpec() datasource.Attribute {
102123
a.SingleNestedAttribute.Attributes = a.Attributes.ToSpec()
103124

0 commit comments

Comments
 (0)