mongodb 6.18.0-dev.20250806.sha.e628296a → 6.18.0-dev.20250814.sha.33d340ef

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/lib/collection.js +5 -5
  2. package/lib/collection.js.map +1 -1
  3. package/lib/operations/client_bulk_write/client_bulk_write.js +9 -42
  4. package/lib/operations/client_bulk_write/client_bulk_write.js.map +1 -1
  5. package/lib/operations/count.js +8 -4
  6. package/lib/operations/count.js.map +1 -1
  7. package/lib/operations/create_collection.js +17 -20
  8. package/lib/operations/create_collection.js.map +1 -1
  9. package/lib/operations/delete.js +16 -13
  10. package/lib/operations/delete.js.map +1 -1
  11. package/lib/operations/drop.js +13 -6
  12. package/lib/operations/drop.js.map +1 -1
  13. package/lib/operations/estimated_document_count.js +8 -4
  14. package/lib/operations/estimated_document_count.js.map +1 -1
  15. package/lib/operations/execute_operation.js.map +1 -1
  16. package/lib/operations/find_and_modify.js +53 -42
  17. package/lib/operations/find_and_modify.js.map +1 -1
  18. package/lib/operations/indexes.js +16 -11
  19. package/lib/operations/indexes.js.map +1 -1
  20. package/lib/operations/insert.js +0 -13
  21. package/lib/operations/insert.js.map +1 -1
  22. package/lib/operations/list_databases.js +6 -4
  23. package/lib/operations/list_databases.js.map +1 -1
  24. package/lib/operations/rename.js +11 -9
  25. package/lib/operations/rename.js.map +1 -1
  26. package/lib/operations/search_indexes/create.js +12 -9
  27. package/lib/operations/search_indexes/create.js.map +1 -1
  28. package/lib/operations/search_indexes/update.js +12 -5
  29. package/lib/operations/search_indexes/update.js.map +1 -1
  30. package/lib/operations/update.js +23 -20
  31. package/lib/operations/update.js.map +1 -1
  32. package/lib/operations/validate_collection.js +18 -19
  33. package/lib/operations/validate_collection.js.map +1 -1
  34. package/lib/sdam/server.js +25 -15
  35. package/lib/sdam/server.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/collection.ts +7 -22
  38. package/src/operations/client_bulk_write/client_bulk_write.ts +23 -67
  39. package/src/operations/count.ts +11 -11
  40. package/src/operations/create_collection.ts +22 -31
  41. package/src/operations/delete.ts +32 -36
  42. package/src/operations/drop.ts +18 -17
  43. package/src/operations/estimated_document_count.ts +10 -11
  44. package/src/operations/execute_operation.ts +7 -6
  45. package/src/operations/find_and_modify.ts +80 -56
  46. package/src/operations/indexes.ts +17 -26
  47. package/src/operations/insert.ts +0 -20
  48. package/src/operations/list_databases.ts +8 -17
  49. package/src/operations/rename.ts +13 -16
  50. package/src/operations/search_indexes/create.ts +16 -16
  51. package/src/operations/search_indexes/update.ts +16 -11
  52. package/src/operations/update.ts +55 -54
  53. package/src/operations/validate_collection.ts +21 -29
  54. package/src/sdam/server.ts +25 -15
@@ -1,16 +1,18 @@
1
+ import { type Connection } from '..';
1
2
  import type { Document } from '../bson';
2
3
  import {
3
4
  MIN_SUPPORTED_QE_SERVER_VERSION,
4
5
  MIN_SUPPORTED_QE_WIRE_VERSION
5
6
  } from '../cmap/wire_protocol/constants';
7
+ import { MongoDBResponse } from '../cmap/wire_protocol/responses';
6
8
  import { Collection } from '../collection';
7
9
  import type { Db } from '../db';
8
10
  import { MongoCompatibilityError } from '../error';
9
11
  import type { PkFactory } from '../mongo_client';
10
- import type { Server } from '../sdam/server';
11
12
  import type { ClientSession } from '../sessions';
