Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal/schema: add AttrImport for object model helper #33

Merged
merged 1 commit into from
Aug 8, 2023

Conversation

austinvalle
Copy link
Member

When running an IR.json like below that generates object model helpers, the "github.com/hashicorp/terraform-plugin-framework/attr" was not being added:

IR.json

{
	"datasources": [
		{
			"name": "order",
			"schema": {
				"attributes": [
					{
						"name": "orderId",
						"int64": {
							"computed_optional_required": "required",
							"description": "ID of order that needs to be fetched"
						}
					},
					{
						"name": "complete",
						"bool": {
							"computed_optional_required": "computed"
						}
					},
					{
						"name": "id",
						"int64": {
							"computed_optional_required": "computed"
						}
					},
					{
						"name": "petId",
						"int64": {
							"computed_optional_required": "computed"
						}
					},
					{
						"name": "quantity",
						"int64": {
							"computed_optional_required": "computed"
						}
					},
					{
						"name": "shipDate",
						"string": {
							"computed_optional_required": "computed"
						}
					},
					{
						"name": "status",
						"string": {
							"computed_optional_required": "computed",
							"description": "Order Status"
						}
					}
				]
			}
		}
	],
	"provider": {
		"name": "petstore"
	},
	"resources": [
		{
			"name": "pet",
			"schema": {
				"attributes": [
					{
						"name": "category",
						"single_nested": {
							"computed_optional_required": "computed_optional",
							"attributes": [
								{
									"name": "id",
									"string": {
										"computed_optional_required": "required"
									}
								},
								{
									"name": "name",
									"string": {
										"computed_optional_required": "computed_optional"
									}
								}
							]
						}
					},
					{
						"name": "id",
						"int64": {
							"computed_optional_required": "computed_optional"
						}
					},
					{
						"name": "name",
						"string": {
							"computed_optional_required": "required"
						}
					},
					{
						"name": "photoUrls",
						"list": {
							"computed_optional_required": "required",
							"element_type": {
								"string": {}
							}
						}
					},
					{
						"name": "status",
						"string": {
							"computed_optional_required": "computed_optional",
							"description": "pet status in the store",
							"validators": [
								{
									"custom": {
										"imports": [
											{
												"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
											}
										],
										"schema_definition": "stringvalidator.OneOf(\n\"available\",\n\"pending\",\n\"sold\",\n)"
									}
								}
							]
						}
					},
					{
						"name": "tags",
						"list_nested": {
							"computed_optional_required": "computed_optional",
							"nested_object": {
								"attributes": [
									{
										"name": "id",
										"int64": {
											"computed_optional_required": "required"
										}
									},
									{
										"name": "name",
										"string": {
											"computed_optional_required": "computed_optional"
										}
									}
								]
							}
						}
					},
					{
						"name": "petId",
						"int64": {
							"computed_optional_required": "computed_optional",
							"description": "ID of pet to return"
						}
					}
				]
			}
		}
	]
}

Result after changes

// Code generated by terraform-plugin-framework-generator DO NOT EDIT.

package provider

import (
	"context"
	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
	"github.com/hashicorp/terraform-plugin-framework/attr"
	"github.com/hashicorp/terraform-plugin-framework/diag"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
	"github.com/hashicorp/terraform-plugin-framework/types"
)

var petResourceSchema = schema.Schema{
	Attributes: map[string]schema.Attribute{
		"category": schema.SingleNestedAttribute{
			Attributes: map[string]schema.Attribute{
				"id": schema.Int64Attribute{
					Optional: true,
					Computed: true,
				},
				"name": schema.StringAttribute{
					Optional: true,
					Computed: true,
				},
			},
			Optional: true,
			Computed: true,
		},
		"id": schema.Int64Attribute{
			Optional: true,
			Computed: true,
		},
		"name": schema.StringAttribute{
			Required: true,
		},
		"petId": schema.Int64Attribute{
			Optional:            true,
			Computed:            true,
			Description:         "ID of pet to return",
			MarkdownDescription: "ID of pet to return",
		},
		"photoUrls": schema.ListAttribute{
			ElementType: types.StringType,
			Required:    true,
		},
		"status": schema.StringAttribute{
			Optional:            true,
			Computed:            true,
			Description:         "pet status in the store",
			MarkdownDescription: "pet status in the store",
			Validators: []validator.String{
				stringvalidator.OneOf(
					"available",
					"pending",
					"sold",
				),
			},
		},
		"tags": schema.ListNestedAttribute{
			NestedObject: schema.NestedAttributeObject{
				Attributes: map[string]schema.Attribute{
					"id": schema.Int64Attribute{
						Required: true,
					},
					"name": schema.StringAttribute{
						Optional: true,
						Computed: true,
					},
				},
			},
			Optional: true,
			Computed: true,
		},
	},
}

