Related datatype for SingleNestedAttribute from types package

I am using below schema for the resource.

"demo_attribute": schema.SingleNestedAttribute{
	Required: true,
	Description:         "",
	MarkdownDescription: "",
		Attributes: map[string]schema.Attribute{
			"id": schema.StringAttribute{
				Description:         "",
				MarkdownDescription: "",
				Optional:            true,
				Computed:            true,
			},
			"name": schema.StringAttribute{
				Description:         "",
				MarkdownDescription: "",
				Optional:            true,
				Computed:            true,
			},
			"attr1": schema.Int64Attribute{
				Description:         "",
				MarkdownDescription: "",
				Computed:            true,
			},
			"list1": schema.SetAttribute{
				Description:         "",
				MarkdownDescription: "",
				ElementType:         types.StringType,
				Optional:            true,
				Computed:            true,
			},
			"list2": schema.SetAttribute{
				Description:         "",
				MarkdownDescription: "",
				ElementType:         types.StringType,
				Computed:            true,
			},
		},
	},
},

The model structure is as follows:

type DemoResourceModel struct {
	DemoAttribute         ?????   `tfsdk:"demo_attribute"`
}

type Demo struct {
	ID              types.String `tfsdk:"id"`
	Name            types.String `tfsdk:"name"`
	Attr1           types.Int64  `tfsdk:"attr1"`
	List1           types.Set    `tfsdk:"list1"`
	List2	   	    types.Set    `tfsdk:"list2"`
}

What can be the type in struct Demo for DemoAttribute? I can’t use the Demo type since its giving an error while reading the state in ModifyPlan.

Hi @akashgs :wave:

For a SingleNestedAttribute you can use types.Object or basetypes.ObjectValue within the model. The types.Object is an alias to basetypes.ObjectValue.

If you tried using Demo as the type for DemoAttribute within the DemoResourceModel I believe you should have seen an error when executing Terraform, something like:

│ Error: Value Conversion Error
│ 
│ An unexpected error was encountered trying to build a value. This is always an error in the provider. Please report the following to the provider developer:
│ 
│ Received null value, however the target type cannot handle null values. Use the corresponding `types` package type, a pointer type or a custom type that handles null values.
│ 
│ Path: Demo
│ Target Type: provider.Demo
│ Suggested `types` Type: basetypes.ObjectValue
│ Suggested Pointer Type: *provider.Demo

I’d be interested to hear whether you saw an error similar to the one described above.

Hi @bendbennett Yes the error is similar.

Hi @ bendbennett
I’m curious why we can’t use Demo as a type there since in the terraform plugin example it’s exactly what it is used and it works:

// orderResourceModel maps the resource schema data.
type orderResourceModel struct {
    ID          types.String     `tfsdk:"id"`
    Items       []orderItemModel `tfsdk:"items"`
    LastUpdated types.String     `tfsdk:"last_updated"`
}
// orderItemModel maps order item data.
type orderItemModel struct {
    Coffee   orderItemCoffeeModel `tfsdk:"coffee"`
    Quantity types.Int64          `tfsdk:"quantity"`
}
// orderItemCoffeeModel maps coffee order item data.
type orderItemCoffeeModel struct {
    ID          types.Int64   `tfsdk:"id"`
    Name        types.String  `tfsdk:"name"`
    Teaser      types.String  `tfsdk:"teaser"`
    Description types.String  `tfsdk:"description"`
    Price       types.Float64 `tfsdk:"price"`
    Image       types.String  `tfsdk:"image"`
}

But when I build my own provider it does not work, having the error you describe.
Plus, if we use types.Object as a type then we cannot say DemoAttribute.Name as Object does not have the property Name.
So, how we can fix this problem to work correctly referencing the correct type ?

Thanks,
Valentin

Hi @valentino8484 :wave:

If you use types.Object then you should be able to convert into your desired type by using the .As() function on types.Object as illustrated in the docs.

With respect to the hashicups demo, a slice (e.g., []orderItemModel) can be used as internally within the Framework, this can handle null values owing to the reflection rules that are applied. However, if the Hashicups demo used models which were structured as:

// orderResourceModel maps the resource schema data.
type orderResourceModel struct {
	ID          types.String   `tfsdk:"id"`
	Items       orderItemModel `tfsdk:"items"`
	LastUpdated types.String   `tfsdk:"last_updated"`
}

// orderItemModel maps order item data.
type orderItemModel struct {
	Coffee   orderItemCoffeeModel `tfsdk:"coffee"`
	Quantity types.Int64          `tfsdk:"quantity"`
}

With a schema that was defined as:

			"items": schema.SingleNestedAttribute{
				Optional: true,
				Attributes: map[string]schema.Attribute{
					"quantity": schema.Int64Attribute{
						Required: true,
					},
					"coffee": schema.SingleNestedAttribute{
						Required: true,
						Attributes: map[string]schema.Attribute{
							"id": schema.Int64Attribute{
								Required: true,
							},
							"name": schema.StringAttribute{
								Computed: true,
							},
							"teaser": schema.StringAttribute{
								Computed: true,
							},
							"description": schema.StringAttribute{
								Computed: true,
							},
							"price": schema.Float64Attribute{
								Computed: true,
							},
							"image": schema.StringAttribute{
								Computed: true,
							},
						},
					},
				},
			},

And the following Terraform configuration was used:

resource "hashicups_order" "edu" {
}

Running terraform apply would produce the following error:

│ Received null value, however the target type cannot handle null values. Use the corresponding `types` package type, a pointer type or a custom type that handles null values.
│ 
│ Path: items
│ Target Type: provider.orderItemModel
│ Suggested `types` Type: basetypes.ObjectValue
│ Suggested Pointer Type: *provider.orderItemModel