hashicorp / hashicorp/terraform-plugin-codegen-spec
Consider adding "mapping" to associated_external_type
- Dominant language
- Go
- Stars
- 12
- Forks
- 9
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 1
Description
### Background
Currently, `associated_external_type` is structured as follows:
```json
"associated_external_type": {
"import": {
"path": "github.com/aws/aws-sdk-go/service/imagebuilder"
},
"type": "*imagebuilder.ImageTestsConfiguration"
}
```
The generation of "expand" and "flatten" methods by _terraform_codegen_framework_ will need to make assumptions about how to map from/to the model struct fields to the `associated_external_type.type`, and in the first instance would use a direct one-to-one mapping. For example, if a resource schema looked as follows:
```go
{
"resources": [
{
"name": "aws_imagebuilder_image",
"schema": {
"attributes": [
/* ... */
],
"blocks": [
{
"name": "image_tests_configuration",
"single_nested": {
"associated_external_type": {
"import": {
"path": "github.com/aws/aws-sdk-go/service/imagebuilder"
},
"type": "*imagebuilder.ImageTestsConfiguration"
},
"attributes": [
{
"name": "image_tests_enabled",
"bool": {
"computed_optional_required": "optional"
}
},
{
"name": "timeout_minutes",
"int64": {
"computed_optional_required": "computed_optional"
}
}
]
}
}
/* ... */
]
}
}
/* ... */
],
/* ... */
}
```
Using an assumed one-to-one mapping for `associated_external_type.type` would yield the following "expand" and "flatten" functions:
**"expand"**
```go
func (m ImageTestsConfigurationModel) ToImageTestsConfiguration(ctx context.Context, tfObject types.Object) (*imagebuilder.ImageTestsConfiguration, diag.Diagnostics) {
var diags diag.Diagnostics
if tfObject.IsNull() || tfObject.IsUnknown() {
return nil, diags
}
var tfModel ImageTestsConfigurationModel
diags.Append(tfObject.As(ctx, &tfModel, basetypes.ObjectAsOptions{})...)
if diags.HasError() {
return nil, diags
}
apiObject := &imagebuilder.ImageTestsConfiguration{
ImageTestsEnabled: tfModel.ImageTestsEnabled.ValueBoolPointer(),
TimeoutMinutes: tfModel.TimeoutMinutes.ValueInt64Pointer(),
}
return apiObject, diags
}
```
**"flatten"**
```go
func (m ImageTestsConfigurationModel) FromImageTestsConfiguration(ctx context.Context, apiObject *imagebuilder.ImageTestsConfiguration) (types.Object, diag.Diagnostics) {
var diags diag.Diagnostics
var tfModel ImageTestsConfigurationModel
if apiObject == nil {
return m.objectNull(ctx), diags
}
tfModel.ImageTestsEnabled = types.BoolPointerValue(apiObject.ImageTestsEnabled)
tfModel.TimeoutMinutes = types.Int64PointerValue(apiObject.TimeoutMinutes)
return m.objectValueFrom(ctx)
}
```
There are assumptions made in this mapping, including but not limited to:
- The name of the field in the "apiObject" (*imagebuilder.ImageTestsConfiguration) is identical to the name of the field in the model.
- The type of the field in the "apiObject" (*imagebuilder.ImageTestsConfiguration) is a pointer to the Go type that correlates with the plugin Framework type used by the model (e.g., `types.Bool` <=> `*bool`).
### Proposal
To provide additional flexibility in the mapping to/from models to API objects defined through `associated_external_type` we should consider the introduction of a "mapping" field, or some other representation, that can be used to shape how the "expand" and "flatten" functions are constructed within _terraform_codegen_framework_. For instance, we could allow the defining of `request` and `response` fields for each `associated_external_type`:
```json
"associated_external_type": {
"imports": [
{
"path": "github.com/aws/aws-sdk-go/service/imagebuilder"
}
],
"type": "*imagebuilder.ImageTestsConfiguration",
"request": {
"timeout_minutes": {
"name": "MinutesTimeout",
},
"response": {
"MinutesTimeoutReturnedVal": {
"name": "timeout_minutes",
}
}
},
```
This contrived example would yield the following "expand" and "flatten" functions:
**"expand"**
```go
func (m ImageTestsConfigurationModel) ToImageTestsConfiguration(ctx context.Context, tfObject types.Object) (*imagebuilder.ImageTestsConfiguration, diag.Diagnostics) {
var diags diag.Diagnostics
if tfObject.IsNull() || tfObject.IsUnknown() {
return nil, diags
}
var tfModel ImageTestsConfigurationModel
diags.Append(tfObject.As(ctx, &tfModel, basetypes.ObjectAsOptions{})...)
if diags.HasError() {
return nil, diags
}
apiObject := &imagebuilder.ImageTestsConfiguration{
ImageTestsEnabled: tfModel.ImageTestsEnabled.ValueBoolPointer(),
MinutesTimeout: tfModel.TimeoutMinutes.ValueInt64Pointer(),
}
return apiObject, diags
}
```
**"flatten"**
```go
func (m ImageTestsConfigurationModel) FromImageTestsConfiguration(ctx context.Context, apiObject *imagebuilder.ImageTestsConfiguration) (types.Object, diag.Diagnostics) {
var diags diag.Diagnostics
var tfModel ImageTestsConfigurationModel
if apiObject == nil {
return m.objectNull(ctx), diags
}
tfModel.ImageTestsEnabled = types.BoolPointerValue(apiObject.ImageTestsEnabled)
tfModel.TimeoutMinutes = types.Int64PointerValue(apiObject.MinutesTimeoutReturnedVal)
return m.objectValueFrom(ctx)
}
```
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.