type PetModel struct {
	Category  types.Object `tfsdk:"category"`
	Id        types.Int64  `tfsdk:"id"`
	Name      types.String `tfsdk:"name"`
	PetId     types.Int64  `tfsdk:"petId"`
	PhotoUrls types.List   `tfsdk:"photoUrls"`
	Status    types.String `tfsdk:"status"`
	Tags      types.List   `tfsdk:"tags"`
}

type CategoryModel struct {
	Id   types.Int64  `tfsdk:"id"`
	Name types.String `tfsdk:"name"`
}

type TagsModel struct {
	Id   types.Int64  `tfsdk:"id"`
	Name types.String `tfsdk:"name"`
}

func (m CategoryModel) ObjectType(ctx context.Context) types.ObjectType {
	return types.ObjectType{AttrTypes: m.ObjectAttributeTypes(ctx)}
}

func (m CategoryModel) ObjectAttributeTypes(ctx context.Context) map[string]attr.Type {
	return map[string]attr.Type{
		"id":   types.Int64Type,
		"name": types.StringType,
	}
}

func (m CategoryModel) ObjectNull(ctx context.Context) types.Object {
	return types.ObjectNull(
		m.ObjectAttributeTypes(ctx),
	)
}

func (m CategoryModel) ObjectValueFrom(ctx context.Context, data any) (types.Object, diag.Diagnostics) {
	return types.ObjectValueFrom(
		ctx,
		m.ObjectAttributeTypes(ctx),
		data,
	)
}
func (m TagsModel) ObjectType(ctx context.Context) types.ObjectType {
	return types.ObjectType{AttrTypes: m.ObjectAttributeTypes(ctx)}
}

func (m TagsModel) ObjectAttributeTypes(ctx context.Context) map[string]attr.Type {
	return map[string]attr.Type{
		"id":   types.Int64Type,
		"name": types.StringType,
	}
}

func (m TagsModel) ObjectNull(ctx context.Context) types.Object {
	return types.ObjectNull(
		m.ObjectAttributeTypes(ctx),
	)
}

func (m TagsModel) ObjectValueFrom(ctx context.Context, data any) (types.Object, diag.Diagnostics) {
	return types.ObjectValueFrom(
		ctx,
		m.ObjectAttributeTypes(ctx),
		data,
	)
}

@austinvalle austinvalle requested a review from a team as a code owner August 8, 2023 19:09
@bflad
Copy link
Contributor

bflad commented Aug 8, 2023

Mentioned out-of-band, but I'm worried about these "global" imports causing the opposite problem of Go code that doesn't compile because of unused imports. Ideally, I think those imports would be associated with object-like attributes that generate the data model helpers, so they only get added when necessary.

Copy link
Contributor

@bflad bflad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent the problem I mention before, I think we'd also generate the object methods for the top-level model as well which would then cause the unused import problem to not exist. If we do make the object method generation optional (e.g. CLI flag), then we can worry about solving this problem then.

@austinvalle austinvalle merged commit 4892af1 into main Aug 8, 2023
@austinvalle austinvalle deleted the av/add-attr branch August 8, 2023 19:56
@bendbennett
Copy link
Contributor

bendbennett commented Aug 9, 2023

There is a related change in the Generate "expand" and "flatten" functions for associated external types PR.

Also relates to the out-of-band discussion we had regarding whether additional flags were going to be used to indicate whether to create specific resources, provider, data_sources, and whether we were going to use flags to allow selective creation of schema, model(s), model helper functions, and expand/flatten functions. I've just added an issue for Consider additional flags for code generation.

Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 23, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants