How to get list in output

I am testing my provider which is built with plugin framework.

The configuration looks like:

data "tidbcloud_project" "example_project" {
}

output "default_project" {
  value = data.tidbcloud_project.example_project.items
}

The output look like:

default_project = tolist([
  {
    "cluster_count" = 0
    "create_timestamp" = "1649154426"
    "id" = "1372813089191121286"
    "name" = "test1"
    "org_id" = "1372813089189921287"
    "user_count" = 1
  },
  {
    "cluster_count" = 1
    "create_timestamp" = "1640602740"
    "id" = "1372813089189561287"
    "name" = "default project"
    "org_id" = "1372813089189921287"
    "user_count" = 1
  },
])

I use array to accept items in my provider code:

type projectDataSourceData struct {
	Id       types.String `tfsdk:"id"`
	Page     types.Int64  `tfsdk:"page"`
	PageSize types.Int64  `tfsdk:"page_size"`
	Projects []project    `tfsdk:"items"`
	Total    types.Int64  `tfsdk:"total"`
}

Here is my question:
how to get the every element in items? Or I need to change my provider code?

@shiyuhang0, it’s hard to say without seeing your full model structures.

But I would say it’s similar to plugin-framework example on Terraform learn page:

Cheers.

Yes, I just following the plugin-framework example, but find I cannot get every element in the array.

here are my full model structures and schemas:

type projectDataSourceData struct {
	Id       types.String `tfsdk:"id"`
	Page     types.Int64  `tfsdk:"page"`
	PageSize types.Int64  `tfsdk:"page_size"`
	Projects []project    `tfsdk:"items"`
	Total    types.Int64  `tfsdk:"total"`
}

type project struct {
	Id              string `tfsdk:"id"`
	OrgId           string `tfsdk:"org_id"`
	Name            string `tfsdk:"name"`
	ClusterCount    int64  `tfsdk:"cluster_count"`
	UserCount       int64  `tfsdk:"user_count"`
	CreateTimestamp string `tfsdk:"create_timestamp"`
}

func (t projectDataSourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
	return tfsdk.Schema{
		MarkdownDescription: "project data source",
		Attributes: map[string]tfsdk.Attribute{
			"id": {
				MarkdownDescription: "ignore it, it is just for test.",
				Computed:            true,
				Type:                types.StringType,
			},
			"page": {
				MarkdownDescription: "Default:1 The number of pages.",
				Optional:            true,
				Computed:            true,
				Type:                types.Int64Type,
			},
			"page_size": {
				MarkdownDescription: "Default:10 The size of a pages.",
				Optional:            true,
				Computed:            true,
				Type:                types.Int64Type,
			},
			"items": {
				MarkdownDescription: "The items of accessible projects.",
				Computed:            true,
				Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{
					"id": {
						MarkdownDescription: "The ID of the project.",
						Computed:            true,
						Type:                types.StringType,
					},
					"org_id": {
						MarkdownDescription: "The ID of the TiDB Cloud organization to which the project belongs.",
						Computed:            true,
						Type:                types.StringType,
					},
					"name": {
						MarkdownDescription: "The name of the project.",
						Computed:            true,
						Type:                types.StringType,
					},
					"cluster_count": {
						MarkdownDescription: "The number of TiDB Cloud clusters deployed in the project.",
						Computed:            true,
						Type:                types.Int64Type,
					},
					"user_count": {
						MarkdownDescription: "The number of users in the project.",
						Computed:            true,
						Type:                types.Int64Type,
					},
					"create_timestamp": {
						MarkdownDescription: "The creation time of the cluster in Unix timestamp seconds (epoch time).",
						Computed:            true,
						Type:                types.StringType,
					},
				}),
			},
			"total": {
				MarkdownDescription: "The total number of accessible projects.",
				Computed:            true,
				Type:                types.Int64Type,
			},
		},
	}, nil
}

And here is my implement of READ method

func (d projectDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
	var data projectDataSourceData
	diags := req.Config.Get(ctx, &data)
	resp.Diagnostics.Append(diags...)
	if resp.Diagnostics.HasError() {
		return
	}

	// set default value
	if data.Page.IsNull() || data.Page.IsUnknown() {
		data.Page = types.Int64{Value: 1}
	}
	if data.PageSize.IsNull() || data.PageSize.IsUnknown() {
		data.PageSize = types.Int64{Value: 10}
	}

	tflog.Trace(ctx, "read project data source")
	projects, err := d.provider.client.GetAllProjects(data.Page.Value, data.PageSize.Value)
	if err != nil {
		resp.Diagnostics.AddError("Read Error", fmt.Sprintf("Unable to call read project, got error: %s", err))
		return
	}

	data.Total = types.Int64{Value: projects.Total}
	var items []project
	for _, key := range projects.Items {
		items = append(items, project{
			Id:              key.Id,
			OrgId:           key.OrgId,
			Name:            key.Name,
			ClusterCount:    key.ClusterCount,
			UserCount:       key.UserCount,
			CreateTimestamp: key.CreateTimestamp,
		})
	}
	data.Projects = items
	data.Id = types.String{Value: "just for test"}

	diags = resp.State.Set(ctx, &data)
	resp.Diagnostics.Append(diags...)
}

@shiyuhang0, just we’re on the same page. Are you looking how you can access the single element in the output?

If yes, it would be something like that (using index for your list)

output "default_project" {
  value = data.tibdcloud_project.example.project.items[0].id
}

I have tried it but get errors with terraform plan or terraform apply

data "tidbcloud_project" "example" {
}

output "output" {
  value = data.tidbcloud_project.example.items[0].id
}
╷
│ Error: Invalid index
│ 
│   on data-source.tf line 20, in output "output":
│   20:   value = data.tidbcloud_project.example.items[0].id
│ 
│ This value does not have any indices.
╵

It seems that terraform does not think it is a list?