opusdev/vector-similarity-api
1
1import { type Connection } from '..';2import type { Document } from '../bson';3import { MongoDBResponse } from '../cmap/wire_protocol/responses';4import type { Collection } from '../collection';5import { MongoCompatibilityError, MongoInvalidArgumentError } from '../error';6import { ReadPreference } from '../read_preference';7import type { ClientSession } from '../sessions';8import { formatSort, type Sort, type SortForCmd } from '../sort';9import { decorateWithCollation, hasAtomicOperators, maxWireVersion } from '../utils';10import { type WriteConcern, type WriteConcernSettings } from '../write_concern';11import { CommandOperation, type CommandOperationOptions } from './command';12import { Aspect, defineAspects } from './operation';13 14/** @public */15export const ReturnDocument = Object.freeze({16 BEFORE: 'before',17 AFTER: 'after'18} as const);19 20/** @public */21export type ReturnDocument = (typeof ReturnDocument)[keyof typeof ReturnDocument];22 23/** @public */24export interface FindOneAndDeleteOptions extends CommandOperationOptions {25 /** An optional hint for query optimization. See the {@link https://www.mongodb.com/docs/manual/reference/command/update/#update-command-hint|update command} reference for more information.*/26 hint?: Document;27 /** Limits the fields to return for all matching documents. */28 projection?: Document;29 /** Determines which document the operation modifies if the query selects multiple documents. */30 sort?: Sort;31 /** Map of parameter names and values that can be accessed using $$var (requires MongoDB 5.0). */32 let?: Document;33 /**34 * Return the ModifyResult instead of the modified document. Defaults to false35 */36 includeResultMetadata?: boolean;37}38 39/** @public */40export interface FindOneAndReplaceOptions extends CommandOperationOptions {41 /** Allow driver to bypass schema validation. */42 bypassDocumentValidation?: boolean;43 /** An optional hint for query optimization. See the {@link https://www.mongodb.com/docs/manual/reference/command/update/#update-command-hint|update command} reference for more information.*/44 hint?: Document;45 /** Limits the fields to return for all matching documents. */46 projection?: Document;47 /** When set to 'after', returns the updated document rather than the original. The default is 'before'. */48 returnDocument?: ReturnDocument;49 /** Determines which document the operation modifies if the query selects multiple documents. */50 sort?: Sort;51 /** Upsert the document if it does not exist. */52 upsert?: boolean;53 /** Map of parameter names and values that can be accessed using $$var (requires MongoDB 5.0). */54 let?: Document;55 /**56 * Return the ModifyResult instead of the modified document. Defaults to false57 */58 includeResultMetadata?: boolean;59}60 61/** @public */62export interface FindOneAndUpdateOptions extends CommandOperationOptions {63 /** Optional list of array filters referenced in filtered positional operators */64 arrayFilters?: Document[];65 /** Allow driver to bypass schema validation. */66 bypassDocumentValidation?: boolean;67 /** An optional hint for query optimization. See the {@link https://www.mongodb.com/docs/manual/reference/command/update/#update-command-hint|update command} reference for more information.*/68 hint?: Document;69 /** Limits the fields to return for all matching documents. */70 projection?: Document;71 /** When set to 'after', returns the updated document rather than the original. The default is 'before'. */72 returnDocument?: ReturnDocument;73 /** Determines which document the operation modifies if the query selects multiple documents. */74 sort?: Sort;75 /** Upsert the document if it does not exist. */76 upsert?: boolean;77 /** Map of parameter names and values that can be accessed using $$var (requires MongoDB 5.0). */78 let?: Document;79 /**80 * Return the ModifyResult instead of the modified document. Defaults to false81 */82 includeResultMetadata?: boolean;83}84 85/** @internal */86interface FindAndModifyCmdBase {87 remove: boolean;88 new: boolean;89 upsert: boolean;90 update?: Document;91 sort?: SortForCmd;92 fields?: Document;93 bypassDocumentValidation?: boolean;94 arrayFilters?: Document[];95 maxTimeMS?: number;96 let?: Document;97 writeConcern?: WriteConcern | WriteConcernSettings;98 /**99 * Comment to apply to the operation.100 *101 * In server versions pre-4.4, 'comment' must be string. A server102 * error will be thrown if any other type is provided.103 *104 * In server versions 4.4 and above, 'comment' can be any valid BSON type.105 */106 comment?: unknown;107}108 109function configureFindAndModifyCmdBaseUpdateOpts(110 cmdBase: FindAndModifyCmdBase,111 options: FindOneAndReplaceOptions | FindOneAndUpdateOptions112): FindAndModifyCmdBase {113 cmdBase.new = options.returnDocument === ReturnDocument.AFTER;114 cmdBase.upsert = options.upsert === true;115 116 if (options.bypassDocumentValidation === true) {117 cmdBase.bypassDocumentValidation = options.bypassDocumentValidation;118 }119 return cmdBase;120}121 122/** @internal */123export class FindAndModifyOperation extends CommandOperation<Document> {124 override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;125 override options: FindOneAndReplaceOptions | FindOneAndUpdateOptions | FindOneAndDeleteOptions;126 collection: Collection;127 query: Document;128 doc?: Document;129 130 constructor(131 collection: Collection,132 query: Document,133 options: FindOneAndReplaceOptions | FindOneAndUpdateOptions | FindOneAndDeleteOptions134 ) {135 super(collection, options);136 this.options = options;137 // force primary read preference138 this.readPreference = ReadPreference.primary;139 140 this.collection = collection;141 this.query = query;142 }143 144 override get commandName() {145 return 'findAndModify' as const;146 }147 148 override buildCommandDocument(149 connection: Connection,150 _session?: ClientSession151 ): Document & FindAndModifyCmdBase {152 const options = this.options;153 const command: Document & FindAndModifyCmdBase = {154 findAndModify: this.collection.collectionName,155 query: this.query,156 remove: false,157 new: false,158 upsert: false159 };160 161 options.includeResultMetadata ??= false;162 163 const sort = formatSort(options.sort);164 if (sort) {165 command.sort = sort;166 }167 168 if (options.projection) {169 command.fields = options.projection;170 }171 172 if (options.maxTimeMS) {173 command.maxTimeMS = options.maxTimeMS;174 }175 176 // Decorate the findAndModify command with the write Concern177 if (options.writeConcern) {178 command.writeConcern = options.writeConcern;179 }180 181 if (options.let) {182 command.let = options.let;183 }184 185 // we check for undefined specifically here to allow falsy values186 // eslint-disable-next-line no-restricted-syntax187 if (options.comment !== undefined) {188 command.comment = options.comment;189 }190 191 decorateWithCollation(command, options);192 193 if (options.hint) {194 const unacknowledgedWrite = this.writeConcern?.w === 0;195 if (unacknowledgedWrite && maxWireVersion(connection) < 9) {196 throw new MongoCompatibilityError(197 'hint for the findAndModify command is only supported on MongoDB 4.4+'198 );199 }200 201 command.hint = options.hint;202 }203 204 return command;205 }206 207 override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): Document {208 const result = super.handleOk(response);209 return this.options.includeResultMetadata ? result : (result.value ?? null);210 }211}212 213/** @internal */214export class FindOneAndDeleteOperation extends FindAndModifyOperation {215 constructor(collection: Collection, filter: Document, options: FindOneAndDeleteOptions) {216 // Basic validation217 if (filter == null || typeof filter !== 'object') {218 throw new MongoInvalidArgumentError('Argument "filter" must be an object');219 }220 221 super(collection, filter, options);222 }223 224 override buildCommandDocument(225 connection: Connection,226 session?: ClientSession227 ): Document & FindAndModifyCmdBase {228 const document = super.buildCommandDocument(connection, session);229 document.remove = true;230 return document;231 }232}233 234/** @internal */235export class FindOneAndReplaceOperation extends FindAndModifyOperation {236 private replacement: Document;237 constructor(238 collection: Collection,239 filter: Document,240 replacement: Document,241 options: FindOneAndReplaceOptions242 ) {243 if (filter == null || typeof filter !== 'object') {244 throw new MongoInvalidArgumentError('Argument "filter" must be an object');245 }246 247 if (replacement == null || typeof replacement !== 'object') {248 throw new MongoInvalidArgumentError('Argument "replacement" must be an object');249 }250 251 if (hasAtomicOperators(replacement)) {252 throw new MongoInvalidArgumentError('Replacement document must not contain atomic operators');253 }254 255 super(collection, filter, options);256 this.replacement = replacement;257 }258 259 override buildCommandDocument(260 connection: Connection,261 session?: ClientSession262 ): Document & FindAndModifyCmdBase {263 const document = super.buildCommandDocument(connection, session);264 document.update = this.replacement;265 configureFindAndModifyCmdBaseUpdateOpts(document, this.options);266 return document;267 }268}269 270/** @internal */271export class FindOneAndUpdateOperation extends FindAndModifyOperation {272 override options: FindOneAndUpdateOptions;273 274 private update: Document;275 constructor(276 collection: Collection,277 filter: Document,278 update: Document,279 options: FindOneAndUpdateOptions280 ) {281 if (filter == null || typeof filter !== 'object') {282 throw new MongoInvalidArgumentError('Argument "filter" must be an object');283 }284 285 if (update == null || typeof update !== 'object') {286 throw new MongoInvalidArgumentError('Argument "update" must be an object');287 }288 289 if (!hasAtomicOperators(update, options)) {290 throw new MongoInvalidArgumentError('Update document requires atomic operators');291 }292 293 super(collection, filter, options);294 this.update = update;295 this.options = options;296 }297 298 override buildCommandDocument(299 connection: Connection,300 session?: ClientSession301 ): Document & FindAndModifyCmdBase {302 const document = super.buildCommandDocument(connection, session);303 document.update = this.update;304 configureFindAndModifyCmdBaseUpdateOpts(document, this.options);305 306 if (this.options.arrayFilters) {307 document.arrayFilters = this.options.arrayFilters;308 }309 310 return document;311 }312}313 314defineAspects(FindAndModifyOperation, [315 Aspect.WRITE_OPERATION,316 Aspect.RETRYABLE,317 Aspect.EXPLAINABLE,318 Aspect.SUPPORTS_RAW_DATA319]);320 