From 3e6f90efe4a0da29e88c0119bdb9b66696572891 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Fri, 3 Apr 2026 14:06:24 -0400 Subject: [PATCH] fix: add regression tests for delete and message update paths Address follow-up review findings: - Add test for deleteObjectFromMeili verifying it uses messageId (not MongoDB _id) when calling index.deleteDocument, guarding against regression of the silent orphaned-document bug. - Add test for message model update path asserting { primaryKey: 'messageId' } is passed to updateDocuments (previously only the conversation model update path was tested). - Add @param config.primaryKey to createMeiliMongooseModel JSDoc. --- .../src/models/plugins/mongoMeili.spec.ts | 40 +++++++++++++++++++ .../src/models/plugins/mongoMeili.ts | 1 + 2 files changed, 41 insertions(+) diff --git a/packages/data-schemas/src/models/plugins/mongoMeili.spec.ts b/packages/data-schemas/src/models/plugins/mongoMeili.spec.ts index 81b9dfbac8..1d341a7939 100644 --- a/packages/data-schemas/src/models/plugins/mongoMeili.spec.ts +++ b/packages/data-schemas/src/models/plugins/mongoMeili.spec.ts @@ -156,6 +156,46 @@ describe('Meilisearch Mongoose plugin', () => { ); }); + test('updating an indexed message calls updateDocuments with primaryKey: messageId', async () => { + const messageModel = createMessageModel(mongoose); + const msg = await messageModel.create({ + messageId: new mongoose.Types.ObjectId().toString(), + conversationId: new mongoose.Types.ObjectId(), + user: new mongoose.Types.ObjectId(), + isCreatedByUser: true, + }); + mockUpdateDocuments.mockClear(); + + msg._meiliIndex = true; + msg.text = 'Updated text'; + await msg.save(); + + expect(mockUpdateDocuments).toHaveBeenCalledWith( + [expect.objectContaining({ messageId: expect.anything() })], + { primaryKey: 'messageId' }, + ); + }); + + test('deleteObjectFromMeili calls deleteDocument with messageId, not _id', async () => { + const messageModel = createMessageModel(mongoose); + const msgId = new mongoose.Types.ObjectId().toString(); + const msg = await messageModel.create({ + messageId: msgId, + conversationId: new mongoose.Types.ObjectId(), + user: new mongoose.Types.ObjectId(), + isCreatedByUser: true, + }); + mockDeleteDocument.mockClear(); + + const typedMsg = msg as unknown as import('./mongoMeili').DocumentWithMeiliIndex; + await new Promise((resolve, reject) => { + typedMsg.deleteObjectFromMeili!((err) => (err ? reject(err) : resolve())); + }); + + expect(mockDeleteDocument).toHaveBeenCalledWith(msgId); + expect(mockDeleteDocument).not.toHaveBeenCalledWith(String(msg._id)); + }); + test('updateDocuments receives preprocessed data with primaryKey', async () => { const conversationModel = createConversationModel(mongoose); const conversationId = 'abc|def|ghi'; diff --git a/packages/data-schemas/src/models/plugins/mongoMeili.ts b/packages/data-schemas/src/models/plugins/mongoMeili.ts index 4692e7d4c7..125e7bab71 100644 --- a/packages/data-schemas/src/models/plugins/mongoMeili.ts +++ b/packages/data-schemas/src/models/plugins/mongoMeili.ts @@ -130,6 +130,7 @@ const processBatch = async ( * @param config - Configuration object. * @param config.index - The MeiliSearch index object. * @param config.attributesToIndex - List of attributes to index. + * @param config.primaryKey - The primary key field for MeiliSearch document operations. * @param config.syncOptions - Sync configuration options. * @returns A class definition that will be loaded into the Mongoose schema. */