coffees_data_source.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright (c) HashiCorp, Inc.
  2. // SPDX-License-Identifier: MPL-2.0
  3. package provider
  4. import (
  5. "context"
  6. "fmt"
  7. "github.com/hashicorp-demoapp/hashicups-client-go"
  8. "github.com/hashicorp/terraform-plugin-framework/datasource"
  9. "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
  10. "github.com/hashicorp/terraform-plugin-framework/types"
  11. )
  12. // Ensure the implementation satisfies the expected interfaces.
  13. var (
  14. _ datasource.DataSource = &coffeesDataSource{}
  15. _ datasource.DataSourceWithConfigure = &coffeesDataSource{}
  16. )
  17. func NewCoffeesDataSource() datasource.DataSource {
  18. return &coffeesDataSource{}
  19. }
  20. type coffeesDataSource struct {
  21. client *hashicups.Client
  22. }
  23. func (d *coffeesDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
  24. // Add a nil check when handling ProviderData because Terraform
  25. // sets that data after it calls the ConfigureProvider RPC.
  26. if req.ProviderData == nil {
  27. return
  28. }
  29. client, ok := req.ProviderData.(*hashicups.Client)
  30. if !ok {
  31. resp.Diagnostics.AddError("Unexpected Data Source Configure Type",
  32. fmt.Sprintf("Expected *hashicups.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData))
  33. return
  34. }
  35. d.client = client
  36. }
  37. func (d *coffeesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
  38. resp.TypeName = req.ProviderTypeName + "_coffees"
  39. }
  40. func (d *coffeesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
  41. resp.Schema = schema.Schema{
  42. Attributes: map[string]schema.Attribute{
  43. "coffees": schema.ListNestedAttribute{
  44. Computed: true,
  45. NestedObject: schema.NestedAttributeObject{
  46. Attributes: map[string]schema.Attribute{
  47. "id": schema.Int64Attribute{
  48. Computed: true,
  49. },
  50. "name": schema.StringAttribute{
  51. Computed: true,
  52. },
  53. "teaser": schema.StringAttribute{
  54. Computed: true,
  55. },
  56. "description": schema.StringAttribute{
  57. Computed: true,
  58. },
  59. "price": schema.Float64Attribute{
  60. Computed: true,
  61. },
  62. "image": schema.StringAttribute{
  63. Computed: true,
  64. },
  65. "ingredients": schema.ListNestedAttribute{
  66. Computed: true,
  67. NestedObject: schema.NestedAttributeObject{
  68. Attributes: map[string]schema.Attribute{
  69. "id": schema.Int64Attribute{
  70. Computed: true,
  71. },
  72. },
  73. },
  74. },
  75. },
  76. },
  77. },
  78. },
  79. }
  80. }
  81. // Read is used by the data source to refresh the Terraform state based on the schema data.
  82. func (d *coffeesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
  83. // 1. Reads coffees list. The method invokes the API client's GetCoffees method.
  84. var state coffeesDataSourceModel
  85. coffees, err := d.client.GetCoffees()
  86. if err != nil {
  87. resp.Diagnostics.AddError(
  88. "Unable to Read HashiCups Coffees",
  89. err.Error(),
  90. )
  91. return
  92. }
  93. // 2. Maps response body to schema attributes.
  94. // After the method reads the coffees, it maps the []hashicups.Coffee response
  95. // to coffeesModel so the data source can set the Terraform state.
  96. for _, coffee := range coffees {
  97. coffeeState := coffeesModel{
  98. ID: types.Int64Value(int64(coffee.ID)),
  99. Name: types.StringValue(coffee.Name),
  100. Teaser: types.StringValue(coffee.Teaser),
  101. Description: types.StringValue(coffee.Description),
  102. Price: types.Float64Value(coffee.Price),
  103. Image: types.StringValue(coffee.Image),
  104. Ingredients: make([]coffeeIngredientsModel, 0, len(coffee.Ingredient)), // Not in tutorial, why ?
  105. }
  106. for _, ingredient := range coffee.Ingredient {
  107. coffeeState.Ingredients = append(coffeeState.Ingredients, coffeeIngredientsModel{
  108. ID: types.Int64Value(int64(ingredient.ID)),
  109. })
  110. }
  111. state.Coffees = append(state.Coffees, coffeeState)
  112. }
  113. // 3. Sets state with coffees list.
  114. diags := resp.State.Set(ctx, state)
  115. resp.Diagnostics.Append(diags...)
  116. // Useless code from tutorial, why ?
  117. if resp.Diagnostics.HasError() {
  118. return
  119. }
  120. }
  121. type coffeesDataSourceModel struct {
  122. Coffees []coffeesModel `tfsdk:"coffees"`
  123. }
  124. type coffeesModel struct {
  125. ID types.Int64 `tfsdk:"id"`
  126. Name types.String `tfsdk:"name"`
  127. Teaser types.String `tfsdk:"teaser"`
  128. Description types.String `tfsdk:"description"`
  129. Price types.Float64 `tfsdk:"price"`
  130. Image types.String `tfsdk:"image"`
  131. Ingredients []coffeeIngredientsModel `tfsdk:"ingredients"`
  132. }
  133. type coffeeIngredientsModel struct {
  134. ID types.Int64 `tfsdk:"id"`
  135. }