12
13
  import { TimeoutContext } from '../timeout';
13
- import { CommandOperation, type CommandOperationOptions } from './command';
14
+ import { maxWireVersion } from '../utils';
15
+ import { type CommandOperationOptions, ModernizedCommandOperation } from './command';
14
16
  import { executeOperation } from './execute_operation';
15
17
  import { CreateIndexesOperation } from './indexes';
16
18
  import { Aspect, defineAspects } from './operation';
@@ -110,7 +112,8 @@ const INVALID_QE_VERSION =
110
112
  'Driver support of Queryable Encryption is incompatible with server. Upgrade server to use Queryable Encryption.';
111
113
 
112
114
  /** @internal */
113
- export class CreateCollectionOperation extends CommandOperation<Collection> {
115
+ export class CreateCollectionOperation extends ModernizedCommandOperation<Collection> {
116
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
114
117
  override options: CreateCollectionOptions;
115
118
  db: Db;
116
119
  name: string;
@@ -127,25 +130,19 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
127
130
  return 'create' as const;
128
131
  }
129
132
 
130
- override async execute(
131
- server: Server,
132
- session: ClientSession | undefined,
133
- timeoutContext: TimeoutContext
134
- ): Promise<Collection> {
135
- const db = this.db;
136
- const name = this.name;
137
- const options = this.options;
138
-
139
- const cmd: Document = { create: name };
140
- for (const [option, value] of Object.entries(options)) {
141
- if (value != null && typeof value !== 'function' && !ILLEGAL_COMMAND_FIELDS.has(option)) {
142
- cmd[option] = value;
143
- }
144
- }
133
+ override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
134
+ const isOptionValid = ([k, v]: [k: string, v: unknown]) =>
135
+ v != null && typeof v !== 'function' && !ILLEGAL_COMMAND_FIELDS.has(k);
136
+ return {
137
+ create: this.name,
138
+ ...Object.fromEntries(Object.entries(this.options).filter(isOptionValid))
139
+ };
140
+ }
145
141
 
146
- // otherwise just execute the command
147
- await super.executeCommand(server, session, cmd, timeoutContext);
148
- return new Collection(db, name, options);
142
+ override handleOk(
143
+ _response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
144
+ ): Collection<Document> {
145
+ return new Collection(this.db, this.name, this.options);
149
146
  }
150
147
  }
151
148
 
