Files
smartmongo/ts/tsmdb/server/handlers/DeleteHandler.ts

116 lines
3.4 KiB
TypeScript
Raw Normal View History

import * as plugins from '../../tsmdb.plugins.js';
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
import type { IStoredDocument } from '../../types/interfaces.js';
import { QueryEngine } from '../../engine/QueryEngine.js';
/**
* DeleteHandler - Handles delete commands
*/
export class DeleteHandler implements ICommandHandler {
async handle(context: IHandlerContext): Promise<plugins.bson.Document> {
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 };
}
const indexEngine = context.getIndexEngine(collection);
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 {
// Try to use index-accelerated query
const candidateIds = await indexEngine.findCandidateIds(filter);
let documents: IStoredDocument[];
if (candidateIds !== null) {
documents = await storage.findByIds(database, collection, candidateIds);
} else {
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);
// Update indexes for deleted documents
for (const doc of docsToDelete) {
await indexEngine.onDelete(doc as any);
}
// 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;
}
}