import * as plugins from '../../congodb.plugins.js'; import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js'; import { QueryEngine } from '../../engine/QueryEngine.js'; /** * DeleteHandler - Handles delete commands */ export class DeleteHandler implements ICommandHandler { async handle(context: IHandlerContext): Promise { const { storage, database, command, documentSequences } = context; const collection = command.delete; if (typeof collection !== 'string') { return { ok: 0, errmsg: 'delete command requires a collection name', code: 2, codeName: 'BadValue', }; } // Get deletes from command or document sequences let deletes: plugins.bson.Document[] = command.deletes || []; // Check for OP_MSG document sequences if (documentSequences && documentSequences.has('deletes')) { deletes = documentSequences.get('deletes')!; } if (!Array.isArray(deletes) || deletes.length === 0) { return { ok: 0, errmsg: 'delete command requires deletes array', code: 2, codeName: 'BadValue', }; } const ordered = command.ordered !== false; const writeErrors: plugins.bson.Document[] = []; let totalDeleted = 0; // Check if collection exists const exists = await storage.collectionExists(database, collection); if (!exists) { // Collection doesn't exist, return success with 0 deleted return { ok: 1, n: 0 }; } for (let i = 0; i < deletes.length; i++) { const deleteSpec = deletes[i]; const filter = deleteSpec.q || deleteSpec.filter || {}; const limit = deleteSpec.limit; // limit: 0 means delete all matching, limit: 1 means delete one const deleteAll = limit === 0; try { // Get all documents const documents = await storage.findAll(database, collection); // Apply filter const matchingDocs = QueryEngine.filter(documents, filter); if (matchingDocs.length === 0) { continue; } // Determine which documents to delete const docsToDelete = deleteAll ? matchingDocs : matchingDocs.slice(0, 1); // Delete the documents const idsToDelete = docsToDelete.map(doc => doc._id); const deleted = await storage.deleteByIds(database, collection, idsToDelete); totalDeleted += deleted; } catch (error: any) { writeErrors.push({ index: i, code: error.code || 1, errmsg: error.message || 'Delete failed', }); if (ordered) { break; } } } const response: plugins.bson.Document = { ok: 1, n: totalDeleted, }; if (writeErrors.length > 0) { response.writeErrors = writeErrors; } return response; } }