opusdev/vector-similarity-api
1
1import type { Document } from '../bson';2import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/responses';3import { type AbstractCursorOptions, type CursorTimeoutMode } from '../cursor/abstract_cursor';4import { MongoInvalidArgumentError } from '../error';5import { type ExplainOptions } from '../explain';6import type { ServerCommandOptions } from '../sdam/server';7import { formatSort, type Sort } from '../sort';8import { type TimeoutContext } from '../timeout';9import { type MongoDBNamespace, normalizeHintField } from '../utils';10import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command';11import { Aspect, defineAspects, type Hint } from './operation';12 13/**14 * @public15 * @typeParam TSchema - Unused schema definition, deprecated usage, only specify `FindOptions` with no generic16 */17// eslint-disable-next-line @typescript-eslint/no-unused-vars18export interface FindOptions<TSchema extends Document = Document>19 extends Omit<CommandOperationOptions, 'writeConcern' | 'explain'>,20 AbstractCursorOptions {21 /** Sets the limit of documents returned in the query. */22 limit?: number;23 /** Set to sort the documents coming back from the query. Array of indexes, `[['a', 1]]` etc. */24 sort?: Sort;25 /** The fields to return in the query. Object of fields to either include or exclude (one of, not both), `{'a':1, 'b': 1}` **or** `{'a': 0, 'b': 0}` */26 projection?: Document;27 /** Set to skip N documents ahead in your query (useful for pagination). */28 skip?: number;29 /** Tell the query to use specific indexes in the query. Object of indexes to use, `{'_id':1}` */30 hint?: Hint;31 /** Specify if the cursor can timeout. */32 timeout?: boolean;33 /** Specify if the cursor is tailable. */34 tailable?: boolean;35 /** Specify if the cursor is a tailable-await cursor. Requires `tailable` to be true */36 awaitData?: boolean;37 /** Set the batchSize for the getMoreCommand when iterating over the query results. */38 batchSize?: number;39 /** If true, returns only the index keys in the resulting documents. */40 returnKey?: boolean;41 /** The inclusive lower bound for a specific index */42 min?: Document;43 /** The exclusive upper bound for a specific index */44 max?: Document;45 /** Number of milliseconds to wait before aborting the query. */46 maxTimeMS?: number;47 /** The maximum amount of time for the server to wait on new documents to satisfy a tailable cursor query. Requires `tailable` and `awaitData` to be true */48 maxAwaitTimeMS?: number;49 /** The server normally times out idle cursors after an inactivity period (10 minutes) to prevent excess memory use. Set this option to prevent that. */50 noCursorTimeout?: boolean;51 /** Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields). */52 collation?: CollationOptions;53 /** Allows disk use for blocking sort operations exceeding 100MB memory. (MongoDB 3.2 or higher) */54 allowDiskUse?: boolean;55 /** Determines whether to close the cursor after the first batch. Defaults to false. */56 singleBatch?: boolean;57 /** For queries against a sharded collection, allows the command (or subsequent getMore commands) to return partial results, rather than an error, if one or more queried shards are unavailable. */58 allowPartialResults?: boolean;59 /** Determines whether to return the record identifier for each document. If true, adds a field $recordId to the returned documents. */60 showRecordId?: boolean;61 /** Map of parameter names and values that can be accessed using $$var (requires MongoDB 5.0). */62 let?: Document;63 /**64 * Option to enable an optimized code path for queries looking for a particular range of `ts` values in the oplog. Requires `tailable` to be true.65 * @deprecated Starting from MongoDB 4.4 this flag is not needed and will be ignored.66 */67 oplogReplay?: boolean;68 69 /**70 * Specifies the verbosity mode for the explain output.71 * @deprecated This API is deprecated in favor of `collection.find().explain()`.72 */73 explain?: ExplainOptions['explain'];74 /** @internal*/75 timeoutMode?: CursorTimeoutMode;76}77 78/** @public */79export interface FindOneOptions extends FindOptions {80 /** @deprecated Will be removed in the next major version. User provided value will be ignored. */81 batchSize?: number;82 /** @deprecated Will be removed in the next major version. User provided value will be ignored. */83 limit?: number;84 /** @deprecated Will be removed in the next major version. User provided value will be ignored. */85 noCursorTimeout?: boolean;86}87 88/** @internal */89export class FindOperation extends CommandOperation<CursorResponse> {90 override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;91 92 /**93 * @remarks WriteConcern can still be present on the options because94 * we inherit options from the client/db/collection. The95 * key must be present on the options in order to delete it.96 * This allows typescript to delete the key but will97 * not allow a writeConcern to be assigned as a property on options.98 */99 override options: FindOptions & { writeConcern?: never };100 filter: Document;101 102 constructor(ns: MongoDBNamespace, filter: Document = {}, options: FindOptions = {}) {103 super(undefined, options);104 105 this.options = { ...options };106 delete this.options.writeConcern;107 this.ns = ns;108 109 if (typeof filter !== 'object' || Array.isArray(filter)) {110 throw new MongoInvalidArgumentError('Query filter must be a plain object or ObjectId');111 }112 113 // special case passing in an ObjectId as a filter114 this.filter = filter != null && filter._bsontype === 'ObjectId' ? { _id: filter } : filter;115 116 this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? ExplainedCursorResponse : CursorResponse;117 }118 119 override get commandName() {120 return 'find' as const;121 }122 123 override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {124 return {125 ...this.options,126 ...this.bsonOptions,127 documentsReturnedIn: 'firstBatch',128 session: this.session,129 timeoutContext130 };131 }132 133 override handleOk(134 response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>135 ): CursorResponse {136 return response;137 }138 139 override buildCommandDocument(): Document {140 return makeFindCommand(this.ns, this.filter, this.options);141 }142}143 144function makeFindCommand(ns: MongoDBNamespace, filter: Document, options: FindOptions): Document {145 const findCommand: Document = {146 find: ns.collection,147 filter148 };149 150 if (options.sort) {151 findCommand.sort = formatSort(options.sort);152 }153 154 if (options.projection) {155 let projection = options.projection;156 if (projection && Array.isArray(projection)) {157 projection = projection.length158 ? projection.reduce((result, field) => {159 result[field] = 1;160 return result;161 }, {})162 : { _id: 1 };163 }164 165 findCommand.projection = projection;166 }167 168 if (options.hint) {169 findCommand.hint = normalizeHintField(options.hint);170 }171 172 if (typeof options.skip === 'number') {173 findCommand.skip = options.skip;174 }175 176 if (typeof options.limit === 'number') {177 if (options.limit < 0) {178 findCommand.limit = -options.limit;179 findCommand.singleBatch = true;180 } else {181 findCommand.limit = options.limit;182 }183 }184 185 if (typeof options.batchSize === 'number') {186 if (options.batchSize < 0) {187 findCommand.limit = -options.batchSize;188 } else {189 if (options.batchSize === options.limit) {190 // Spec dictates that if these are equal the batchSize should be one more than the191 // limit to avoid leaving the cursor open.192 findCommand.batchSize = options.batchSize + 1;193 } else {194 findCommand.batchSize = options.batchSize;195 }196 }197 }198 199 if (typeof options.singleBatch === 'boolean') {200 findCommand.singleBatch = options.singleBatch;201 }202 203 // we check for undefined specifically here to allow falsy values204 // eslint-disable-next-line no-restricted-syntax205 if (options.comment !== undefined) {206 findCommand.comment = options.comment;207 }208 209 if (options.max) {210 findCommand.max = options.max;211 }212 213 if (options.min) {214 findCommand.min = options.min;215 }216 217 if (typeof options.returnKey === 'boolean') {218 findCommand.returnKey = options.returnKey;219 }220 221 if (typeof options.showRecordId === 'boolean') {222 findCommand.showRecordId = options.showRecordId;223 }224 225 if (typeof options.tailable === 'boolean') {226 findCommand.tailable = options.tailable;227 }228 229 if (typeof options.oplogReplay === 'boolean') {230 findCommand.oplogReplay = options.oplogReplay;231 }232 233 if (typeof options.timeout === 'boolean') {234 findCommand.noCursorTimeout = !options.timeout;235 } else if (typeof options.noCursorTimeout === 'boolean') {236 findCommand.noCursorTimeout = options.noCursorTimeout;237 }238 239 if (typeof options.awaitData === 'boolean') {240 findCommand.awaitData = options.awaitData;241 }242 243 if (typeof options.allowPartialResults === 'boolean') {244 findCommand.allowPartialResults = options.allowPartialResults;245 }246 if (typeof options.allowDiskUse === 'boolean') {247 findCommand.allowDiskUse = options.allowDiskUse;248 }249 250 if (options.let) {251 findCommand.let = options.let;252 }253 254 return findCommand;255}256 257defineAspects(FindOperation, [258 Aspect.READ_OPERATION,259 Aspect.RETRYABLE,260 Aspect.EXPLAINABLE,261 Aspect.CURSOR_CREATING,262 Aspect.SUPPORTS_RAW_DATA263]);264 