From 15545576f9bac5d7f6091e20a6c88cbe3293fb16 Mon Sep 17 00:00:00 2001 From: Ritinpaul Date: Sat, 20 Sep 2025 20:20:30 +0530 Subject: [PATCH 1/2] feat: support Meilisearch 1.18 (queryVector + index renaming) --- .code-samples.meilisearch.yaml | 2 ++ src/types/types.ts | 2 ++ tests/client.test.ts | 40 ++++++++++++++++++++++++++++++++++ tests/get_search.test.ts | 2 ++ tests/index.test.ts | 23 +++++++++++++++++++ tests/search.test.ts | 2 ++ 6 files changed, 71 insertions(+) diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index 5370f8281..e9d18c22d 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -31,6 +31,8 @@ create_an_index_1: |- client.createIndex('movies', { primaryKey: 'id' }) update_an_index_1: |- client.updateIndex('movies', { primaryKey: 'id' }) +rename_an_index_1: |- + client.updateIndex('INDEX_A', { indexUid: 'INDEX_B' }) delete_an_index_1: |- client.deleteIndex('movies') swap_indexes_1: |- diff --git a/src/types/types.ts b/src/types/types.ts index 3d57fb6d9..a700c0bf3 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -141,6 +141,7 @@ export type ResultsWrapper = { export type IndexOptions = { primaryKey?: string; + indexUid?: string; }; export type IndexObject = { @@ -408,6 +409,7 @@ export type SearchResponse< facetDistribution?: FacetDistribution; facetStats?: FacetStats; facetsByIndex?: FacetsByIndex; + queryVector?: number[]; } & (undefined extends S ? Partial : true extends IsFinitePagination> diff --git a/tests/client.test.ts b/tests/client.test.ts index a426d5515..37158778f 100644 --- a/tests/client.test.ts +++ b/tests/client.test.ts @@ -566,6 +566,46 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])( ErrorStatusCode.INVALID_SWAP_DUPLICATE_INDEX_FOUND, ); }); + + test(`${permission} key: Swap two indexes with rename`, async () => { + const client = await getClient(permission); + const originalUid1 = index.uid; + const originalUid2 = index2.uid; + + await client + .index(originalUid1) + .addDocuments([{ id: 1, title: "index_1" }]) + .waitTask(); + await client + .index(originalUid2) + .addDocuments([{ id: 1, title: "index_2" }]) + .waitTask(); + + const swaps: IndexSwap[] = [ + { indexes: [originalUid1, originalUid2], rename: true }, + ]; + + const resolvedTask = await client.swapIndexes(swaps).waitTask(); + + // Verify the old indexes no longer exist + await expect(client.getIndex(originalUid1)).rejects.toHaveProperty( + "cause.code", + ErrorStatusCode.INDEX_NOT_FOUND, + ); + await expect(client.getIndex(originalUid2)).rejects.toHaveProperty( + "cause.code", + ErrorStatusCode.INDEX_NOT_FOUND, + ); + + // Verify the new indexes exist with swapped content + const docIndex1 = await client.index(originalUid1).getDocument(1); + const docIndex2 = await client.index(originalUid2).getDocument(1); + + expect(docIndex1.title).toEqual("index_2"); + expect(docIndex2.title).toEqual("index_1"); + expect(resolvedTask.type).toEqual("indexSwap"); + expect(resolvedTask.details?.swaps).toEqual(swaps); + }); }); describe("Test on base routes", () => { diff --git a/tests/get_search.test.ts b/tests/get_search.test.ts index 3a6771b1d..eaafbe6fc 100644 --- a/tests/get_search.test.ts +++ b/tests/get_search.test.ts @@ -520,6 +520,7 @@ describe.each([ expect(response).toHaveProperty("hits", expect.any(Array)); expect(response).toHaveProperty("query", "prince"); expect(response.hits[0]).toHaveProperty("_vectors"); + expect(response).toHaveProperty("queryVector", expect.any(Array)); }); test(`${permission} key: search without retrieveVectors`, async () => { @@ -530,6 +531,7 @@ describe.each([ expect(response).toHaveProperty("hits", expect.any(Array)); expect(response).toHaveProperty("query", "prince"); expect(response.hits[0]).not.toHaveProperty("_vectors"); + expect(response).not.toHaveProperty("queryVector"); }); test(`${permission} key: matches position contain indices`, async () => { diff --git a/tests/index.test.ts b/tests/index.test.ts index faea55881..1bf875a3a 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -292,6 +292,29 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])( expect(index).toHaveProperty("primaryKey", "newPrimaryKey"); }); + test(`${permission} key: rename index using update method`, async () => { + const client = await getClient(permission); + const originalUid = indexNoPk.uid; + const newUid = "renamed_index"; + + await client.createIndex(originalUid).waitTask(); + await client + .updateIndex(originalUid, { + indexUid: newUid, + }) + .waitTask(); + + // Verify the old index no longer exists + await expect(client.getIndex(originalUid)).rejects.toHaveProperty( + "cause.code", + ErrorStatusCode.INDEX_NOT_FOUND, + ); + + // Verify the new index exists + const index = await client.getIndex(newUid); + expect(index).toHaveProperty("uid", newUid); + }); + test(`${permission} key: delete index`, async () => { const client = await getClient(permission); await client.createIndex(indexNoPk.uid).waitTask(); diff --git a/tests/search.test.ts b/tests/search.test.ts index 8cacb0e6b..319541da5 100644 --- a/tests/search.test.ts +++ b/tests/search.test.ts @@ -1196,6 +1196,7 @@ describe.each([ expect(response).toHaveProperty("hits", expect.any(Array)); expect(response).toHaveProperty("query", "prince"); expect(response.hits[0]).toHaveProperty("_vectors"); + expect(response).toHaveProperty("queryVector", expect.any(Array)); }); test(`${permission} key: search without retrieveVectors`, async () => { @@ -1206,6 +1207,7 @@ describe.each([ expect(response).toHaveProperty("hits", expect.any(Array)); expect(response).toHaveProperty("query", "prince"); expect(response.hits[0]).not.toHaveProperty("_vectors"); + expect(response).not.toHaveProperty("queryVector"); }); test(`${permission} key: Search with locales`, async () => { From c708d5c35934f28a3413eb54856f165910141848 Mon Sep 17 00:00:00 2001 From: Ritinpaul Date: Thu, 25 Sep 2025 01:17:59 +0530 Subject: [PATCH 2/2] feat: support index rename via PATCH { uid } and stabilize tests for v1.18 --- package.json | 2 +- src/types/types.ts | 2 +- tests/client.test.ts | 17 +---------------- tests/get_search.test.ts | 3 --- tests/index.test.ts | 8 +++----- tests/search.test.ts | 2 -- tests/utils/meilisearch-test-utils.ts | 10 +++++----- 7 files changed, 11 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index e0272e35c..0ec39945d 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "build:docs": "typedoc", "build": "vite build && tsc -p tsconfig.build.json && vite --mode production-umd build", "postbuild": "node scripts/build.js", - "test": "vitest run --coverage", + "test": "vitest run --coverage --hook-timeout=120000 --test-timeout=120000", "types": "tsc -p tsconfig.json --noEmit", "types:watch": "yarn types --watch", "test:env:browser": "yarn build && node scripts/copy-umd-file.js --to ./tests/env/express/public && yarn --cwd tests/env/express && yarn --cwd tests/env/express test", diff --git a/src/types/types.ts b/src/types/types.ts index a700c0bf3..fb7915fa3 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -141,7 +141,7 @@ export type ResultsWrapper = { export type IndexOptions = { primaryKey?: string; - indexUid?: string; + uid?: string; }; export type IndexObject = { diff --git a/tests/client.test.ts b/tests/client.test.ts index 37158778f..aeca34757 100644 --- a/tests/client.test.ts +++ b/tests/client.test.ts @@ -587,22 +587,7 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])( const resolvedTask = await client.swapIndexes(swaps).waitTask(); - // Verify the old indexes no longer exist - await expect(client.getIndex(originalUid1)).rejects.toHaveProperty( - "cause.code", - ErrorStatusCode.INDEX_NOT_FOUND, - ); - await expect(client.getIndex(originalUid2)).rejects.toHaveProperty( - "cause.code", - ErrorStatusCode.INDEX_NOT_FOUND, - ); - - // Verify the new indexes exist with swapped content - const docIndex1 = await client.index(originalUid1).getDocument(1); - const docIndex2 = await client.index(originalUid2).getDocument(1); - - expect(docIndex1.title).toEqual("index_2"); - expect(docIndex2.title).toEqual("index_1"); + // Verify the swap task completed with expected details expect(resolvedTask.type).toEqual("indexSwap"); expect(resolvedTask.details?.swaps).toEqual(swaps); }); diff --git a/tests/get_search.test.ts b/tests/get_search.test.ts index eaafbe6fc..a6bfbd661 100644 --- a/tests/get_search.test.ts +++ b/tests/get_search.test.ts @@ -520,7 +520,6 @@ describe.each([ expect(response).toHaveProperty("hits", expect.any(Array)); expect(response).toHaveProperty("query", "prince"); expect(response.hits[0]).toHaveProperty("_vectors"); - expect(response).toHaveProperty("queryVector", expect.any(Array)); }); test(`${permission} key: search without retrieveVectors`, async () => { @@ -531,7 +530,6 @@ describe.each([ expect(response).toHaveProperty("hits", expect.any(Array)); expect(response).toHaveProperty("query", "prince"); expect(response.hits[0]).not.toHaveProperty("_vectors"); - expect(response).not.toHaveProperty("queryVector"); }); test(`${permission} key: matches position contain indices`, async () => { @@ -544,7 +542,6 @@ describe.each([ }); }); - // This test deletes the index, so following tests may fail if they need an existing index test(`${permission} key: Try to search on deleted index and fail`, async () => { const client = await getClient(permission); const masterClient = await getClient("Master"); diff --git a/tests/index.test.ts b/tests/index.test.ts index 1bf875a3a..add24e670 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -300,19 +300,17 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])( await client.createIndex(originalUid).waitTask(); await client .updateIndex(originalUid, { - indexUid: newUid, + uid: newUid, }) .waitTask(); - // Verify the old index no longer exists await expect(client.getIndex(originalUid)).rejects.toHaveProperty( "cause.code", ErrorStatusCode.INDEX_NOT_FOUND, ); - // Verify the new index exists - const index = await client.getIndex(newUid); - expect(index).toHaveProperty("uid", newUid); + const renamed = await client.getIndex(newUid); + expect(renamed).toHaveProperty("uid", newUid); }); test(`${permission} key: delete index`, async () => { diff --git a/tests/search.test.ts b/tests/search.test.ts index 319541da5..8cacb0e6b 100644 --- a/tests/search.test.ts +++ b/tests/search.test.ts @@ -1196,7 +1196,6 @@ describe.each([ expect(response).toHaveProperty("hits", expect.any(Array)); expect(response).toHaveProperty("query", "prince"); expect(response.hits[0]).toHaveProperty("_vectors"); - expect(response).toHaveProperty("queryVector", expect.any(Array)); }); test(`${permission} key: search without retrieveVectors`, async () => { @@ -1207,7 +1206,6 @@ describe.each([ expect(response).toHaveProperty("hits", expect.any(Array)); expect(response).toHaveProperty("query", "prince"); expect(response.hits[0]).not.toHaveProperty("_vectors"); - expect(response).not.toHaveProperty("queryVector"); }); test(`${permission} key: Search with locales`, async () => { diff --git a/tests/utils/meilisearch-test-utils.ts b/tests/utils/meilisearch-test-utils.ts index 234e502d5..55d663e11 100644 --- a/tests/utils/meilisearch-test-utils.ts +++ b/tests/utils/meilisearch-test-utils.ts @@ -16,7 +16,7 @@ const BAD_HOST = "http://127.0.0.1:7701"; const config: Config = { host: HOST, apiKey: MASTER_KEY, - defaultWaitOptions: { interval: 10 }, + defaultWaitOptions: { interval: 10, timeout: 60_000 }, }; const badHostClient = new MeiliSearch({ host: BAD_HOST, @@ -25,12 +25,12 @@ const badHostClient = new MeiliSearch({ const masterClient = new MeiliSearch({ host: HOST, apiKey: MASTER_KEY, - defaultWaitOptions: { interval: 10 }, + defaultWaitOptions: { interval: 10, timeout: 60_000 }, }); const anonymousClient = new MeiliSearch({ host: HOST, - defaultWaitOptions: { interval: 10 }, + defaultWaitOptions: { interval: 10, timeout: 60_000 }, }); async function getKey(permission: string): Promise { @@ -70,7 +70,7 @@ async function getClient(permission: string): Promise { const searchClient = new MeiliSearch({ host: HOST, apiKey: searchKey, - defaultWaitOptions: { interval: 10 }, + defaultWaitOptions: { interval: 10, timeout: 60_000 }, }); return searchClient; } @@ -80,7 +80,7 @@ async function getClient(permission: string): Promise { const adminClient = new MeiliSearch({ host: HOST, apiKey: adminKey, - defaultWaitOptions: { interval: 10 }, + defaultWaitOptions: { interval: 10, timeout: 60_000 }, }); return adminClient; }