opusdev/vector-similarity-api
1
1import type { Document } from '../bson';2import { type Connection } from '../cmap/connection';3import { MongoDBResponse } from '../cmap/wire_protocol/responses';4import { MongoCompatibilityError, MongoServerError } from '../error';5import type { ClientSession } from '../sessions';6import { maxWireVersion, type MongoDBCollectionNamespace, type MongoDBNamespace } from '../utils';7import { type WriteConcernOptions } from '../write_concern';8import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command';9import { Aspect, defineAspects, type Hint } from './operation';10 11/** @public */12export interface DeleteOptions extends CommandOperationOptions, WriteConcernOptions {13 /** If true, when an insert fails, don't execute the remaining writes. If false, continue with remaining inserts when one fails. */14 ordered?: boolean;15 /** Specifies the collation to use for the operation */16 collation?: CollationOptions;17 /** Specify that the update query should only consider plans using the hinted index */18 hint?: string | Document;19 /** Map of parameter names and values that can be accessed using $$var (requires MongoDB 5.0). */20 let?: Document;21}22 23/** @public */24export interface DeleteResult {25 /** Indicates whether this write result was acknowledged. If not, then all other members of this result will be undefined. */26 acknowledged: boolean;27 /** The number of documents that were deleted */28 deletedCount: number;29}30 31/** @public */32export interface DeleteStatement {33 /** The query that matches documents to delete. */34 q: Document;35 /** The number of matching documents to delete. */36 limit: number;37 /** Specifies the collation to use for the operation. */38 collation?: CollationOptions;39 /** A document or string that specifies the index to use to support the query predicate. */40 hint?: Hint;41}42 43/** @internal */44export class DeleteOperation extends CommandOperation<Document> {45 override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;46 override options: DeleteOptions;47 statements: DeleteStatement[];48 49 constructor(ns: MongoDBNamespace, statements: DeleteStatement[], options: DeleteOptions) {50 super(undefined, options);51 this.options = options;52 this.ns = ns;53 this.statements = statements;54 }55 56 override get commandName() {57 return 'delete' as const;58 }59 60 override get canRetryWrite(): boolean {61 if (super.canRetryWrite === false) {62 return false;63 }64 65 return this.statements.every(op => (op.limit != null ? op.limit > 0 : true));66 }67 68 override buildCommandDocument(connection: Connection, _session?: ClientSession): Document {69 const options = this.options;70 71 const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;72 const command: Document = {73 delete: this.ns.collection,74 deletes: this.statements,75 ordered76 };77 78 if (options.let) {79 command.let = options.let;80 }81 82 // we check for undefined specifically here to allow falsy values83 // eslint-disable-next-line no-restricted-syntax84 if (options.comment !== undefined) {85 command.comment = options.comment;86 }87 88 const unacknowledgedWrite = this.writeConcern && this.writeConcern.w === 0;89 if (unacknowledgedWrite && maxWireVersion(connection) < 9) {90 if (this.statements.find((o: Document) => o.hint)) {91 throw new MongoCompatibilityError(92 `hint for the delete command is only supported on MongoDB 4.4+`93 );94 }95 }96 97 return command;98 }99}100 101export class DeleteOneOperation extends DeleteOperation {102 constructor(ns: MongoDBCollectionNamespace, filter: Document, options: DeleteOptions) {103 super(ns, [makeDeleteStatement(filter, { ...options, limit: 1 })], options);104 }105 106 override handleOk(107 response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>108 ): DeleteResult {109 const res = super.handleOk(response);110 111 // @ts-expect-error Explain commands have broken TS112 if (this.explain) return res;113 114 if (res.code) throw new MongoServerError(res);115 if (res.writeErrors) throw new MongoServerError(res.writeErrors[0]);116 117 return {118 acknowledged: this.writeConcern?.w !== 0,119 deletedCount: res.n120 };121 }122}123export class DeleteManyOperation extends DeleteOperation {124 constructor(ns: MongoDBCollectionNamespace, filter: Document, options: DeleteOptions) {125 super(ns, [makeDeleteStatement(filter, options)], options);126 }127 128 override handleOk(129 response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>130 ): DeleteResult {131 const res = super.handleOk(response);132 133 // @ts-expect-error Explain commands have broken TS134 if (this.explain) return res;135 136 if (res.code) throw new MongoServerError(res);137 if (res.writeErrors) throw new MongoServerError(res.writeErrors[0]);138 139 return {140 acknowledged: this.writeConcern?.w !== 0,141 deletedCount: res.n142 };143 }144}145 146export function makeDeleteStatement(147 filter: Document,148 options: DeleteOptions & { limit?: number }149): DeleteStatement {150 const op: DeleteStatement = {151 q: filter,152 limit: typeof options.limit === 'number' ? options.limit : 0153 };154 155 if (options.collation) {156 op.collation = options.collation;157 }158 159 if (options.hint) {160 op.hint = options.hint;161 }162 163 return op;164}165 166defineAspects(DeleteOperation, [167 Aspect.RETRYABLE,168 Aspect.WRITE_OPERATION,169 Aspect.SUPPORTS_RAW_DATA170]);171defineAspects(DeleteOneOperation, [172 Aspect.RETRYABLE,173 Aspect.WRITE_OPERATION,174 Aspect.EXPLAINABLE,175 Aspect.SKIP_COLLATION,176 Aspect.SUPPORTS_RAW_DATA177]);178defineAspects(DeleteManyOperation, [179 Aspect.WRITE_OPERATION,180 Aspect.EXPLAINABLE,181 Aspect.SKIP_COLLATION,182 Aspect.SUPPORTS_RAW_DATA183]);184 