feat(medusa): Rollout index engine behind feature flag (#11431)

**What**
- Add index engine feature flag
- apply it to the `store/products` end point as well as `admin/products`
- Query builder various fixes
- search capabilities on full data of every entities. The `q` search will be applied to all involved joined table for selection/where clauses

Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com>
This commit is contained in:
Adrien de Peretti
2025-02-18 13:49:57 +00:00
committed by GitHub
co-authored by Carlos R. L. Rodrigues
parent 3b69f5a105
commit 448dbcb596
27 changed files with 881 additions and 135 deletions
@@ -2,6 +2,8 @@ export const schema = `
type Product @Listeners(values: ["product.created", "product.updated", "product.deleted"]) {
id: String
title: String
created_at: DateTime
deep: InternalNested
variants: [ProductVariant]
}
@@ -133,7 +133,7 @@ describe("IndexModuleService syncIndexConfig", function () {
afterEach(afterEach_)
it("should full sync all entities when the config has changed", async () => {
it.only("should full sync all entities when the config has changed", async () => {
await setTimeout(1000)
const currentMetadata = await indexMetadataService.list()
@@ -148,7 +148,7 @@ describe("IndexModuleService syncIndexConfig", function () {
}),
expect.objectContaining({
entity: "Product",
fields: "id,title",
fields: "created_at,id,title",
status: "done",
}),
expect.objectContaining({
@@ -199,7 +199,7 @@ describe("DataSynchronizer", () => {
filters: {
id: [testProductId],
},
fields: ["id", "title"],
fields: ["id", "created_at", "title"],
})
// Second loop fetching products
@@ -225,7 +225,7 @@ describe("DataSynchronizer", () => {
filters: {
id: [testProductId2],
},
fields: ["id", "title"],
fields: ["id", "created_at", "title"],
})
expect(ackMock).toHaveBeenNthCalledWith(1, {
@@ -30,29 +30,34 @@ const dbUtils = TestDatabaseUtils.dbTestUtilFactory()
jest.setTimeout(300000)
const productId = "prod_1"
const productId2 = "prod_2"
const variantId = "var_1"
const variantId2 = "var_2"
const priceSetId = "price_set_1"
const priceId = "money_amount_1"
const linkId = "link_id_1"
const sendEvents = async (eventDataToEmit) => {
let a = 0
let productCounter = 0
let variantCounter = 0
queryMock.graph = jest.fn().mockImplementation((query) => {
const entity = query.entity
if (entity === "product") {
return {
data: {
id: a++ > 0 ? "aaaa" : productId,
id: productCounter++ > 0 ? productId2 : productId,
title: "Test Product " + productCounter,
},
}
} else if (entity === "product_variant") {
const counter = variantCounter++
return {
data: {
id: variantId,
id: counter > 0 ? variantId2 : variantId,
sku: "aaa test aaa",
product: {
id: productId,
id: counter > 0 ? productId2 : productId,
},
},
}
@@ -374,7 +379,16 @@ describe("IndexModuleService", function () {
{
name: "product.created",
data: {
id: "PRODUCTASDASDAS",
id: productId2,
},
},
{
name: "variant.created",
data: {
id: variantId2,
product: {
id: productId2,
},
},
},
{
@@ -426,14 +440,46 @@ describe("IndexModuleService", function () {
})
expect(productIndexEntries).toHaveLength(2)
expect(productIndexEntries[0].id).toEqual(productId)
expect(productIndexEntries).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: productId,
data: expect.objectContaining({
id: productId,
title: expect.stringContaining("Test Product"),
}),
}),
expect.objectContaining({
id: productId2,
data: expect.objectContaining({
id: productId2,
title: expect.stringContaining("Test Product"),
}),
}),
])
)
const variantIndexEntries = indexEntries.filter((entry) => {
return entry.name === "ProductVariant"
})
expect(variantIndexEntries).toHaveLength(1)
expect(variantIndexEntries[0].id).toEqual(variantId)
expect(variantIndexEntries).toHaveLength(2)
expect(variantIndexEntries).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: variantId,
data: expect.objectContaining({
id: variantId,
}),
}),
expect.objectContaining({
id: variantId2,
data: expect.objectContaining({
id: variantId2,
}),
}),
])
)
const priceSetIndexEntries = indexEntries.filter((entry) => {
return entry.name === "PriceSet"
@@ -461,7 +507,7 @@ describe("IndexModuleService", function () {
{}
)
expect(indexRelationEntries).toHaveLength(4)
expect(indexRelationEntries).toHaveLength(5)
const productVariantIndexRelationEntries = indexRelationEntries.filter(
(entry) => {
@@ -414,7 +414,19 @@ describe("IndexModuleService query", function () {
},
})
// NULLS LAST (DESC = first)
expect(data).toEqual([
{
id: "prod_2",
title: "Product 2 title",
deep: {
a: 1,
obj: {
b: 15,
},
},
variants: [],
},
{
id: "prod_1",
variants: [
@@ -440,17 +452,6 @@ describe("IndexModuleService query", function () {
},
],
},
{
id: "prod_2",
title: "Product 2 title",
deep: {
a: 1,
obj: {
b: 15,
},
},
variants: [],
},
])
const { data: dataAsc } = await module.query({
@@ -469,17 +470,6 @@ describe("IndexModuleService query", function () {
})
expect(dataAsc).toEqual([
{
id: "prod_2",
title: "Product 2 title",
deep: {
a: 1,
obj: {
b: 15,
},
},
variants: [],
},
{
id: "prod_1",
variants: [
@@ -505,6 +495,17 @@ describe("IndexModuleService query", function () {
},
],
},
{
id: "prod_2",
title: "Product 2 title",
deep: {
a: 1,
obj: {
b: 15,
},
},
variants: [],
},
])
})
@@ -565,6 +566,11 @@ describe("IndexModuleService query", function () {
pagination: {
take: 100,
skip: 0,
order: {
product: {
created_at: "ASC",
},
},
},
})
@@ -596,7 +602,7 @@ describe("IndexModuleService query", function () {
product: {
variants: {
prices: {
amount: "DESC",
amount: "ASC",
},
},
},
@@ -608,14 +614,14 @@ describe("IndexModuleService query", function () {
{
id: "prod_1",
variants: [
{
id: "var_1",
sku: "aaa test aaa",
},
{
id: "var_2",
sku: "sku 123",
},
{
id: "var_1",
sku: "aaa test aaa",
},
],
},
{