Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |-
Expand Down
2 changes: 2 additions & 0 deletions src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export type ResultsWrapper<T> = {

export type IndexOptions = {
primaryKey?: string;
indexUid?: string;
};

export type IndexObject = {
Expand Down Expand Up @@ -408,6 +409,7 @@ export type SearchResponse<
facetDistribution?: FacetDistribution;
facetStats?: FacetStats;
facetsByIndex?: FacetsByIndex;
queryVector?: number[];
} & (undefined extends S
? Partial<FinitePagination & InfinitePagination>
: true extends IsFinitePagination<NonNullable<S>>
Expand Down
40 changes: 40 additions & 0 deletions tests/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Comment on lines 570 to 593
Copy link

@coderabbitai coderabbitai bot Sep 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Test contradiction: asserting non-existence then reading from the same indexes

The test first asserts both original UIDs no longer exist, then immediately fetches documents from those same UIDs. Both cannot be true. With rename: true, UIDs are swapped, not deleted; the original UIDs should remain addressable, with swapped content.

Apply this diff to remove the invalid assertions and clarify the intent:

       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
+      // Verify the indexes are accessible and content has been swapped under the same UIDs
       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);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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);
});
const resolvedTask = await client.swapIndexes(swaps).waitTask();
// Verify the indexes are accessible and content has been swapped under the same UIDs
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);
🤖 Prompt for AI Agents
In tests/client.test.ts around lines 570 to 608, the test incorrectly asserts
that the original UIDs no longer exist then tries to read documents from those
same UIDs; with rename: true the UIDs remain addressable and their contents are
swapped. Remove the two expect(...) checks that assert INDEX_NOT_FOUND for
originalUid1 and originalUid2, keep the document fetches and assertions that
docIndex1.title === "index_2" and docIndex2.title === "index_1", and update the
surrounding comments to state that the UIDs remain and their contents are
swapped rather than deleted.

Copy link
Collaborator

@Strift Strift Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ritinpaul what do you think of this?

I agree with the feedback; the intent is unclear. That being said, the tests are passing

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

});

describe("Test on base routes", () => {
Expand Down
2 changes: 2 additions & 0 deletions tests/get_search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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 () => {
Expand Down
23 changes: 23 additions & 0 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 2 additions & 0 deletions tests/search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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 () => {
Expand Down