mongodb 6.18.0 → 6.19.0-dev.20250828.sha.41034f16

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 (158) hide show
  1. package/lib/admin.js +2 -1
  2. package/lib/admin.js.map +1 -1
  3. package/lib/beta.d.ts +59 -7
  4. package/lib/bulk/common.js +19 -32
  5. package/lib/bulk/common.js.map +1 -1
  6. package/lib/client-side-encryption/client_encryption.js +4 -1
  7. package/lib/client-side-encryption/client_encryption.js.map +1 -1
  8. package/lib/client-side-encryption/state_machine.js +4 -0
  9. package/lib/client-side-encryption/state_machine.js.map +1 -1
  10. package/lib/cmap/connection.js.map +1 -1
  11. package/lib/collection.js +62 -19
  12. package/lib/collection.js.map +1 -1
  13. package/lib/cursor/aggregation_cursor.js +2 -1
  14. package/lib/cursor/aggregation_cursor.js.map +1 -1
  15. package/lib/cursor/explainable_cursor.js +36 -0
  16. package/lib/cursor/explainable_cursor.js.map +1 -0
  17. package/lib/cursor/find_cursor.js +2 -1
  18. package/lib/cursor/find_cursor.js.map +1 -1
  19. package/lib/cursor/run_command_cursor.js +2 -4
  20. package/lib/cursor/run_command_cursor.js.map +1 -1
  21. package/lib/db.js +12 -5
  22. package/lib/db.js.map +1 -1
  23. package/lib/explain.js +1 -33
  24. package/lib/explain.js.map +1 -1
  25. package/lib/index.js +6 -6
  26. package/lib/index.js.map +1 -1
  27. package/lib/mongo_client.js +25 -2
  28. package/lib/mongo_client.js.map +1 -1
  29. package/lib/operations/aggregate.js +9 -7
  30. package/lib/operations/aggregate.js.map +1 -1
  31. package/lib/operations/client_bulk_write/client_bulk_write.js +8 -41
  32. package/lib/operations/client_bulk_write/client_bulk_write.js.map +1 -1
  33. package/lib/operations/command.js +16 -19
  34. package/lib/operations/command.js.map +1 -1
  35. package/lib/operations/count.js +7 -3
  36. package/lib/operations/count.js.map +1 -1
  37. package/lib/operations/create_collection.js +56 -49
  38. package/lib/operations/create_collection.js.map +1 -1
  39. package/lib/operations/delete.js +15 -12
  40. package/lib/operations/delete.js.map +1 -1
  41. package/lib/operations/distinct.js +18 -26
  42. package/lib/operations/distinct.js.map +1 -1
  43. package/lib/operations/drop.js +57 -39
  44. package/lib/operations/drop.js.map +1 -1
  45. package/lib/operations/estimated_document_count.js +7 -3
  46. package/lib/operations/estimated_document_count.js.map +1 -1
  47. package/lib/operations/execute_operation.js +14 -3
  48. package/lib/operations/execute_operation.js.map +1 -1
  49. package/lib/operations/find.js +21 -30
  50. package/lib/operations/find.js.map +1 -1
  51. package/lib/operations/find_and_modify.js +52 -41
  52. package/lib/operations/find_and_modify.js.map +1 -1
  53. package/lib/operations/get_more.js +10 -11
  54. package/lib/operations/get_more.js.map +1 -1
  55. package/lib/operations/indexes.js +21 -12
  56. package/lib/operations/indexes.js.map +1 -1
  57. package/lib/operations/insert.js +8 -47
  58. package/lib/operations/insert.js.map +1 -1
  59. package/lib/operations/kill_cursors.js +13 -15
  60. package/lib/operations/kill_cursors.js.map +1 -1
  61. package/lib/operations/list_collections.js +7 -6
  62. package/lib/operations/list_collections.js.map +1 -1
  63. package/lib/operations/list_databases.js +5 -3
  64. package/lib/operations/list_databases.js.map +1 -1
  65. package/lib/operations/operation.js +30 -1
  66. package/lib/operations/operation.js.map +1 -1
  67. package/lib/operations/profiling_level.js +14 -4
  68. package/lib/operations/profiling_level.js.map +1 -1
  69. package/lib/operations/remove_user.js +6 -2
  70. package/lib/operations/remove_user.js.map +1 -1
  71. package/lib/operations/rename.js +10 -8
  72. package/lib/operations/rename.js.map +1 -1
  73. package/lib/operations/run_command.js +28 -32
  74. package/lib/operations/run_command.js.map +1 -1
  75. package/lib/operations/search_indexes/create.js +11 -8
  76. package/lib/operations/search_indexes/create.js.map +1 -1
  77. package/lib/operations/search_indexes/drop.js +16 -9
  78. package/lib/operations/search_indexes/drop.js.map +1 -1
  79. package/lib/operations/search_indexes/update.js +11 -4
  80. package/lib/operations/search_indexes/update.js.map +1 -1
  81. package/lib/operations/set_profiling_level.js +8 -4
  82. package/lib/operations/set_profiling_level.js.map +1 -1
  83. package/lib/operations/stats.js +4 -2
  84. package/lib/operations/stats.js.map +1 -1
  85. package/lib/operations/update.js +22 -19
  86. package/lib/operations/update.js.map +1 -1
  87. package/lib/operations/validate_collection.js +17 -18
  88. package/lib/operations/validate_collection.js.map +1 -1
  89. package/lib/sdam/server.js +46 -35
  90. package/lib/sdam/server.js.map +1 -1
  91. package/lib/sdam/topology.js +4 -3
  92. package/lib/sdam/topology.js.map +1 -1
  93. package/lib/sessions.js +3 -3
  94. package/lib/sessions.js.map +1 -1
  95. package/lib/utils.js +8 -13
  96. package/lib/utils.js.map +1 -1
  97. package/mongodb.d.ts +59 -7
  98. package/package.json +19 -19
  99. package/src/admin.ts +3 -2
  100. package/src/bulk/common.ts +21 -41
  101. package/src/client-side-encryption/client_encryption.ts +52 -3
  102. package/src/client-side-encryption/state_machine.ts +5 -1
  103. package/src/cmap/connection.ts +0 -1
  104. package/src/collection.ts +94 -65
  105. package/src/cursor/aggregation_cursor.ts +1 -1
  106. package/src/cursor/explainable_cursor.ts +51 -0
  107. package/src/cursor/find_cursor.ts +1 -1
  108. package/src/cursor/run_command_cursor.ts +4 -5
  109. package/src/db.ts +16 -19
  110. package/src/explain.ts +0 -49
  111. package/src/index.ts +4 -4
  112. package/src/mongo_client.ts +24 -9
  113. package/src/operations/aggregate.ts +15 -20
  114. package/src/operations/client_bulk_write/client_bulk_write.ts +21 -65
  115. package/src/operations/command.ts +22 -45
  116. package/src/operations/count.ts +9 -9
  117. package/src/operations/create_collection.ts +83 -75
  118. package/src/operations/delete.ts +27 -35
  119. package/src/operations/distinct.ts +23 -40
  120. package/src/operations/drop.ts +76 -60
  121. package/src/operations/estimated_document_count.ts +8 -9
  122. package/src/operations/execute_operation.ts +21 -11
  123. package/src/operations/find.ts +40 -57
  124. package/src/operations/find_and_modify.ts +78 -54
  125. package/src/operations/get_more.ts +17 -19
  126. package/src/operations/indexes.ts +26 -30
  127. package/src/operations/insert.ts +11 -77
  128. package/src/operations/kill_cursors.ts +21 -22
  129. package/src/operations/list_collections.ts +13 -21
  130. package/src/operations/list_databases.ts +6 -15
  131. package/src/operations/operation.ts +47 -10
  132. package/src/operations/profiling_level.ts +17 -11
  133. package/src/operations/remove_user.ts +9 -9
  134. package/src/operations/rename.ts +11 -14
  135. package/src/operations/run_command.ts +40 -68
  136. package/src/operations/search_indexes/create.ts +15 -15
  137. package/src/operations/search_indexes/drop.ts +23 -14
  138. package/src/operations/search_indexes/update.ts +14 -9
  139. package/src/operations/set_profiling_level.ts +13 -11
  140. package/src/operations/stats.ts +5 -10
  141. package/src/operations/update.ts +49 -52
  142. package/src/operations/validate_collection.ts +19 -27
  143. package/src/sdam/server.ts +56 -59
  144. package/src/sdam/topology.ts +5 -4
  145. package/src/sessions.ts +5 -4
  146. package/src/utils.ts +10 -25
  147. package/lib/operations/bulk_write.js +0 -39
  148. package/lib/operations/bulk_write.js.map +0 -1
  149. package/lib/operations/collections.js +0 -33
  150. package/lib/operations/collections.js.map +0 -1
  151. package/lib/operations/is_capped.js +0 -28
  152. package/lib/operations/is_capped.js.map +0 -1
  153. package/lib/operations/options_operation.js +0 -28
  154. package/lib/operations/options_operation.js.map +0 -1
  155. package/src/operations/bulk_write.ts +0 -64
  156. package/src/operations/collections.ts +0 -47
  157. package/src/operations/is_capped.ts +0 -35
  158. package/src/operations/options_operation.ts +0 -35
