From 52bd9f9a53f6e63e5fbe0beb1fb2c650d88f7c88 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Mon, 19 May 2025 17:57:58 +0200 Subject: [PATCH] chore(product, modules-sdk): Add missing index for select-in strategy + allow to pass top level strategy to force the behaviour (#12508) **What** - Add missing index for query that falls in select in strategy, specifically the heaviest one with variant IN filtering - Allow to force the strategy to be sent to the entry point module when using the graph API. It is useful with big dataset where filtering is enough without pagination and select in can offer better performances e.g ```ts await query.graph({ entity: 'product', fields, filters, strategy: 'select-in' // <-- this will force the module to use receive this value and apply it accordingly }) ``` --- .changeset/real-beans-provide.md | 7 ++++++ .../remote-query/__tests__/to-remote-query.ts | 22 +++++++++++++++++++ .../modules-sdk/src/remote-query/query.ts | 1 + .../src/remote-query/remote-query.ts | 1 + .../src/remote-query/to-remote-query.ts | 8 +++++++ .../remote-query-object-from-string.ts | 4 ++++ .../migrations/.snapshot-medusa-product.json | 9 ++++++++ .../src/migrations/Migration20250516081326.ts | 13 +++++++++++ .../product/src/models/product-variant.ts | 6 ++++- 9 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 .changeset/real-beans-provide.md create mode 100644 packages/modules/product/src/migrations/Migration20250516081326.ts diff --git a/.changeset/real-beans-provide.md b/.changeset/real-beans-provide.md new file mode 100644 index 0000000000..faae511cfe --- /dev/null +++ b/.changeset/real-beans-provide.md @@ -0,0 +1,7 @@ +--- +"@medusajs/product": patch +"@medusajs/modules-sdk": patch +"@medusajs/types": patch +--- + +chore(product, modules-sdk): Add missing index for select-in strategy + allow to pass top level strategy to force the behaviour diff --git a/packages/core/modules-sdk/src/remote-query/__tests__/to-remote-query.ts b/packages/core/modules-sdk/src/remote-query/__tests__/to-remote-query.ts index 72d643b8e8..b1f0b93db0 100644 --- a/packages/core/modules-sdk/src/remote-query/__tests__/to-remote-query.ts +++ b/packages/core/modules-sdk/src/remote-query/__tests__/to-remote-query.ts @@ -40,6 +40,28 @@ describe("toRemoteQuery", () => { }) }) + it("should transform a query with strategy", () => { + const format = toRemoteQuery( + { + entity: "product", + fields: ["id", "handle", "description"], + strategy: "select-in", + }, + entitiesMap + ) + + expect(format).toEqual({ + product: { + __fields: ["id", "handle", "description"], + __args: { + options: { + strategy: "select-in", + }, + }, + }, + }) + }) + it("should transform a query with pagination", () => { const format = toRemoteQuery( { diff --git a/packages/core/modules-sdk/src/remote-query/query.ts b/packages/core/modules-sdk/src/remote-query/query.ts index 9e28f3a24a..022a2bb050 100644 --- a/packages/core/modules-sdk/src/remote-query/query.ts +++ b/packages/core/modules-sdk/src/remote-query/query.ts @@ -159,6 +159,7 @@ export class Query { queryOptions, this.#remoteQuery.getEntitiesMap() ) + let response: | any[] | { rows: any[]; metadata: RemoteQueryFunctionReturnPagination } diff --git a/packages/core/modules-sdk/src/remote-query/remote-query.ts b/packages/core/modules-sdk/src/remote-query/remote-query.ts index fed1806fe4..a6d8ce8256 100644 --- a/packages/core/modules-sdk/src/remote-query/remote-query.ts +++ b/packages/core/modules-sdk/src/remote-query/remote-query.ts @@ -313,6 +313,7 @@ export class RemoteQuery { "sort", "order", "withDeleted", + "options", ] const availableOptionsAlias = new Map([ ["limit", "take"], diff --git a/packages/core/modules-sdk/src/remote-query/to-remote-query.ts b/packages/core/modules-sdk/src/remote-query/to-remote-query.ts index 1bca5a08ce..061f8a42b3 100644 --- a/packages/core/modules-sdk/src/remote-query/to-remote-query.ts +++ b/packages/core/modules-sdk/src/remote-query/to-remote-query.ts @@ -37,6 +37,7 @@ export function toRemoteQuery( pagination?: Partial["pagination"]> context?: Record withDeleted?: boolean + strategy?: "joined" | "select-in" }, entitiesMap: Map ): RemoteQueryGraph { @@ -46,6 +47,7 @@ export function toRemoteQuery( filters = {}, context = {}, withDeleted, + strategy, } = config const joinerQuery: Record = { @@ -130,6 +132,12 @@ export function toRemoteQuery( } } + if (strategy) { + joinerQuery[entity][ARGUMENTS] ??= {} as any + joinerQuery[entity][ARGUMENTS]["options"] ??= {} as any + joinerQuery[entity][ARGUMENTS]["options"]["strategy"] = strategy + } + if (withDeleted) { joinerQuery[entity][ARGUMENTS] ??= {} as any joinerQuery[entity][ARGUMENTS]["withDeleted"] = true diff --git a/packages/core/types/src/modules-sdk/remote-query-object-from-string.ts b/packages/core/types/src/modules-sdk/remote-query-object-from-string.ts index 58e89ef266..36bbf98022 100644 --- a/packages/core/types/src/modules-sdk/remote-query-object-from-string.ts +++ b/packages/core/types/src/modules-sdk/remote-query-object-from-string.ts @@ -71,6 +71,10 @@ export type RemoteQueryInput = { * Apply a `withDeleted` flag on the retrieved data to retrieve soft deleted items. */ withDeleted?: boolean + /** + * Strategy will be send to the entry module called method + */ + strategy?: "joined" | "select-in" } export type RemoteQueryGraph = { diff --git a/packages/modules/product/src/migrations/.snapshot-medusa-product.json b/packages/modules/product/src/migrations/.snapshot-medusa-product.json index 5fa50e656d..669b52670a 100644 --- a/packages/modules/product/src/migrations/.snapshot-medusa-product.json +++ b/packages/modules/product/src/migrations/.snapshot-medusa-product.json @@ -1582,6 +1582,15 @@ "unique": false, "expression": "CREATE INDEX IF NOT EXISTS \"IDX_product_variant_deleted_at\" ON \"product_variant\" (deleted_at) WHERE deleted_at IS NULL" }, + { + "keyName": "IDX_product_variant_id_product_id", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_product_variant_id_product_id\" ON \"product_variant\" (id, product_id) WHERE deleted_at IS NULL" + }, { "keyName": "IDX_product_variant_sku_unique", "columnNames": [], diff --git a/packages/modules/product/src/migrations/Migration20250516081326.ts b/packages/modules/product/src/migrations/Migration20250516081326.ts new file mode 100644 index 0000000000..175021a659 --- /dev/null +++ b/packages/modules/product/src/migrations/Migration20250516081326.ts @@ -0,0 +1,13 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20250516081326 extends Migration { + + override async up(): Promise { + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_product_variant_id_product_id" ON "product_variant" (id, product_id) WHERE deleted_at IS NULL;`); + } + + override async down(): Promise { + this.addSql(`drop index if exists "IDX_product_variant_id_product_id";`); + } + +} diff --git a/packages/modules/product/src/models/product-variant.ts b/packages/modules/product/src/models/product-variant.ts index 5bd3d832a9..7cd8efb63c 100644 --- a/packages/modules/product/src/models/product-variant.ts +++ b/packages/modules/product/src/models/product-variant.ts @@ -35,10 +35,14 @@ const ProductVariant = model }), }) .indexes([ + { + name: "IDX_product_variant_id_product_id", + on: ["id", "product_id"], + where: "deleted_at IS NULL", + }, { name: "IDX_product_variant_product_id", on: ["product_id"], - unique: false, where: "deleted_at IS NULL", }, {