mongodb 6.18.0 → 6.19.0

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 +18 -18
  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
@@ -1,11 +1,9 @@
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
8
  import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command';
11
9
  import { Aspect, defineAspects, type Hint } from './operation';
@@ -43,7 +41,8 @@ export interface DeleteStatement {
43
41
  }
44
42
 
45
43
  /** @internal */
46
- export class DeleteOperation extends CommandOperation<DeleteResult> {
44
+ export class DeleteOperation extends CommandOperation<Document> {
45
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
47
46
  override options: DeleteOptions;
48
47
  statements: DeleteStatement[];
49
48
 
@@ -66,12 +65,9 @@ export class DeleteOperation extends CommandOperation<DeleteResult> {
66
65
  return this.statements.every(op => (op.limit != null ? op.limit > 0 : true));
67
66
  }
68
67
 
69
- override async execute(
70
- server: Server,
71
- session: ClientSession | undefined,
72
- timeoutContext: TimeoutContext
73
- ): Promise<DeleteResult> {
74
- const options = this.options ?? {};
68
+ override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
69
+ const options = this.options;
70
+
75
71
  const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
76
72
  const command: Document = {
77
73
  delete: this.ns.collection,
@@ -97,28 +93,23 @@ export class DeleteOperation extends CommandOperation<DeleteResult> {
97
93
  }
98
94
  }
99
95
 
100
- const res: TODO_NODE_3286 = await super.executeCommand(
101
- server,
102
- session,
103
- command,
104
- timeoutContext
105
- );
106
- return res;
96
+ return command;
107
97
  }
108
98
  }
109
99
 
110
100
  export class DeleteOneOperation extends DeleteOperation {
111
- constructor(collection: Collection, filter: Document, options: DeleteOptions) {
112
- super(collection.s.namespace, [makeDeleteStatement(filter, { ...options, limit: 1 })], options);
101
+ constructor(ns: MongoDBCollectionNamespace, filter: Document, options: DeleteOptions) {
102
+ super(ns, [makeDeleteStatement(filter, { ...options, limit: 1 })], options);
113
103
  }
114
104
 
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);
105
+ override handleOk(
106
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
107
+ ): DeleteResult {
108
+ const res = super.handleOk(response);
109
+
110
+ // @ts-expect-error Explain commands have broken TS
121
111
  if (this.explain) return res;
112
+
122
113
  if (res.code) throw new MongoServerError(res);
123
114
  if (res.writeErrors) throw new MongoServerError(res.writeErrors[0]);
124
115
 
@@ -129,17 +120,18 @@ export class DeleteOneOperation extends DeleteOperation {
129
120
  }
130
121
  }
131
122
  export class DeleteManyOperation extends DeleteOperation {
132
- constructor(collection: Collection, filter: Document, options: DeleteOptions) {
133
- super(collection.s.namespace, [makeDeleteStatement(filter, options)], options);
123
+ constructor(ns: MongoDBCollectionNamespace, filter: Document, options: DeleteOptions) {
124
+ super(ns, [makeDeleteStatement(filter, options)], options);
134
125
  }
135
126
 
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);
127
+ override handleOk(
128
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
129
+ ): DeleteResult {
130
+ const res = super.handleOk(response);
131
+
132
+ // @ts-expect-error Explain commands have broken TS
142
133
  if (this.explain) return res;
134
+
143
135
  if (res.code) throw new MongoServerError(res);
144
136
  if (res.writeErrors) throw new MongoServerError(res.writeErrors[0]);
145
137
 
@@ -1,9 +1,7 @@
1
- import type { Document } from '../bson';
1
+ import { type Document } from '../bson';
2
+ import { type Connection } from '../cmap/connection';
3
+ import { MongoDBResponse } from '../cmap/wire_protocol/responses';
2
4
  import type { Collection } from '../collection';
3
- import type { Server } from '../sdam/server';
4
- import type { ClientSession } from '../sessions';
5
- import { type TimeoutContext } from '../timeout';
6
- import { decorateWithCollation, decorateWithReadConcern } from '../utils';
7
5
  import { CommandOperation, type CommandOperationOptions } from './command';
8
6
  import { Aspect, defineAspects } from './operation';
9
7
 
@@ -27,7 +25,8 @@ export type DistinctOptions = CommandOperationOptions & {
27
25
  * Return a list of distinct values for the given key across a collection.
28
26
  * @internal
29
27
  */
30
- export class DistinctOperation extends CommandOperation<any[]> {
28
+ export class DistinctOperation extends CommandOperation<any[] | Document> {
29
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
31
30
  override options: DistinctOptions;
32
31
  collection: Collection;
33
32
  /** Field of the document to find distinct values for. */
@@ -56,48 +55,32 @@ export class DistinctOperation extends CommandOperation<any[]> {
56
55
  return 'distinct' as const;
57
56
  }
58
57
 
59
- override async execute(
60
- server: Server,
61
- session: ClientSession | undefined,
62
- timeoutContext: TimeoutContext
63
- ): Promise<any[]> {
64
- const coll = this.collection;
65
- const key = this.key;
66
- const query = this.query;
67
- const options = this.options;
68
-
69
- // Distinct command
70
- const cmd: Document = {
71
- distinct: coll.collectionName,
72
- key: key,
73
- query: query
58
+ override buildCommandDocument(_connection: Connection): Document {
59
+ const command: Document = {
60
+ distinct: this.collection.collectionName,
61
+ key: this.key,
62
+ query: this.query
74
63
  };
75
-
76
- // Add maxTimeMS if defined
77
- if (typeof options.maxTimeMS === 'number') {
78
- cmd.maxTimeMS = options.maxTimeMS;
79
- }
80
-
81
64
  // we check for undefined specifically here to allow falsy values
82
65
  // eslint-disable-next-line no-restricted-syntax
83
- if (typeof options.comment !== 'undefined') {
84
- cmd.comment = options.comment;
66
+ if (this.options.comment !== undefined) {
67
+ command.comment = this.options.comment;
85
68
  }
86
69
 
87
- if (options.hint != null) {
88
- cmd.hint = options.hint;
70
+ if (this.options.hint != null) {
71
+ command.hint = this.options.hint;
89
72
  }
90
73
 
91
- // Do we have a readConcern specified
92
- decorateWithReadConcern(cmd, coll, options);
93
-
94
- // Have we specified collation
95
- decorateWithCollation(cmd, coll, options);
96
-
97
- const result = await super.executeCommand(server, session, cmd, timeoutContext);
74
+ return command;
75
+ }
98
76
 
99
- // @ts-expect-error: Explain always returns a document
100
- return this.explain ? result : result.values;
77
+ override handleOk(
78
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
79
+ ): any[] | Document {
80
+ if (this.explain) {
81
+ return response.toObject(this.bsonOptions);
82
+ }
83
+ return response.toObject(this.bsonOptions).values;
101
84
  }
102
85
  }
103
86
 
@@ -1,10 +1,13 @@
1
+ import { type Connection, MongoServerError } from '..';
1
2
  import type { Document } from '../bson';
3
+ import { MongoDBResponse } from '../cmap/wire_protocol/responses';
4
+ import { CursorTimeoutContext } from '../cursor/abstract_cursor';
2
5
  import type { Db } from '../db';
3
- import { MONGODB_ERROR_CODES, MongoServerError } from '../error';
4
- import type { Server } from '../sdam/server';
6
+ import { MONGODB_ERROR_CODES } from '../error';
5
7
  import type { ClientSession } from '../sessions';
6
- import { type TimeoutContext } from '../timeout';
8
+ import { TimeoutContext } from '../timeout';
7
9
  import { CommandOperation, type CommandOperationOptions } from './command';
10
+ import { executeOperation } from './execute_operation';
8
11
  import { Aspect, defineAspects } from './operation';
9
12
 
10
13
  /** @public */
@@ -15,13 +18,13 @@ export interface DropCollectionOptions extends CommandOperationOptions {
15
18
 
16
19
  /** @internal */
17
20
  export class DropCollectionOperation extends CommandOperation<boolean> {
21
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
22
+
18
23
  override options: DropCollectionOptions;
19
- db: Db;
20
24
  name: string;
21
25
 
22
26
  constructor(db: Db, name: string, options: DropCollectionOptions = {}) {
23
27
  super(db, options);
24
- this.db = db;
25
28
  this.options = options;
26
29
  this.name = name;
27
30
  }
@@ -30,61 +33,74 @@ export class DropCollectionOperation extends CommandOperation<boolean> {
30
33
  return 'drop' as const;
31
34
  }
32
35
 
33
- override async execute(
34
- server: Server,
35
- session: ClientSession | undefined,
36
- timeoutContext: TimeoutContext
37
- ): Promise<boolean> {
38
- const db = this.db;
39
- const options = this.options;
40
- const name = this.name;
41
-
42
- const encryptedFieldsMap = db.client.s.options.autoEncryption?.encryptedFieldsMap;
43
- let encryptedFields: Document | undefined =
44
- options.encryptedFields ?? encryptedFieldsMap?.[`${db.databaseName}.${name}`];
45
-
46
- if (!encryptedFields && encryptedFieldsMap) {
47
- // If the MongoClient was configured with an encryptedFieldsMap,
48
- // and no encryptedFields config was available in it or explicitly
49
- // passed as an argument, the spec tells us to look one up using
50
- // listCollections().
51
- const listCollectionsResult = await db
52
- .listCollections({ name }, { nameOnly: false })
53
- .toArray();
54
- encryptedFields = listCollectionsResult?.[0]?.options?.encryptedFields;
55
- }
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 {
41
+ return true;
42
+ }
43
+ }
56
44
 
57
- if (encryptedFields) {
58
- const escCollection = encryptedFields.escCollection || `enxcol_.${name}.esc`;
59
- const ecocCollection = encryptedFields.ecocCollection || `enxcol_.${name}.ecoc`;
60
-
61
- for (const collectionName of [escCollection, ecocCollection]) {
62
- // Drop auxilliary collections, ignoring potential NamespaceNotFound errors.
63
- const dropOp = new DropCollectionOperation(db, collectionName);
64
- try {
65
- await dropOp.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
66
- } catch (err) {
67
- if (
68
- !(err instanceof MongoServerError) ||
69
- err.code !== MONGODB_ERROR_CODES.NamespaceNotFound
70
- ) {
71
- throw err;
72
- }
45
+ export async function dropCollections(
46
+ db: Db,
47
+ name: string,
48
+ options: DropCollectionOptions
49
+ ): Promise<boolean> {
50
+ const timeoutContext = TimeoutContext.create({
51
+ session: options.session,
52
+ serverSelectionTimeoutMS: db.client.s.options.serverSelectionTimeoutMS,
53
+ waitQueueTimeoutMS: db.client.s.options.waitQueueTimeoutMS,
54
+ timeoutMS: options.timeoutMS
55
+ });
56
+
57
+ const encryptedFieldsMap = db.client.s.options.autoEncryption?.encryptedFieldsMap;
58
+ let encryptedFields: Document | undefined =
59
+ options.encryptedFields ?? encryptedFieldsMap?.[`${db.databaseName}.${name}`];
60
+
61
+ if (!encryptedFields && encryptedFieldsMap) {
62
+ // If the MongoClient was configured with an encryptedFieldsMap,
63
+ // and no encryptedFields config was available in it or explicitly
64
+ // passed as an argument, the spec tells us to look one up using
65
+ // listCollections().
66
+ const listCollectionsResult = await db
67
+ .listCollections(
68
+ { name },
69
+ {
70
+ nameOnly: false,
71
+ session: options.session,
72
+ timeoutContext: new CursorTimeoutContext(timeoutContext, Symbol())
73
+ }
74
+ )
75
+ .toArray();
76
+ encryptedFields = listCollectionsResult?.[0]?.options?.encryptedFields;
77
+ }
78
+
79
+ if (encryptedFields) {
80
+ const escCollection = encryptedFields.escCollection || `enxcol_.${name}.esc`;
81
+ const ecocCollection = encryptedFields.ecocCollection || `enxcol_.${name}.ecoc`;
82
+
83
+ for (const collectionName of [escCollection, ecocCollection]) {
84
+ // Drop auxilliary collections, ignoring potential NamespaceNotFound errors.
85
+ const dropOp = new DropCollectionOperation(db, collectionName, options);
86
+ try {
87
+ await executeOperation(db.client, dropOp, timeoutContext);
88
+ } catch (err) {
89
+ if (
90
+ !(err instanceof MongoServerError) ||
91
+ err.code !== MONGODB_ERROR_CODES.NamespaceNotFound
92
+ ) {
93
+ throw err;
73
94
  }
74
95
  }
75
96
  }
76
-
77
- return await this.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
78
97
  }
79
98
 
80
- private async executeWithoutEncryptedFieldsCheck(
81
- server: Server,
82
- session: ClientSession | undefined,
83
- timeoutContext: TimeoutContext
84
- ): Promise<boolean> {
85
- await super.executeCommand(server, session, { drop: this.name }, timeoutContext);
86
- return true;
87
- }
99
+ return await executeOperation(
100
+ db.client,
101
+ new DropCollectionOperation(db, name, options),
102
+ timeoutContext
103
+ );
88
104
  }
89
105
 
90
106
  /** @public */
@@ -92,6 +108,7 @@ export type DropDatabaseOptions = CommandOperationOptions;
92
108
 
93
109
  /** @internal */
94
110
  export class DropDatabaseOperation extends CommandOperation<boolean> {
111
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
95
112
  override options: DropDatabaseOptions;
96
113
 
97
114
  constructor(db: Db, options: DropDatabaseOptions) {
@@ -102,12 +119,11 @@ export class DropDatabaseOperation extends CommandOperation<boolean> {
102
119
  return 'dropDatabase' as const;
103
120
  }
104
121
 
105
- override async execute(
106
- server: Server,
107
- session: ClientSession | undefined,
108
- timeoutContext: TimeoutContext
109
- ): Promise<boolean> {
110
- 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 {
111
127
  return true;
112
128
  }
113
129
  }
@@ -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 { CommandOperation, type CommandOperationOptions } from './command';
7
7
  import { Aspect, defineAspects } from './operation';
8
8
 
@@ -18,6 +18,7 @@ export interface EstimatedDocumentCountOptions extends CommandOperationOptions {
18
18
 
19
19
  /** @internal */
20
20
  export class EstimatedDocumentCountOperation extends CommandOperation<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
 
@@ -26,14 +26,16 @@ import type { Topology } from '../sdam/topology';
26
26
  import type { ClientSession } from '../sessions';
27
27
  import { TimeoutContext } from '../timeout';
28
28
  import { abortable, supportsRetryableWrites } from '../utils';
29
+ import { AggregateOperation } from './aggregate';
29
30
  import { AbstractOperation, Aspect } from './operation';
30
31
 
31
32
  const MMAPv1_RETRY_WRITES_ERROR_CODE = MONGODB_ERROR_CODES.IllegalOperation;
32
33
  const MMAPv1_RETRY_WRITES_ERROR_MESSAGE =
33
34
  'This MongoDB deployment does not support retryable writes. Please add retryWrites=false to your connection string.';
34
35
 
35
- type ResultTypeFromOperation<TOperation> =
36
- TOperation extends AbstractOperation<infer K> ? K : never;
36
+ type ResultTypeFromOperation<TOperation extends AbstractOperation> = ReturnType<
37
+ TOperation['handleOk']
38
+ >;
37
39
 
38
40
  /**
39
41
  * Executes the given operation with provided arguments.
@@ -56,7 +58,7 @@ type ResultTypeFromOperation<TOperation> =
56
58
  * @param operation - The operation to execute
57
59
  */
58
60
  export async function executeOperation<
59
- T extends AbstractOperation<TResult>,
61
+ T extends AbstractOperation,
60
62
  TResult = ResultTypeFromOperation<T>
61
63
  >(client: MongoClient, operation: T, timeoutContext?: TimeoutContext | null): Promise<TResult> {
62
64
  if (!(operation instanceof AbstractOperation)) {
@@ -85,6 +87,8 @@ export async function executeOperation<
85
87
  throw new MongoInvalidArgumentError('ClientSession must be from the same MongoClient');
86
88
  }
87
89
 
90
+ operation.session ??= session;
91
+
88
92
  const readPreference = operation.readPreference ?? ReadPreference.primary;
89
93
  const inTransaction = !!session?.inTransaction();
90
94
 
@@ -129,7 +133,7 @@ export async function executeOperation<
129
133
  * Connects a client if it has not yet been connected
130
134
  * @internal
131
135
  */
132
- async function autoConnect(client: MongoClient): Promise<Topology> {
136
+ export async function autoConnect(client: MongoClient): Promise<Topology> {
133
137
  if (client.topology == null) {
134
138
  if (client.s.hasBeenClosed) {
135
139
  throw new MongoNotConnectedError('Client must be connected before running operations');
@@ -176,10 +180,7 @@ type RetryOptions = {
176
180
  *
177
181
  * @param operation - The operation to execute
178
182
  * */
179
- async function tryOperation<
180
- T extends AbstractOperation<TResult>,
181
- TResult = ResultTypeFromOperation<T>
182
- >(
183
+ async function tryOperation<T extends AbstractOperation, TResult = ResultTypeFromOperation<T>>(
183
184
  operation: T,
184
185
  { topology, timeoutContext, session, readPreference }: RetryOptions
185
186
  ): Promise<TResult> {
@@ -190,7 +191,7 @@ async function tryOperation<
190
191
  // server selection to potentially force monitor checks if the server is
191
192
  // in an unknown state.
192
193
  selector = sameServerSelector(operation.server?.description);
193
- } else if (operation.trySecondaryWrite) {
194
+ } else if (operation instanceof AggregateOperation && operation.hasWriteStage) {
194
195
  // If operation should try to write to secondary use the custom server selector
195
196
  // otherwise provide the read preference.
196
197
  selector = secondaryWritableServerSelector(topology.commonWireVersion, readPreference);
@@ -248,8 +249,9 @@ async function tryOperation<
248
249
  if (hasWriteAspect && !isRetryableWriteError(previousOperationError))
249
250
  throw previousOperationError;
250
251
 
251
- if (hasReadAspect && !isRetryableReadError(previousOperationError))
252
+ if (hasReadAspect && !isRetryableReadError(previousOperationError)) {
252
253
  throw previousOperationError;
254
+ }
253
255
 
254
256
  if (
255
257
  previousOperationError instanceof MongoNetworkError &&
@@ -275,12 +277,20 @@ async function tryOperation<
275
277
  }
276
278
  }
277
279
 
280
+ operation.server = server;
281
+
278
282
  try {
279
283
  // If tries > 0 and we are command batching we need to reset the batch.
280
284
  if (tries > 0 && operation.hasAspect(Aspect.COMMAND_BATCHING)) {
281
285
  operation.resetBatch();
282
286
  }
283
- return await operation.execute(server, session, timeoutContext);
287
+
288
+ try {
289
+ const result = await server.command(operation, timeoutContext);
290
+ return operation.handleOk(result);
291
+ } catch (error) {
292
+ return operation.handleError(error);
293
+ }
284
294
  } catch (operationError) {
285
295
  if (!(operationError instanceof MongoError)) throw operationError;
286
296
  if (
@@ -2,14 +2,8 @@ import type { Document } from '../bson';
2
2
  import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/responses';
3
3
  import { type AbstractCursorOptions, type CursorTimeoutMode } from '../cursor/abstract_cursor';
4
4
  import { MongoInvalidArgumentError } from '../error';
5
- import {
6
- decorateWithExplain,
7
- type ExplainOptions,
8
- validateExplainTimeoutOptions
9
- } from '../explain';
10
- import { ReadConcern } from '../read_concern';
11
- import type { Server } from '../sdam/server';
12
- import type { ClientSession } from '../sessions';
5
+ import { type ExplainOptions } from '../explain';
6
+ import type { ServerCommandOptions } from '../sdam/server';
13
7
  import { formatSort, type Sort } from '../sort';
14
8
  import { type TimeoutContext } from '../timeout';
15
9
  import { type MongoDBNamespace, normalizeHintField } from '../utils';
@@ -81,8 +75,20 @@ export interface FindOptions<TSchema extends Document = Document>
81
75
  timeoutMode?: CursorTimeoutMode;
82
76
  }
83
77
 
78
+ /** @public */
79
+ export 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
+
84
88
  /** @internal */
85
89
  export class FindOperation extends CommandOperation<CursorResponse> {
90
+ override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
91
+
86
92
  /**
87
93
  * @remarks WriteConcern can still be present on the options because
88
94
  * we inherit options from the client/db/collection. The
@@ -106,39 +112,32 @@ export class FindOperation extends CommandOperation<CursorResponse> {
106
112
 
107
113
  // special case passing in an ObjectId as a filter
108
114
  this.filter = filter != null && filter._bsontype === 'ObjectId' ? { _id: filter } : filter;
115
+
116
+ this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? ExplainedCursorResponse : CursorResponse;
109
117
  }
110
118
 
111
119
  override get commandName() {
112
120
  return 'find' as const;
113
121
  }
114
122
 
115
- override async execute(
116
- server: Server,
117
- session: ClientSession | undefined,
118
- timeoutContext: TimeoutContext
119
- ): Promise<CursorResponse> {
120
- this.server = server;
121
-
122
- const options = this.options;
123
+ override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
124
+ return {
125
+ ...this.options,
126
+ ...this.bsonOptions,
127
+ documentsReturnedIn: 'firstBatch',
128
+ session: this.session,
129
+ timeoutContext
130
+ };
131
+ }
123
132
 
124
- let findCommand = makeFindCommand(this.ns, this.filter, options);
125
- if (this.explain) {
126
- validateExplainTimeoutOptions(this.options, this.explain);
127
- findCommand = decorateWithExplain(findCommand, this.explain);
128
- }
133
+ override handleOk(
134
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
135
+ ): CursorResponse {
136
+ return response;
137
+ }
129
138
 
130
- return await server.command(
131
- this.ns,
132
- findCommand,
133
- {
134
- ...this.options,
135
- ...this.bsonOptions,
136
- documentsReturnedIn: 'firstBatch',
137
- session,
138
- timeoutContext
139
- },
140
- this.explain ? ExplainedCursorResponse : CursorResponse
141
- );
139
+ override buildCommandDocument(): Document {
140
+ return makeFindCommand(this.ns, this.filter, this.options);
142
141
  }
143
142
  }
144
143
 
@@ -185,17 +184,15 @@ function makeFindCommand(ns: MongoDBNamespace, filter: Document, options: FindOp
185
184
 
186
185
  if (typeof options.batchSize === 'number') {
187
186
  if (options.batchSize < 0) {
188
- if (
189
- options.limit &&
190
- options.limit !== 0 &&
191
- Math.abs(options.batchSize) < Math.abs(options.limit)
192
- ) {
193
- findCommand.limit = -options.batchSize;
194
- }
195
-
196
- findCommand.singleBatch = true;
187
+ findCommand.limit = -options.batchSize;
197
188
  } else {
198
- findCommand.batchSize = options.batchSize;
189
+ if (options.batchSize === options.limit) {
190
+ // Spec dictates that if these are equal the batchSize should be one more than the
191
+ // limit to avoid leaving the cursor open.
192
+ findCommand.batchSize = options.batchSize + 1;
193
+ } else {
194
+ findCommand.batchSize = options.batchSize;
195
+ }
199
196
  }
200
197
  }
201
198
 
@@ -209,15 +206,6 @@ function makeFindCommand(ns: MongoDBNamespace, filter: Document, options: FindOp
209
206
  findCommand.comment = options.comment;
210
207
  }
211
208
 
212
- if (typeof options.maxTimeMS === 'number') {
213
- findCommand.maxTimeMS = options.maxTimeMS;
214
- }
215
-
216
- const readConcern = ReadConcern.fromOptions(options);
217
- if (readConcern) {
218
- findCommand.readConcern = readConcern.toJSON();
219
- }
220
-
221
209
  if (options.max) {
222
210
  findCommand.max = options.max;
223
211
  }
@@ -255,11 +243,6 @@ function makeFindCommand(ns: MongoDBNamespace, filter: Document, options: FindOp
255
243
  if (typeof options.allowPartialResults === 'boolean') {
256
244
  findCommand.allowPartialResults = options.allowPartialResults;
257
245
  }
258
-
259
- if (options.collation) {
260
- findCommand.collation = options.collation;
261
- }
262
-
263
246
  if (typeof options.allowDiskUse === 'boolean') {
264
247
  findCommand.allowDiskUse = options.allowDiskUse;
265
248
  }