diff --git a/.changes/unreleased/Added-20241022-103914.yaml b/.changes/unreleased/Added-20241022-103914.yaml new file mode 100644 index 00000000..61b90a40 --- /dev/null +++ b/.changes/unreleased/Added-20241022-103914.yaml @@ -0,0 +1,3 @@ +kind: Added +body: Added handling of product search and customer search indexes +time: 2024-10-22T10:39:14.745921232+02:00 diff --git a/docs/resources/project_settings.md b/docs/resources/project_settings.md index 1ea72d3e..91db2b91 100644 --- a/docs/resources/project_settings.md +++ b/docs/resources/project_settings.md @@ -53,8 +53,10 @@ resource "commercetools_project_settings" "my-project" { - `carts` (Block List) [Carts Configuration](https://docs.commercetools.com/api/projects/project#carts-configuration) (see [below for nested schema](#nestedblock--carts)) - `countries` (List of String) A two-digit country code as per [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) - `currencies` (List of String) A three-digit currency code as per [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) +- `enable_search_index_customers` (Boolean) Enable the Search Indexing of customers - `enable_search_index_orders` (Boolean) Enable the Search Indexing of orders -- `enable_search_index_products` (Boolean) Enable the Search Indexing of products +- `enable_search_index_product_search` (Boolean) Enable the Search Indexing of products +- `enable_search_index_products` (Boolean) Enable the Search Indexing of product projections - `external_oauth` (Block List) [External OAUTH](https://docs.commercetools.com/api/projects/project#externaloauth) (see [below for nested schema](#nestedblock--external_oauth)) - `languages` (List of String) [IETF Language Tag](https://en.wikipedia.org/wiki/IETF_language_tag) - `messages` (Block List) The change notifications subscribed to (see [below for nested schema](#nestedblock--messages)) diff --git a/internal/resources/project/model.go b/internal/resources/project/model.go index b06638a1..304ef8db 100644 --- a/internal/resources/project/model.go +++ b/internal/resources/project/model.go @@ -26,8 +26,10 @@ type Project struct { Countries []types.String `tfsdk:"countries"` Languages []types.String `tfsdk:"languages"` - EnableSearchIndexProducts types.Bool `tfsdk:"enable_search_index_products"` - EnableSearchIndexOrders types.Bool `tfsdk:"enable_search_index_orders"` + EnableSearchIndexProducts types.Bool `tfsdk:"enable_search_index_products"` + EnableSearchIndexProductSearch types.Bool `tfsdk:"enable_search_index_product_search"` + EnableSearchIndexOrders types.Bool `tfsdk:"enable_search_index_orders"` + EnableSearchIndexCustomers types.Bool `tfsdk:"enable_search_index_customers"` // These items all have maximal one item. We don't use SingleNestedBlock // here since it isn't quite robust currently. @@ -53,8 +55,10 @@ func NewProjectFromNative(n *platform.Project) Project { Countries: pie.Map(n.Countries, types.StringValue), Languages: pie.Map(n.Languages, types.StringValue), - EnableSearchIndexProducts: types.BoolValue(false), - EnableSearchIndexOrders: types.BoolValue(false), + EnableSearchIndexProducts: types.BoolValue(false), + EnableSearchIndexProductSearch: types.BoolValue(false), + EnableSearchIndexOrders: types.BoolValue(false), + EnableSearchIndexCustomers: types.BoolValue(false), Carts: []Carts{ { @@ -101,12 +105,24 @@ func NewProjectFromNative(n *platform.Project) Project { res.EnableSearchIndexProducts = types.BoolValue(enabled) } + if n.SearchIndexing != nil && n.SearchIndexing.ProductsSearch != nil && n.SearchIndexing.ProductsSearch.Status != nil { + status := *n.SearchIndexing.ProductsSearch.Status + enabled := status != platform.SearchIndexingConfigurationStatusDeactivated + res.EnableSearchIndexProductSearch = types.BoolValue(enabled) + } + if n.SearchIndexing != nil && n.SearchIndexing.Orders != nil && n.SearchIndexing.Orders.Status != nil { status := *n.SearchIndexing.Orders.Status enabled := status != platform.SearchIndexingConfigurationStatusDeactivated res.EnableSearchIndexOrders = types.BoolValue(enabled) } + if n.SearchIndexing != nil && n.SearchIndexing.Customers != nil && n.SearchIndexing.Customers.Status != nil { + status := *n.SearchIndexing.Customers.Status + enabled := status != platform.SearchIndexingConfigurationStatusDeactivated + res.EnableSearchIndexCustomers = types.BoolValue(enabled) + } + if n.ExternalOAuth != nil { res.ExternalOAuth = []ExternalOAuth{ { @@ -266,11 +282,37 @@ func (p *Project) updateActions(plan Project) (platform.ProjectUpdate, error) { ) } - // changeProductSearchIndexingEnabled - if !(p.EnableSearchIndexProducts.ValueBool() == plan.EnableSearchIndexProducts.ValueBool()) { + // changeProductSearchIndexingEnabled (ProductProjectionsSearch) + if !p.EnableSearchIndexProducts.Equal(plan.EnableSearchIndexProducts) { + var mode = platform.ProductSearchIndexingModeProductProjectionsSearch result.Actions = append(result.Actions, platform.ProjectChangeProductSearchIndexingEnabledAction{ Enabled: plan.EnableSearchIndexProducts.ValueBool(), + Mode: &mode, + }, + ) + } + + // changeProductSearchIndexingEnabled (ProductsSearch) + if !p.EnableSearchIndexProductSearch.Equal(plan.EnableSearchIndexProductSearch) { + var mode = platform.ProductSearchIndexingModeProductsSearch + result.Actions = append(result.Actions, + platform.ProjectChangeProductSearchIndexingEnabledAction{ + Enabled: plan.EnableSearchIndexProductSearch.ValueBool(), + Mode: &mode, + }, + ) + } + + // changeCustomerSearchStatus + if !p.EnableSearchIndexCustomers.Equal(plan.EnableSearchIndexCustomers) { + status := platform.CustomerSearchStatusDeactivated + if plan.EnableSearchIndexCustomers.ValueBool() { + status = platform.CustomerSearchStatusActivated + } + result.Actions = append(result.Actions, + platform.ProjectChangeCustomerSearchStatusAction{ + Status: status, }, ) } diff --git a/internal/resources/project/model_test.go b/internal/resources/project/model_test.go index d42b1b3d..01261012 100644 --- a/internal/resources/project/model_test.go +++ b/internal/resources/project/model_test.go @@ -32,8 +32,10 @@ func TestNewProjectFromNative(t *testing.T) { Key: types.StringValue("my-project"), Name: types.StringValue("my project"), - EnableSearchIndexProducts: types.BoolValue(false), - EnableSearchIndexOrders: types.BoolValue(false), + EnableSearchIndexProducts: types.BoolValue(false), + EnableSearchIndexOrders: types.BoolValue(false), + EnableSearchIndexCustomers: types.BoolValue(false), + EnableSearchIndexProductSearch: types.BoolValue(false), ExternalOAuth: []ExternalOAuth{}, Carts: []Carts{ @@ -157,17 +159,15 @@ func TestUpdateActions(t *testing.T) { }, }, { - name: "Create with bool unknown", + name: "Update with search index orders activated", state: Project{ - Version: types.Int64Value(1), - EnableSearchIndexOrders: types.BoolValue(false), - EnableSearchIndexProducts: types.BoolValue(false), + Version: types.Int64Value(1), + EnableSearchIndexOrders: types.BoolValue(false), }, plan: Project{ Version: types.Int64Value(1), - EnableSearchIndexOrders: types.BoolValue(true), - EnableSearchIndexProducts: types.BoolUnknown(), + EnableSearchIndexOrders: types.BoolValue(true), }, action: platform.ProjectUpdate{ Version: 1, @@ -176,6 +176,167 @@ func TestUpdateActions(t *testing.T) { }, }, }, + { + name: "Update with search index orders deactivated", + state: Project{ + Version: types.Int64Value(1), + EnableSearchIndexOrders: types.BoolValue(true), + }, + plan: Project{ + Version: types.Int64Value(1), + EnableSearchIndexOrders: types.BoolValue(false), + }, + action: platform.ProjectUpdate{ + Version: 1, + Actions: []platform.ProjectUpdateAction{ + platform.ProjectChangeOrderSearchStatusAction{Status: platform.OrderSearchStatusDeactivated}, + }, + }, + }, + { + name: "Update with search index orders no changes", + state: Project{ + Version: types.Int64Value(1), + EnableSearchIndexOrders: types.BoolValue(false), + }, + plan: Project{ + Version: types.Int64Value(1), + EnableSearchIndexOrders: types.BoolValue(false), + }, + action: platform.ProjectUpdate{ + Version: 1, + Actions: []platform.ProjectUpdateAction{}, + }, + }, + { + name: "Update with search index customers activated", + state: Project{ + Version: types.Int64Value(1), + EnableSearchIndexCustomers: types.BoolValue(false), + }, + plan: Project{ + Version: types.Int64Value(1), + EnableSearchIndexCustomers: types.BoolValue(true), + }, + action: platform.ProjectUpdate{ + Version: 1, + Actions: []platform.ProjectUpdateAction{ + platform.ProjectChangeCustomerSearchStatusAction{Status: platform.CustomerSearchStatusActivated}, + }, + }, + }, + { + name: "Update with search index customers deactivated", + state: Project{ + Version: types.Int64Value(1), + EnableSearchIndexCustomers: types.BoolValue(true), + }, + plan: Project{ + Version: types.Int64Value(1), + EnableSearchIndexCustomers: types.BoolValue(false), + }, + action: platform.ProjectUpdate{ + Version: 1, + Actions: []platform.ProjectUpdateAction{ + platform.ProjectChangeCustomerSearchStatusAction{Status: platform.CustomerSearchStatusDeactivated}, + }, + }, + }, + { + name: "Update with search index customers no changes", + state: Project{ + Version: types.Int64Value(1), + EnableSearchIndexCustomers: types.BoolValue(false), + }, + plan: Project{ + Version: types.Int64Value(1), + EnableSearchIndexCustomers: types.BoolValue(false), + }, + action: platform.ProjectUpdate{ + Version: 1, + Actions: []platform.ProjectUpdateAction{}, + }, + }, + { + name: "Update with search index products activated", + state: Project{ + Version: types.Int64Value(1), + EnableSearchIndexProducts: types.BoolValue(false), + }, + plan: Project{ + Version: types.Int64Value(1), + EnableSearchIndexProducts: types.BoolValue(true), + }, + action: platform.ProjectUpdate{ + Version: 1, + Actions: []platform.ProjectUpdateAction{ + platform.ProjectChangeProductSearchIndexingEnabledAction{ + Enabled: true, + Mode: utils.GetRef(platform.ProductSearchIndexingModeProductProjectionsSearch), + }, + }, + }, + }, + { + name: "Update with search index products deactivated", + state: Project{ + Version: types.Int64Value(1), + EnableSearchIndexProducts: types.BoolValue(true), + }, + plan: Project{ + Version: types.Int64Value(1), + EnableSearchIndexProducts: types.BoolValue(false), + }, + action: platform.ProjectUpdate{ + Version: 1, + Actions: []platform.ProjectUpdateAction{ + platform.ProjectChangeProductSearchIndexingEnabledAction{ + Enabled: false, + Mode: utils.GetRef(platform.ProductSearchIndexingModeProductProjectionsSearch), + }, + }, + }, + }, + { + name: "Update with search index product search activated", + state: Project{ + Version: types.Int64Value(1), + EnableSearchIndexProductSearch: types.BoolValue(false), + }, + plan: Project{ + Version: types.Int64Value(1), + EnableSearchIndexProductSearch: types.BoolValue(true), + }, + action: platform.ProjectUpdate{ + Version: 1, + Actions: []platform.ProjectUpdateAction{ + platform.ProjectChangeProductSearchIndexingEnabledAction{ + Enabled: true, + Mode: utils.GetRef(platform.ProductSearchIndexingModeProductsSearch), + }, + }, + }, + }, + { + name: "Update with search index product search deactivated", + state: Project{ + Version: types.Int64Value(1), + EnableSearchIndexProductSearch: types.BoolValue(true), + }, + plan: Project{ + Version: types.Int64Value(1), + EnableSearchIndexProductSearch: types.BoolValue(false), + }, + action: platform.ProjectUpdate{ + Version: 1, + Actions: []platform.ProjectUpdateAction{ + platform.ProjectChangeProductSearchIndexingEnabledAction{ + Enabled: false, + Mode: utils.GetRef(platform.ProductSearchIndexingModeProductsSearch), + }, + }, + }, + }, { name: "Create with business unit settings", state: Project{ diff --git a/internal/resources/project/resource.go b/internal/resources/project/resource.go index 03465a59..6d2f1a58 100644 --- a/internal/resources/project/resource.go +++ b/internal/resources/project/resource.go @@ -2,6 +2,7 @@ package project import ( "context" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "time" @@ -18,7 +19,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" - sdk_resource "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + sdkresource "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/labd/commercetools-go-sdk/platform" "github.com/labd/terraform-provider-commercetools/internal/customtypes" @@ -114,20 +115,28 @@ func (r *projectResource) Schema(_ context.Context, _ resource.SchemaRequest, re }, }, "enable_search_index_products": schema.BoolAttribute{ + MarkdownDescription: "Enable the Search Indexing of product projections", + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "enable_search_index_product_search": schema.BoolAttribute{ MarkdownDescription: "Enable the Search Indexing of products", Optional: true, Computed: true, - PlanModifiers: []planmodifier.Bool{ - boolplanmodifier.UseStateForUnknown(), - }, + Default: booldefault.StaticBool(false), }, "enable_search_index_orders": schema.BoolAttribute{ MarkdownDescription: "Enable the Search Indexing of orders", Optional: true, Computed: true, - PlanModifiers: []planmodifier.Bool{ - boolplanmodifier.UseStateForUnknown(), - }, + Default: booldefault.StaticBool(false), + }, + "enable_search_index_customers": schema.BoolAttribute{ + MarkdownDescription: "Enable the Search Indexing of customers", + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), }, "shipping_rate_input_type": schema.StringAttribute{ MarkdownDescription: "Three ways to dynamically select a ShippingRatePriceTier exist. The CartValue type uses " + @@ -327,7 +336,7 @@ func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest } var res *platform.Project - err = sdk_resource.RetryContext(ctx, 5*time.Second, func() *sdk_resource.RetryError { + err = sdkresource.RetryContext(ctx, 5*time.Second, func() *sdkresource.RetryError { var err error res, err = r.client.Post(input).Execute(ctx) return utils.ProcessRemoteError(err) @@ -402,7 +411,7 @@ func (r *projectResource) Update(ctx context.Context, req resource.UpdateRequest } var res *platform.Project - err = sdk_resource.RetryContext(ctx, 5*time.Second, func() *sdk_resource.RetryError { + err = sdkresource.RetryContext(ctx, 5*time.Second, func() *sdkresource.RetryError { var err error res, err = r.client.Post(input).Execute(ctx) return utils.ProcessRemoteError(err) diff --git a/internal/resources/project/resource_test.go b/internal/resources/project/resource_test.go index 3b975f93..d11370ce 100644 --- a/internal/resources/project/resource_test.go +++ b/internal/resources/project/resource_test.go @@ -32,6 +32,10 @@ func TestAccProjectCreate_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "messages.#", "1"), resource.TestCheckResourceAttr(resourceName, "messages.0.enabled", "true"), resource.TestCheckResourceAttr(resourceName, "external_oauth.#", "1"), + resource.TestCheckResourceAttr(resourceName, "enable_search_index_orders", "false"), + resource.TestCheckResourceAttr(resourceName, "enable_search_index_customers", "false"), + resource.TestCheckResourceAttr(resourceName, "enable_search_index_products", "false"), + resource.TestCheckResourceAttr(resourceName, "enable_search_index_product_search", "false"), resource.TestCheckResourceAttr( resourceName, "external_oauth.0.authorization_header", "Bearer secret"), resource.TestCheckResourceAttr( @@ -88,6 +92,10 @@ func TestAccProjectCreate_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "languages.#", "5"), resource.TestCheckResourceAttr(resourceName, "messages.0.enabled", "false"), resource.TestCheckResourceAttr(resourceName, "messages.0.delete_days_after_creation", "15"), + resource.TestCheckResourceAttr(resourceName, "enable_search_index_orders", "true"), + resource.TestCheckResourceAttr(resourceName, "enable_search_index_customers", "true"), + resource.TestCheckResourceAttr(resourceName, "enable_search_index_products", "true"), + resource.TestCheckResourceAttr(resourceName, "enable_search_index_product_search", "true"), resource.TestCheckResourceAttr( resourceName, "external_oauth.0.url", "https://new-example.com/oauth/token"), resource.TestCheckResourceAttr( @@ -237,8 +245,10 @@ func testAccProjectConfigUpdate(identifier string) string { delete_days_after_last_modification = 21 } - enable_search_index_products = true - enable_search_index_orders = true + enable_search_index_orders = true + enable_search_index_customers = true + enable_search_index_products = true + enable_search_index_product_search = true shipping_rate_input_type = "CartClassification" shipping_rate_cart_classification_value { diff --git a/internal/resources/project/upgrade_v1.go b/internal/resources/project/upgrade_v1.go index de1eca6f..2b7c729f 100644 --- a/internal/resources/project/upgrade_v1.go +++ b/internal/resources/project/upgrade_v1.go @@ -63,8 +63,10 @@ var ProjectResourceDataV1 = tftypes.Object{ "countries": tftypes.List{ElementType: tftypes.String}, "languages": tftypes.List{ElementType: tftypes.String}, - "enable_search_index_products": tftypes.Bool, - "enable_search_index_orders": tftypes.Bool, + "enable_search_index_products": tftypes.Bool, + "enable_search_index_product_search": tftypes.Bool, + "enable_search_index_orders": tftypes.Bool, + "enable_search_index_customers": tftypes.Bool, "carts": tftypes.List{ ElementType: tftypes.Object{ @@ -154,9 +156,11 @@ func upgradeStateV0(ctx context.Context, req resource.UpgradeStateRequest, resp "shipping_rate_cart_classification_value": rawState["shipping_rate_cart_classification_value"], // Values that didn't exist yet - "enable_search_index_products": tftypes.NewValue(tftypes.Bool, tftypes.UnknownValue), - "enable_search_index_orders": tftypes.NewValue(tftypes.Bool, tftypes.UnknownValue), - "business_units": valueToList(nil, "business_units"), + "enable_search_index_products": tftypes.NewValue(tftypes.Bool, tftypes.UnknownValue), + "enable_search_index_product_search": tftypes.NewValue(tftypes.Bool, tftypes.UnknownValue), + "enable_search_index_orders": tftypes.NewValue(tftypes.Bool, tftypes.UnknownValue), + "enable_search_index_customers": tftypes.NewValue(tftypes.Bool, tftypes.UnknownValue), + "business_units": valueToList(nil, "business_units"), }), ) if err != nil { diff --git a/internal/resources/project/upgrade_v1_test.go b/internal/resources/project/upgrade_v1_test.go index 4243cda2..57315c77 100644 --- a/internal/resources/project/upgrade_v1_test.go +++ b/internal/resources/project/upgrade_v1_test.go @@ -63,9 +63,11 @@ func Test_upgradeStateV0(t *testing.T) { Countries: []types.String{}, Languages: []types.String{types.StringValue("nl")}, - EnableSearchIndexProducts: types.BoolUnknown(), - EnableSearchIndexOrders: types.BoolUnknown(), - BusinessUnits: []BusinessUnits{}, + EnableSearchIndexProducts: types.BoolUnknown(), + EnableSearchIndexProductSearch: types.BoolUnknown(), + EnableSearchIndexOrders: types.BoolUnknown(), + EnableSearchIndexCustomers: types.BoolUnknown(), + BusinessUnits: []BusinessUnits{}, ExternalOAuth: []ExternalOAuth{}, Carts: []Carts{ diff --git a/internal/utils/value.go b/internal/utils/value.go new file mode 100644 index 00000000..b99a7657 --- /dev/null +++ b/internal/utils/value.go @@ -0,0 +1,6 @@ +package utils + +// GetRef gets the reference of value with generic type +func GetRef[T any](value T) *T { + return &value +}