package/src/index.ts CHANGED
@@ -10,7 +10,6 @@ import { ListCollectionsCursor } from './cursor/list_collections_cursor';
10
10
  import { ListIndexesCursor } from './cursor/list_indexes_cursor';
11
11
  import type { RunCommandCursor } from './cursor/run_command_cursor';
12
12
  import { Db } from './db';
13
- import { ExplainableCursor } from './explain';
14
13
  import { GridFSBucket } from './gridfs';
15
14
  import { GridFSBucketReadStream } from './gridfs/download';
16
15
  import { GridFSBucketWriteStream } from './gridfs/upload';
@@ -44,6 +43,7 @@ export {
44
43
  } from './bulk/common';
45
44
  export { ClientEncryption } from './client-side-encryption/client_encryption';
46
45
  export { ChangeStreamCursor } from './cursor/change_stream_cursor';
46
+ export { ExplainableCursor } from './cursor/explainable_cursor';
47
47
  export {
48
48
  MongoAPIError,
49
49
  MongoAWSError,
@@ -98,7 +98,6 @@ export {
98
98
  ClientSession,
99
99
  Collection,
100
100
  Db,
101
- ExplainableCursor,
102
101
  FindCursor,
103
102
  GridFSBucket,
104
103
  GridFSBucketReadStream,
@@ -243,7 +242,8 @@ export type {
243
242
  DataKey,
244
243
  GCPEncryptionKeyOptions,
245
244
  KMIPEncryptionKeyOptions,
246
- RangeOptions
245
+ RangeOptions,
246
+ TextQueryOptions
247
247
  } from './client-side-encryption/client_encryption';
248
248
  export {
249
249
  MongoCryptAzureKMSRequestError,
@@ -523,7 +523,7 @@ export type { DeleteOptions, DeleteResult, DeleteStatement } from './operations/
523
523
  export type { DistinctOptions } from './operations/distinct';
524
524
  export type { DropCollectionOptions, DropDatabaseOptions } from './operations/drop';
525
525
  export type { EstimatedDocumentCountOptions } from './operations/estimated_document_count';
526
- export type { FindOptions } from './operations/find';
526
+ export type { FindOneOptions, FindOptions } from './operations/find';
527
527
  export type {
528
528
  FindOneAndDeleteOptions,
529
529
  FindOneAndReplaceOptions,
@@ -2,6 +2,7 @@ import { promises as fs } from 'fs';
2
2
  import type { TcpNetConnectOpts } from 'net';
3
3
  import type { ConnectionOptions as TLSConnectionOptions, TLSSocketOptions } from 'tls';
4
4
 
5
+ import { type ServerCommandOptions, type TimeoutContext } from '.';
5
6
  import { type BSONSerializeOptions, type Document, resolveBSONOptions } from './bson';
6
7
  import { ChangeStream, type ChangeStreamDocument, type ChangeStreamOptions } from './change_stream';
7
8
  import type { AutoEncrypter, AutoEncryptionOptions } from './client-side-encryption/auto_encrypter';
@@ -20,6 +21,7 @@ import {
20
21
  makeClientMetadata
21
22
  } from './cmap/handshake/client_metadata';
22
23
  import type { CompressorName } from './cmap/wire_protocol/compression';
24
+ import { MongoDBResponse } from './cmap/wire_protocol/responses';
23
25
  import { parseOptions, resolveSRVRecord } from './connection_string';
24
26
  import { MONGO_CLIENT_EVENTS } from './constants';
25
27
  import { type AbstractCursor } from './cursor/abstract_cursor';
@@ -42,7 +44,7 @@ import {
42
44
  } from './operations/client_bulk_write/common';
43
45
  import { ClientBulkWriteExecutor } from './operations/client_bulk_write/executor';
44
46
  import { executeOperation } from './operations/execute_operation';
45
- import { RunAdminCommandOperation } from './operations/run_command';
47
+ import { AbstractOperation } from './operations/operation';
46
48
  import type { ReadConcern, ReadConcernLevel, ReadConcernLike } from './read_concern';
47
49
  import { ReadPreference, type ReadPreferenceMode } from './read_preference';
48
50
  import { type AsyncDisposable, configureResourceManagement } from './resource_management';
@@ -60,7 +62,7 @@ import {
60
62
  type HostAddress,
61
63
  hostMatchesWildcards,
62
64
  isHostMatch,
63
- type MongoDBNamespace,
65
+ MongoDBNamespace,
64
66
  noop,
65
67
  ns,
66
68
  resolveOptions,
@@ -790,13 +792,26 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
790
792
  const endSessions = Array.from(this.s.sessionPool.sessions, ({ id }) => id);
791
793
  if (endSessions.length !== 0) {
792
794
  try {
793
- await executeOperation(
794
- this,
795
- new RunAdminCommandOperation(
796
- { endSessions },
797
- { readPreference: ReadPreference.primaryPreferred, noResponse: true }
798
- )
799
- );
795
+ class EndSessionsOperation extends AbstractOperation<void> {
796
+ override ns = MongoDBNamespace.fromString('admin.$cmd');
797
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
798
+ override buildCommand(_connection: Connection, _session?: ClientSession): Document {
799
+ return {
800
+ endSessions
801
+ };
802
+ }
803
+ override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
804
+ return {
805
+ timeoutContext,
806
+ readPreference: ReadPreference.primaryPreferred,
807
+ noResponse: true
808
+ };
809
+ }
810
+ override get commandName(): string {
811
+ return 'endSessions';
812
+ }
813
+ }
814
+ await executeOperation(this, new EndSessionsOperation());
800
815
  } catch (error) {
801
816
  squashError(error);
802
817
  }
@@ -1,11 +1,9 @@
1
+ import { type Connection } from '..';
1
2
  import type { Document } from '../bson';
2
3
  import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/responses';
3
4
  import { type CursorTimeoutMode } from '../cursor/abstract_cursor';
4
5
  import { MongoInvalidArgumentError } from '../error';
5
6
  import { type ExplainOptions } from '../explain';
6
- import type { Server } from '../sdam/server';
7
- import type { ClientSession } from '../sessions';
8
- import { type TimeoutContext } from '../timeout';
9
7
  import { maxWireVersion, type MongoDBNamespace } from '../utils';
10
8
  import { WriteConcern } from '../write_concern';
11
9
  import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command';
@@ -52,6 +50,7 @@ export interface AggregateOptions extends Omit<CommandOperationOptions, 'explain
52
50
 
53
51
  /** @internal */
54
52
  export class AggregateOperation extends CommandOperation<CursorResponse> {
53
+ override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
55
54
  override options: AggregateOptions;
56
55
  target: string | typeof DB_AGGREGATE_COLLECTION;
57
56
  pipeline: Document[];
@@ -79,9 +78,7 @@ export class AggregateOperation extends CommandOperation<CursorResponse> {
79
78
  }
80
79
  }
81
80
 
82
- if (this.hasWriteStage) {
83
- this.trySecondaryWrite = true;
84
- } else {
81
+ if (!this.hasWriteStage) {
85
82
  delete this.options.writeConcern;
86
83
  }
87
84
 
@@ -94,6 +91,8 @@ export class AggregateOperation extends CommandOperation<CursorResponse> {
94
91
  if (options?.cursor != null && typeof options.cursor !== 'object') {
95
92
  throw new MongoInvalidArgumentError('Cursor options must be an object');
96
93
  }
94
+
95
+ this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? ExplainedCursorResponse : CursorResponse;
97
96
  }
98
97
 
99
98
  override get commandName() {
@@ -108,13 +107,9 @@ export class AggregateOperation extends CommandOperation<CursorResponse> {
108
107
  this.pipeline.push(stage);
109
108
  }
110
109
 
111
- override async execute(
112
- server: Server,
113
- session: ClientSession | undefined,
114
- timeoutContext: TimeoutContext
115
- ): Promise<CursorResponse> {
116
- const options: AggregateOptions = this.options;
117
- const serverWireVersion = maxWireVersion(server);
110
+ override buildCommandDocument(connection: Connection): Document {
111
+ const options = this.options;
112
+ const serverWireVersion = maxWireVersion(connection);
118
113
  const command: Document = { aggregate: this.target, pipeline: this.pipeline };
119
114
 
120
115
  if (this.hasWriteStage && serverWireVersion < MIN_WIRE_VERSION_$OUT_READ_CONCERN_SUPPORT) {
@@ -152,13 +147,13 @@ export class AggregateOperation extends CommandOperation<CursorResponse> {
152
147
  command.cursor.batchSize = options.batchSize;
153
148
  }
154
149
 
155
- return await super.executeCommand(
156
- server,
157
- session,
158
- command,
159
- timeoutContext,
160
- this.explain ? ExplainedCursorResponse : CursorResponse
161
- );
150
+ return command;
151
+ }
152
+
153
+ override handleOk(
154
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
155
+ ): CursorResponse {
156
+ return response;
162
157
  }
163
158
  }
164
159
 
@@ -1,12 +1,10 @@
1
- import { MongoClientBulkWriteExecutionError, ServerType } from '../../beta';
1
+ import { type Connection } from '../../cmap/connection';
2
2
  import { ClientBulkWriteCursorResponse } from '../../cmap/wire_protocol/responses';
3
- import type { Server } from '../../sdam/server';
4
3
  import type { ClientSession } from '../../sessions';
5
- import { type TimeoutContext } from '../../timeout';
6
4
  import { MongoDBNamespace } from '../../utils';
7
5
  import { CommandOperation } from '../command';
8
6
  import { Aspect, defineAspects } from '../operation';
9
- import { type ClientBulkWriteCommandBuilder } from './command_builder';
7
+ import { type ClientBulkWriteCommand, type ClientBulkWriteCommandBuilder } from './command_builder';
10
8
  import { type ClientBulkWriteOptions } from './common';
11
9
 
12
10
  /**
@@ -14,6 +12,8 @@ import { type ClientBulkWriteOptions } from './common';
14
12
  * @internal
15
13
  */
16
14
  export class ClientBulkWriteOperation extends CommandOperation<ClientBulkWriteCursorResponse> {
15
+ override SERVER_COMMAND_RESPONSE_TYPE = ClientBulkWriteCursorResponse;
16
+
17
17
  commandBuilder: ClientBulkWriteCommandBuilder;
18
18
  override options: ClientBulkWriteOptions;
19
19
 
@@ -36,72 +36,28 @@ export class ClientBulkWriteOperation extends CommandOperation<ClientBulkWriteCu
36
36
  return this.commandBuilder.isBatchRetryable;
37
37
  }
38
38
 
39
- /**
40
- * Execute the command. Superclass will handle write concern, etc.
41
- * @param server - The server.
42
- * @param session - The session.
43
- * @returns The response.
44
- */
45
- override async execute(
46
- server: Server,
47
- session: ClientSession | undefined,
48
- timeoutContext: TimeoutContext
49
- ): Promise<ClientBulkWriteCursorResponse> {
50
- let command;
39
+ override handleOk(
40
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
41
+ ): ClientBulkWriteCursorResponse {
42
+ return response;
43
+ }
51
44
 
52
- if (server.description.type === ServerType.LoadBalancer) {
53
- if (session) {
54
- let connection;
55
- if (!session.pinnedConnection) {
56
- // Checkout a connection to build the command.
57
- connection = await server.pool.checkOut({ timeoutContext });
58
- // Pin the connection to the session so it get used to execute the command and we do not
59
- // perform a double check-in/check-out.
60
- session.pin(connection);
61
- } else {
62
- connection = session.pinnedConnection;
63
- }
64
- command = this.commandBuilder.buildBatch(
65
- connection.hello?.maxMessageSizeBytes,
66
- connection.hello?.maxWriteBatchSize,
67
- connection.hello?.maxBsonObjectSize
68
- );
69
- } else {
70
- throw new MongoClientBulkWriteExecutionError(
71
- 'Session provided to the client bulk write operation must be present.'
72
- );
73
- }
74
- } else {
75
- // At this point we have a server and the auto connect code has already
76
- // run in executeOperation, so the server description will be populated.
77
- // We can use that to build the command.
78
- if (
79
- !server.description.maxWriteBatchSize ||
80
- !server.description.maxMessageSizeBytes ||
81
- !server.description.maxBsonObjectSize
82
- ) {
83
- throw new MongoClientBulkWriteExecutionError(
84
- 'In order to execute a client bulk write, both maxWriteBatchSize, maxMessageSizeBytes and maxBsonObjectSize must be provided by the servers hello response.'
85
- );
86
- }
87
- command = this.commandBuilder.buildBatch(
88
- server.description.maxMessageSizeBytes,
89
- server.description.maxWriteBatchSize,
90
- server.description.maxBsonObjectSize
91
- );
92
- }
45
+ override buildCommandDocument(
46
+ connection: Connection,
47
+ _session?: ClientSession
48
+ ): ClientBulkWriteCommand {
49
+ const command = this.commandBuilder.buildBatch(
50
+ connection.description.maxMessageSizeBytes,
51
+ connection.description.maxWriteBatchSize,
52
+ connection.description.maxBsonObjectSize
53
+ );
93
54
 
94
- // Check after the batch is built if we cannot retry it and override the option.
55
+ // Check _after_ the batch is built if we cannot retry it and override the option.
95
56
  if (!this.canRetryWrite) {
96
57
  this.options.willRetryWrite = false;
97
58
  }
98
- return await super.executeCommand(
99
- server,
100
- session,
101
- command,
102
- timeoutContext,
103
- ClientBulkWriteCursorResponse
104
- );
59
+
60
+ return command;
105
61
  }
106
62
  }
107
63
 
@@ -1,5 +1,5 @@
1
+ import { type Connection } from '..';
1
2
  import type { BSONSerializeOptions, Document } from '../bson';
2
- import { type MongoDBResponseConstructor } from '../cmap/wire_protocol/responses';
3
3
  import { MongoInvalidArgumentError } from '../error';
4
4
  import {
5
5
  decorateWithExplain,
@@ -9,11 +9,10 @@ import {
9
9
  } from '../explain';
10
10
  import { ReadConcern } from '../read_concern';
11
11
  import type { ReadPreference } from '../read_preference';
12
- import type { Server } from '../sdam/server';
13
- import { MIN_SECONDARY_WRITE_WIRE_VERSION } from '../sdam/server_selection';
12
+ import type { ServerCommandOptions } from '../sdam/server';
14
13
  import type { ClientSession } from '../sessions';
15
14
  import { type TimeoutContext } from '../timeout';
16
- import { commandSupportsReadConcern, maxWireVersion, MongoDBNamespace } from '../utils';
15
+ import { commandSupportsReadConcern, MongoDBNamespace } from '../utils';
17
16
  import { WriteConcern, type WriteConcernOptions } from '../write_concern';
18
17
  import type { ReadConcernLike } from './../read_concern';
19
18
  import { AbstractOperation, Aspect, type OperationOptions } from './operation';
@@ -117,69 +116,47 @@ export abstract class CommandOperation<T> extends AbstractOperation<T> {
117
116
  return super.canRetryWrite;
118
117
  }
119
118
 
120
- public async executeCommand<T extends MongoDBResponseConstructor>(
121
- server: Server,
122
- session: ClientSession | undefined,
123
- cmd: Document,
124
- timeoutContext: TimeoutContext,
125
- responseType: T | undefined
126
- ): Promise<typeof responseType extends undefined ? Document : InstanceType<T>>;
127
-
128
- public async executeCommand(
129
- server: Server,
130
- session: ClientSession | undefined,
131
- cmd: Document,
132
- timeoutContext: TimeoutContext
133
- ): Promise<Document>;
134
-
135
- async executeCommand(
136
- server: Server,
137
- session: ClientSession | undefined,
138
- cmd: Document,
139
- timeoutContext: TimeoutContext,
140
- responseType?: MongoDBResponseConstructor
141
- ): Promise<Document> {
142
- this.server = server;
143
-
144
- const options = {
119
+ abstract buildCommandDocument(connection: Connection, session?: ClientSession): Document;
120
+
121
+ override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
122
+ return {
145
123
  ...this.options,
146
124
  ...this.bsonOptions,
147
125
  timeoutContext,
148
126
  readPreference: this.readPreference,
149
- session
127
+ session: this.session
150
128
  };
129
+ }
151
130
 
152
- const serverWireVersion = maxWireVersion(server);
153
- const inTransaction = this.session && this.session.inTransaction();
131
+ override buildCommand(connection: Connection, session?: ClientSession): Document {
132
+ const command = this.buildCommandDocument(connection, session);
154
133
 
155
- if (this.readConcern && commandSupportsReadConcern(cmd) && !inTransaction) {
156
- Object.assign(cmd, { readConcern: this.readConcern });
157
- }
134
+ const inTransaction = this.session && this.session.inTransaction();
158
135
 
159
- if (this.trySecondaryWrite && serverWireVersion < MIN_SECONDARY_WRITE_WIRE_VERSION) {
160
- options.omitReadPreference = true;
136
+ if (this.readConcern && commandSupportsReadConcern(command) && !inTransaction) {
137
+ Object.assign(command, { readConcern: this.readConcern });
161
138
  }
162
139
 
163
140
  if (this.writeConcern && this.hasAspect(Aspect.WRITE_OPERATION) && !inTransaction) {
164
- WriteConcern.apply(cmd, this.writeConcern);
141
+ WriteConcern.apply(command, this.writeConcern);
165
142
  }
166
143
 
167
144
  if (
168
- options.collation &&
169
- typeof options.collation === 'object' &&
145
+ this.options.collation &&
146
+ typeof this.options.collation === 'object' &&
170
147
  !this.hasAspect(Aspect.SKIP_COLLATION)
171
148
  ) {
172
- Object.assign(cmd, { collation: options.collation });
149
+ Object.assign(command, { collation: this.options.collation });
173
150
  }
174
151
 
175
- if (typeof options.maxTimeMS === 'number') {
176
- cmd.maxTimeMS = options.maxTimeMS;
152
+ if (typeof this.options.maxTimeMS === 'number') {
153
+ command.maxTimeMS = this.options.maxTimeMS;
177
154
  }
178
155
 
179
156
  if (this.hasAspect(Aspect.EXPLAINABLE) && this.explain) {
180
- cmd = decorateWithExplain(cmd, this.explain);
157
+ return decorateWithExplain(command, this.explain);
181
158
  }
182
159
 
183
- return await server.command(this.ns, cmd, options, responseType);
160
+ return command;
184
161
  }
185
162
  }
@@ -1,8 +1,8 @@
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
6
  import type { MongoDBNamespace } from '../utils';
7
7
  import { CommandOperation, type CommandOperationOptions } from './command';
8
8
  import { Aspect, defineAspects } from './operation';
@@ -23,6 +23,7 @@ export interface CountOptions extends CommandOperationOptions {
23
23
 
24
24
  /** @internal */
25
25
  export class CountOperation extends CommandOperation<number> {
26
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
26
27
  override options: CountOptions;
27
28
  collectionName?: string;
28
29
  query: Document;
@@ -39,11 +40,7 @@ export class CountOperation extends CommandOperation<number> {
39
40
  return 'count' as const;
40
41
  }
41
42
 
42
- override async execute(
43
- server: Server,
44
- session: ClientSession | undefined,
45
- timeoutContext: TimeoutContext
46
- ): Promise<number> {
43
+ override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
47
44
  const options = this.options;
48
45
  const cmd: Document = {
49
46
  count: this.collectionName,
@@ -66,8 +63,11 @@ export class CountOperation extends CommandOperation<number> {
66
63
  cmd.maxTimeMS = options.maxTimeMS;
67
64
  }
68
65
 
69
- const result = await super.executeCommand(server, session, cmd, timeoutContext);
70
- return result ? result.n : 0;
66
+ return cmd;
67
+ }
68
+
69
+ override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): number {
70
+ return response.getNumber('n') ?? 0;
71
71
  }
72
72
  }
73
73
 
@@ -1,16 +1,19 @@
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
- import { type TimeoutContext } from '../timeout';
13
+ import { TimeoutContext } from '../timeout';
14
+ import { maxWireVersion } from '../utils';
13
15
  import { CommandOperation, type CommandOperationOptions } from './command';
16
+ import { executeOperation } from './execute_operation';
14
17
  import { CreateIndexesOperation } from './indexes';
15
18
  import { Aspect, defineAspects } from './operation';
16
19
 
@@ -110,6 +113,7 @@ const INVALID_QE_VERSION =
110
113
 
111
114
  /** @internal */
112
115
  export class CreateCollectionOperation extends CommandOperation<Collection> {
116
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
113
117
  override options: CreateCollectionOptions;
114
118
  db: Db;
115
119
  name: string;
@@ -126,88 +130,92 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
126
130
  return 'create' as const;
127
131
  }
128
132
 
129
- override async execute(
130
- server: Server,
131
- session: ClientSession | undefined,
132
- timeoutContext: TimeoutContext
133
- ): Promise<Collection> {
134
- const db = this.db;
135
- const name = this.name;
136
- const options = this.options;
137
-
138
- const encryptedFields: Document | undefined =
139
- options.encryptedFields ??
140
- db.client.s.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
141
-
142
- if (encryptedFields) {
143
- // Creating a QE collection required min server of 7.0.0
144
- // TODO(NODE-5353): Get wire version information from connection.
145
- if (
146
- !server.loadBalanced &&
147
- server.description.maxWireVersion < MIN_SUPPORTED_QE_WIRE_VERSION
148
- ) {
149
- throw new MongoCompatibilityError(
150
- `${INVALID_QE_VERSION} The minimum server version required is ${MIN_SUPPORTED_QE_SERVER_VERSION}`
151
- );
152
- }
153
- // Create auxilliary collections for queryable encryption support.
154
- const escCollection = encryptedFields.escCollection ?? `enxcol_.${name}.esc`;
155
- const ecocCollection = encryptedFields.ecocCollection ?? `enxcol_.${name}.ecoc`;
156
-
157
- for (const collectionName of [escCollection, ecocCollection]) {
158
- const createOp = new CreateCollectionOperation(db, collectionName, {
159
- clusteredIndex: {
160
- key: { _id: 1 },
161
- unique: true
162
- }
163
- });
164
- await createOp.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
165
- }
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
+ }
141
+
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);
146
+ }
147
+ }
166
148
 
167
- if (!options.encryptedFields) {
168
- this.options = { ...this.options, encryptedFields };
149
+ export async function createCollections<TSchema extends Document>(
150
+ db: Db,
151
+ name: string,
152
+ options: CreateCollectionOptions
153
+ ): Promise<Collection<TSchema>> {
154
+ const timeoutContext = TimeoutContext.create({
155
+ session: options.session,
156
+ serverSelectionTimeoutMS: db.client.s.options.serverSelectionTimeoutMS,
157
+ waitQueueTimeoutMS: db.client.s.options.waitQueueTimeoutMS,
158
+ timeoutMS: options.timeoutMS
159
+ });
160
+
161
+ const encryptedFields: Document | undefined =
162
+ options.encryptedFields ??
163
+ db.client.s.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
164
+
165
+ if (encryptedFields) {
166
+ class CreateSupportingFLEv2CollectionOperation extends CreateCollectionOperation {
167
+ override buildCommandDocument(connection: Connection, session?: ClientSession): Document {
168
+ if (
169
+ !connection.description.loadBalanced &&
170
+ maxWireVersion(connection) < MIN_SUPPORTED_QE_WIRE_VERSION
171
+ ) {
172
+ throw new MongoCompatibilityError(
173
+ `${INVALID_QE_VERSION} The minimum server version required is ${MIN_SUPPORTED_QE_SERVER_VERSION}`
174
+ );
175
+ }
176
+
177
+ return super.buildCommandDocument(connection, session);
169
178
  }
170
179
  }
171
180
 
172
- const coll = await this.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
173
-
174
- if (encryptedFields) {
175
- // Create the required index for queryable encryption support.
176
- const createIndexOp = CreateIndexesOperation.fromIndexSpecification(
177
- db,
178
- name,
179
- { __safeContent__: 1 },
180
- {}
181
- );
182
- await createIndexOp.execute(server, session, timeoutContext);
181
+ // Create auxilliary collections for queryable encryption support.
182
+ const escCollection = encryptedFields.escCollection ?? `enxcol_.${name}.esc`;
183
+ const ecocCollection = encryptedFields.ecocCollection ?? `enxcol_.${name}.ecoc`;
184
+
185
+ for (const collectionName of [escCollection, ecocCollection]) {
186
+ const createOp = new CreateSupportingFLEv2CollectionOperation(db, collectionName, {
187
+ clusteredIndex: {
188
+ key: { _id: 1 },
189
+ unique: true
190
+ },
191
+ session: options.session
192
+ });
193
+ await executeOperation(db.client, createOp, timeoutContext);
183
194
  }
184
195
 
185
- return coll;
196
+ if (!options.encryptedFields) {
197
+ options = { ...options, encryptedFields };
198
+ }
186
199
  }
187
200
 
188
- private async executeWithoutEncryptedFieldsCheck(
189
- server: Server,
190
- session: ClientSession | undefined,
191
- timeoutContext: TimeoutContext
192
- ): Promise<Collection> {
193
- const db = this.db;
194
- const name = this.name;
195
- const options = this.options;
196
-
197
- const cmd: Document = { create: name };
198
- for (const n in options) {
199
- if (
200
- (options as any)[n] != null &&
201
- typeof (options as any)[n] !== 'function' &&
202
- !ILLEGAL_COMMAND_FIELDS.has(n)
203
- ) {
204
- cmd[n] = (options as any)[n];
205
- }
206
- }
207
- // otherwise just execute the command
208
- await super.executeCommand(server, session, cmd, timeoutContext);
209
- return new Collection(db, name, options);
201
+ const coll = await executeOperation(
202
+ db.client,
203
+ new CreateCollectionOperation(db, name, options),
204
+ timeoutContext
205
+ );
206
+
207
+ if (encryptedFields) {
208
+ // Create the required index for queryable encryption support.
209
+ const createIndexOp = CreateIndexesOperation.fromIndexSpecification(
210
+ db,
211
+ name,
212
+ { __safeContent__: 1 },
213
+ { session: options.session }
214
+ );
215
+ await executeOperation(db.client, createIndexOp, timeoutContext);
210
216
  }
217
+
218
+ return coll as unknown as Collection<TSchema>;
211
219
  }
212
220
 
213
221
  defineAspects(CreateCollectionOperation, [Aspect.WRITE_OPERATION]);