@@ -167,23 +164,17 @@ export async function createCollections<TSchema extends Document>(
167
164
 
168
165
  if (encryptedFields) {
169
166
  class CreateSupportingFLEv2CollectionOperation extends CreateCollectionOperation {
170
- override execute(
171
- server: Server,
172
- session: ClientSession | undefined,
173
- timeoutContext: TimeoutContext
174
- ): Promise<Collection> {
175
- // Creating a QE collection required min server of 7.0.0
176
- // TODO(NODE-5353): Get wire version information from connection.
167
+ override buildCommandDocument(connection: Connection, session?: ClientSession): Document {
177
168
  if (
178
- !server.loadBalanced &&
179
- server.description.maxWireVersion < MIN_SUPPORTED_QE_WIRE_VERSION
169
+ !connection.description.loadBalanced &&
170
+ maxWireVersion(connection) < MIN_SUPPORTED_QE_WIRE_VERSION
180
171
  ) {
181
172
  throw new MongoCompatibilityError(
182
173
  `${INVALID_QE_VERSION} The minimum server version required is ${MIN_SUPPORTED_QE_SERVER_VERSION}`
183
174
  );
184
175
  }
185
176
 
186
- return super.execute(server, session, timeoutContext);
177
+ return super.buildCommandDocument(connection, session);
187
178
  }
188
179
  }
189
180
 
@@ -1,13 +1,15 @@
1
1
  import type { Document } from '../bson';
2
- import type { Collection } from '../collection';
2
+ import { type Connection } from '../cmap/connection';
3
+ import { MongoDBResponse } from '../cmap/wire_protocol/responses';
3
4
  import { MongoCompatibilityError, MongoServerError } from '../error';
4
- import { type TODO_NODE_3286 } from '../mongo_types';
5
- import type { Server } from '../sdam/server';
6
5
  import type { ClientSession } from '../sessions';
7
- import { type TimeoutContext } from '../timeout';
8
- import { type MongoDBNamespace } from '../utils';
6
+ import { type MongoDBCollectionNamespace, type MongoDBNamespace } from '../utils';
9
7
  import { type WriteConcernOptions } from '../write_concern';
10
- import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command';
8
+ import {
9
+ type CollationOptions,
10
+ type CommandOperationOptions,
11
+ ModernizedCommandOperation
12
+ } from './command';
11
13
  import { Aspect, defineAspects, type Hint } from './operation';
12
14
 
13
15
  /** @public */
@@ -43,7 +45,8 @@ export interface DeleteStatement {
43
45
  }
44
46
 
45
47
  /** @internal */
46
- export class DeleteOperation extends CommandOperation<DeleteResult> {
48
+ export class DeleteOperation extends ModernizedCommandOperation<Document> {
49
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
47
50
  override options: DeleteOptions;
48
51
  statements: DeleteStatement[];
49
52
 
@@ -66,12 +69,9 @@ export class DeleteOperation extends CommandOperation<DeleteResult> {
66
69
  return this.statements.every(op => (op.limit != null ? op.limit > 0 : true));
67
70
  }
68
71
 
69
- override async execute(
70
- server: Server,
71
- session: ClientSession | undefined,
72
- timeoutContext: TimeoutContext
73
- ): Promise<DeleteResult> {
74
- const options = this.options ?? {};
72
+ override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
73
+ const options = this.options;
74
+
75
75
  const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
76
76
  const command: Document = {
77
77
  delete: this.ns.collection,
@@ -97,28 +97,23 @@ export class DeleteOperation extends CommandOperation<DeleteResult> {
97
97
  }
98
98
  }
99
99
 
100
- const res: TODO_NODE_3286 = await super.executeCommand(
101
- server,
102
- session,
103
- command,
104
- timeoutContext
105
- );
106
- return res;
100
+ return command;
107
101
  }
108
102
  }
109
103
 
110
104
  export class DeleteOneOperation extends DeleteOperation {
111
- constructor(collection: Collection, filter: Document, options: DeleteOptions) {
112
- super(collection.s.namespace, [makeDeleteStatement(filter, { ...options, limit: 1 })], options);
105
+ constructor(ns: MongoDBCollectionNamespace, filter: Document, options: DeleteOptions) {
106
+ super(ns, [makeDeleteStatement(filter, { ...options, limit: 1 })], options);
113
107
  }
114
108
 
115
- override async execute(
116
- server: Server,
117
- session: ClientSession | undefined,
118
- timeoutContext: TimeoutContext
119
- ): Promise<DeleteResult> {
120
- const res: TODO_NODE_3286 = await super.execute(server, session, timeoutContext);
109
+ override handleOk(
110
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
111
+ ): DeleteResult {
112
+ const res = super.handleOk(response);
113
+
114
+ // @ts-expect-error Explain commands have broken TS
121
115
  if (this.explain) return res;
116
+
122
117
  if (res.code) throw new MongoServerError(res);
123
118
  if (res.writeErrors) throw new MongoServerError(res.writeErrors[0]);
124
119
 
@@ -129,17 +124,18 @@ export class DeleteOneOperation extends DeleteOperation {
129
124
  }
130
125
  }
131
126
  export class DeleteManyOperation extends DeleteOperation {
132
- constructor(collection: Collection, filter: Document, options: DeleteOptions) {
133
- super(collection.s.namespace, [makeDeleteStatement(filter, options)], options);
127
+ constructor(ns: MongoDBCollectionNamespace, filter: Document, options: DeleteOptions) {
128
+ super(ns, [makeDeleteStatement(filter, options)], options);
134
129
  }
135
130
 
136
- override async execute(
137
- server: Server,
138
- session: ClientSession | undefined,
139
- timeoutContext: TimeoutContext
140
- ): Promise<DeleteResult> {
141
- const res: TODO_NODE_3286 = await super.execute(server, session, timeoutContext);
131
+ override handleOk(
132
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
133
+ ): DeleteResult {
134
+ const res = super.handleOk(response);
135
+
136
+ // @ts-expect-error Explain commands have broken TS
142
137
  if (this.explain) return res;
138
+
143
139
  if (res.code) throw new MongoServerError(res);
144
140
  if (res.writeErrors) throw new MongoServerError(res.writeErrors[0]);
145
141
 
@@ -1,12 +1,12 @@
1
- import { MongoServerError } from '..';
1
+ import { type Connection, MongoServerError } from '..';
2
2
  import type { Document } from '../bson';
3
+ import { MongoDBResponse } from '../cmap/wire_protocol/responses';
3
4
  import { CursorTimeoutContext } from '../cursor/abstract_cursor';
4
5
  import type { Db } from '../db';
5
6
  import { MONGODB_ERROR_CODES } from '../error';
6
- import type { Server } from '../sdam/server';
7
7
  import type { ClientSession } from '../sessions';
8
8
  import { TimeoutContext } from '../timeout';
9
- import { CommandOperation, type CommandOperationOptions } from './command';
9
+ import { type CommandOperationOptions, ModernizedCommandOperation } from './command';
10
10
  import { executeOperation } from './execute_operation';
11
11
  import { Aspect, defineAspects } from './operation';
12
12
 
@@ -17,7 +17,9 @@ export interface DropCollectionOptions extends CommandOperationOptions {
17
17
  }
18
18
 
19
19
  /** @internal */
20
- export class DropCollectionOperation extends CommandOperation<boolean> {
20
+ export class DropCollectionOperation extends ModernizedCommandOperation<boolean> {
21
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
22
+
21
23
  override options: DropCollectionOptions;
22
24
  name: string;
23
25
 
@@ -31,12 +33,11 @@ export class DropCollectionOperation extends CommandOperation<boolean> {
31
33
  return 'drop' as const;
32
34
  }
33
35
 
34
- override async execute(
35
- server: Server,
36
- session: ClientSession | undefined,
37
- timeoutContext: TimeoutContext
38
- ): Promise<boolean> {
39
- await super.executeCommand(server, session, { drop: this.name }, timeoutContext);
36
+ override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
37
+ return { drop: this.name };
38
+ }
39
+
40
+ override handleOk(_response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): boolean {
40
41
  return true;
41
42
  }
42
43
  }
@@ -106,7 +107,8 @@ export async function dropCollections(
106
107
  export type DropDatabaseOptions = CommandOperationOptions;
107
108
 
108
109
  /** @internal */
109
- export class DropDatabaseOperation extends CommandOperation<boolean> {
110
+ export class DropDatabaseOperation extends ModernizedCommandOperation<boolean> {
111
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
110
112
  override options: DropDatabaseOptions;
111
113
 
112
114
  constructor(db: Db, options: DropDatabaseOptions) {
@@ -117,12 +119,11 @@ export class DropDatabaseOperation extends CommandOperation<boolean> {
117
119
  return 'dropDatabase' as const;
118
120
  }
119
121
 
120
- override async execute(
121
- server: Server,
122
- session: ClientSession | undefined,
123
- timeoutContext: TimeoutContext
124
- ): Promise<boolean> {
125
- await super.executeCommand(server, session, { dropDatabase: 1 }, timeoutContext);
122
+ override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
123
+ return { dropDatabase: 1 };
124
+ }
125
+
126
+ override handleOk(_response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): boolean {
126
127
  return true;
127
128
  }
128
129
  }
@@ -1,9 +1,9 @@
1
+ import { type Connection } from '..';
1
2
  import type { Document } from '../bson';
3
+ import { MongoDBResponse } from '../cmap/wire_protocol/responses';
2
4
  import type { Collection } from '../collection';
3
- import type { Server } from '../sdam/server';
4
5
  import type { ClientSession } from '../sessions';
5
- import { type TimeoutContext } from '../timeout';
6
- import { CommandOperation, type CommandOperationOptions } from './command';
6
+ import { type CommandOperationOptions, ModernizedCommandOperation } from './command';
7
7
  import { Aspect, defineAspects } from './operation';
8
8
 
9
9
  /** @public */
@@ -17,7 +17,8 @@ export interface EstimatedDocumentCountOptions extends CommandOperationOptions {
17
17
  }
18
18
 
19
19
  /** @internal */
20
- export class EstimatedDocumentCountOperation extends CommandOperation<number> {
20
+ export class EstimatedDocumentCountOperation extends ModernizedCommandOperation<number> {
21
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
21
22
  override options: EstimatedDocumentCountOptions;
22
23
  collectionName: string;
23
24
 
@@ -31,11 +32,7 @@ export class EstimatedDocumentCountOperation extends CommandOperation<number> {
31
32
  return 'count' as const;
32
33
  }
33
34
 
34
- override async execute(
35
- server: Server,
36
- session: ClientSession | undefined,
37
- timeoutContext: TimeoutContext
38
- ): Promise<number> {
35
+ override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
39
36
  const cmd: Document = { count: this.collectionName };
40
37
 
41
38
  if (typeof this.options.maxTimeMS === 'number') {
@@ -48,9 +45,11 @@ export class EstimatedDocumentCountOperation extends CommandOperation<number> {
48
45
  cmd.comment = this.options.comment;
49
46
  }
50
47
 
51
- const response = await super.executeCommand(server, session, cmd, timeoutContext);
48
+ return cmd;
49
+ }
52
50
 
53
- return response?.n || 0;
51
+ override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): number {
52
+ return response.getNumber('n') ?? 0;
54
53
  }
55
54
  }
56
55
 
@@ -34,7 +34,11 @@ const MMAPv1_RETRY_WRITES_ERROR_MESSAGE =
34
34
  'This MongoDB deployment does not support retryable writes. Please add retryWrites=false to your connection string.';
35
35
 
36
36
  type ResultTypeFromOperation<TOperation> =
37
- TOperation extends AbstractOperation<infer K> ? K : never;
37
+ TOperation extends ModernizedOperation<infer _>
38
+ ? ReturnType<TOperation['handleOk']>
39
+ : TOperation extends AbstractOperation<infer K>
40
+ ? K
41
+ : never;
38
42
 
39
43
  /**
40
44
  * Executes the given operation with provided arguments.
@@ -57,7 +61,7 @@ type ResultTypeFromOperation<TOperation> =
57
61
  * @param operation - The operation to execute
58
62
  */
59
63
  export async function executeOperation<
60
- T extends AbstractOperation<TResult>,
64
+ T extends AbstractOperation,
61
65
  TResult = ResultTypeFromOperation<T>
62
66
  >(client: MongoClient, operation: T, timeoutContext?: TimeoutContext | null): Promise<TResult> {
63
67
  if (!(operation instanceof AbstractOperation)) {
@@ -179,10 +183,7 @@ type RetryOptions = {
179
183
  *
180
184
  * @param operation - The operation to execute
181
185
  * */
182
- async function tryOperation<
183
- T extends AbstractOperation<TResult>,
184
- TResult = ResultTypeFromOperation<T>
185
- >(
186
+ async function tryOperation<T extends AbstractOperation, TResult = ResultTypeFromOperation<T>>(
186
187
  operation: T,
187
188
  { topology, timeoutContext, session, readPreference }: RetryOptions
188
189
  ): Promise<TResult> {
@@ -1,14 +1,14 @@
1
+ import { type Connection } from '..';
1
2
  import type { Document } from '../bson';
3
+ import { MongoDBResponse } from '../cmap/wire_protocol/responses';
2
4
  import type { Collection } from '../collection';
3
5
  import { MongoCompatibilityError, MongoInvalidArgumentError } from '../error';
4
6
  import { ReadPreference } from '../read_preference';
5
- import type { Server } from '../sdam/server';
6
7
  import type { ClientSession } from '../sessions';
7
8
  import { formatSort, type Sort, type SortForCmd } from '../sort';
8
- import { type TimeoutContext } from '../timeout';
9
- import { decorateWithCollation, hasAtomicOperators, maxWireVersion } from '../utils';
9
+ import { decorateWithCollation, hasAtomicOperators } from '../utils';
10
10
  import { type WriteConcern, type WriteConcernSettings } from '../write_concern';
11
- import { CommandOperation, type CommandOperationOptions } from './command';
11
+ import { type CommandOperationOptions, ModernizedCommandOperation } from './command';
12
12
  import { Aspect, defineAspects } from './operation';
13
13
 
14
14
  /** @public */
@@ -120,9 +120,9 @@ function configureFindAndModifyCmdBaseUpdateOpts(
120
120
  }
121
121
 
122
122
  /** @internal */
123
- export class FindAndModifyOperation extends CommandOperation<Document> {
123
+ export class FindAndModifyOperation extends ModernizedCommandOperation<Document> {
124
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
124
125
  override options: FindOneAndReplaceOptions | FindOneAndUpdateOptions | FindOneAndDeleteOptions;
125
- cmdBase: FindAndModifyCmdBase;
126
126
  collection: Collection;
127
127
  query: Document;
128
128
  doc?: Document;
@@ -133,8 +133,26 @@ export class FindAndModifyOperation extends CommandOperation<Document> {
133
133
  options: FindOneAndReplaceOptions | FindOneAndUpdateOptions | FindOneAndDeleteOptions
134
134
  ) {
135
135
  super(collection, options);
136
- this.options = options ?? {};
137
- this.cmdBase = {
136
+ this.options = options;
137
+ // force primary read preference
138
+ 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?: ClientSession
151
+ ): Document & FindAndModifyCmdBase {
152
+ const options = this.options;
153
+ const command: Document & FindAndModifyCmdBase = {
154
+ findAndModify: this.collection.collectionName,
155
+ query: this.query,
138
156
  remove: false,
139
157
  new: false,
140
158
  upsert: false
@@ -144,77 +162,51 @@ export class FindAndModifyOperation extends CommandOperation<Document> {
144
162
 
145
163
  const sort = formatSort(options.sort);
146
164
  if (sort) {
147
- this.cmdBase.sort = sort;
165
+ command.sort = sort;
148
166
  }
149
167
 
150
168
  if (options.projection) {
151
- this.cmdBase.fields = options.projection;
169
+ command.fields = options.projection;
152
170
  }
153
171
 
154
172
  if (options.maxTimeMS) {
155
- this.cmdBase.maxTimeMS = options.maxTimeMS;
173
+ command.maxTimeMS = options.maxTimeMS;
156
174
  }
157
175
 
158
176
  // Decorate the findAndModify command with the write Concern
159
177
  if (options.writeConcern) {
160
- this.cmdBase.writeConcern = options.writeConcern;
178
+ command.writeConcern = options.writeConcern;
161
179
  }
162
180
 
163
181
  if (options.let) {
164
- this.cmdBase.let = options.let;
182
+ command.let = options.let;
165
183
  }
166
184
 
167
185
  // we check for undefined specifically here to allow falsy values
168
186
  // eslint-disable-next-line no-restricted-syntax
169
187
  if (options.comment !== undefined) {
170
- this.cmdBase.comment = options.comment;
188
+ command.comment = options.comment;
171
189
  }
172
190
 
173
- // force primary read preference
174
- this.readPreference = ReadPreference.primary;
175
-
176
- this.collection = collection;
177
- this.query = query;
178
- }
179
-
180
- override get commandName() {
181
- return 'findAndModify' as const;
182
- }
183
-
184
- override async execute(
185
- server: Server,
186
- session: ClientSession | undefined,
187
- timeoutContext: TimeoutContext
188
- ): Promise<Document> {
189
- const coll = this.collection;
190
- const query = this.query;
191
- const options = { ...this.options, ...this.bsonOptions };
192
-
193
- // Create findAndModify command object
194
- const cmd: Document = {
195
- findAndModify: coll.collectionName,
196
- query: query,
197
- ...this.cmdBase
198
- };
199
-
200
- decorateWithCollation(cmd, coll, options);
191
+ decorateWithCollation(command, this.collection, options);
201
192
 
202
193
  if (options.hint) {
203
- // TODO: once this method becomes a CommandOperation we will have the server
204
- // in place to check.
205
194
  const unacknowledgedWrite = this.writeConcern?.w === 0;
206
- if (unacknowledgedWrite || maxWireVersion(server) < 8) {
195
+ if (unacknowledgedWrite) {
207
196
  throw new MongoCompatibilityError(
208
197
  'The current topology does not support a hint on findAndModify commands'
209
198
  );
210
199
  }
211
200
 
212
- cmd.hint = options.hint;
201
+ command.hint = options.hint;
213
202
  }
214
203
 
215
- // Execute the command
216
- const result = await super.executeCommand(server, session, cmd, timeoutContext);
217
- return options.includeResultMetadata ? result : (result.value ?? null);
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);
218
210
  }
219
211
  }
220
212
 
@@ -227,12 +219,21 @@ export class FindOneAndDeleteOperation extends FindAndModifyOperation {
227
219
  }
228
220
 
229
221
  super(collection, filter, options);
230
- this.cmdBase.remove = true;
222
+ }
223
+
224
+ override buildCommandDocument(
225
+ connection: Connection,
226
+ session?: ClientSession
227
+ ): Document & FindAndModifyCmdBase {
228
+ const document = super.buildCommandDocument(connection, session);
229
+ document.remove = true;
230
+ return document;
231
231
  }
232
232
  }
233
233
 
234
234
  /** @internal */
235
235
  export class FindOneAndReplaceOperation extends FindAndModifyOperation {
236
+ private replacement: Document;
236
237
  constructor(
237
238
  collection: Collection,
238
239
  filter: Document,
@@ -252,13 +253,25 @@ export class FindOneAndReplaceOperation extends FindAndModifyOperation {
252
253
  }
253
254
 
254
255
  super(collection, filter, options);
255
- this.cmdBase.update = replacement;
256
- configureFindAndModifyCmdBaseUpdateOpts(this.cmdBase, options);
256
+ this.replacement = replacement;
257
+ }
258
+
259
+ override buildCommandDocument(
260
+ connection: Connection,
261
+ session?: ClientSession
262
+ ): Document & FindAndModifyCmdBase {
263
+ const document = super.buildCommandDocument(connection, session);
264
+ document.update = this.replacement;
265
+ configureFindAndModifyCmdBaseUpdateOpts(document, this.options);
266
+ return document;
257
267
  }
258
268
  }
259
269
 
260
270
  /** @internal */
261
271
  export class FindOneAndUpdateOperation extends FindAndModifyOperation {
272
+ override options: FindOneAndUpdateOptions;
273
+
274
+ private update: Document;
262
275
  constructor(
263
276
  collection: Collection,
264
277
  filter: Document,
@@ -278,12 +291,23 @@ export class FindOneAndUpdateOperation extends FindAndModifyOperation {
278
291
  }
279
292
 
280
293
  super(collection, filter, options);
281
- this.cmdBase.update = update;
282
- configureFindAndModifyCmdBaseUpdateOpts(this.cmdBase, options);
294
+ this.update = update;
295
+ this.options = options;
296
+ }
283
297
 
284
- if (options.arrayFilters) {
285
- this.cmdBase.arrayFilters = options.arrayFilters;
298
+ override buildCommandDocument(
299
+ connection: Connection,
300
+ session?: ClientSession
301
+ ): 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;
286
308
  }
309
+
310
+ return document;
287
311
  }
288
312
  }
289
313