mongodb 6.3.0 → 6.4.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 (221) hide show
  1. package/lib/bson.js +2 -1
  2. package/lib/bson.js.map +1 -1
  3. package/lib/bulk/common.js +14 -9
  4. package/lib/bulk/common.js.map +1 -1
  5. package/lib/change_stream.js +4 -2
  6. package/lib/change_stream.js.map +1 -1
  7. package/lib/client-side-encryption/state_machine.js +58 -52
  8. package/lib/client-side-encryption/state_machine.js.map +1 -1
  9. package/lib/cmap/auth/auth_provider.js +4 -0
  10. package/lib/cmap/auth/auth_provider.js.map +1 -1
  11. package/lib/cmap/auth/gssapi.js +1 -1
  12. package/lib/cmap/auth/gssapi.js.map +1 -1
  13. package/lib/cmap/auth/mongo_credentials.js.map +1 -1
  14. package/lib/cmap/auth/mongocr.js +2 -2
  15. package/lib/cmap/auth/mongocr.js.map +1 -1
  16. package/lib/cmap/auth/mongodb_aws.js +58 -55
  17. package/lib/cmap/auth/mongodb_aws.js.map +1 -1
  18. package/lib/cmap/auth/mongodb_oidc/callback_workflow.js +2 -2
  19. package/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map +1 -1
  20. package/lib/cmap/auth/mongodb_oidc/service_workflow.js +1 -1
  21. package/lib/cmap/auth/mongodb_oidc/service_workflow.js.map +1 -1
  22. package/lib/cmap/auth/plain.js +1 -1
  23. package/lib/cmap/auth/plain.js.map +1 -1
  24. package/lib/cmap/auth/scram.js +5 -7
  25. package/lib/cmap/auth/scram.js.map +1 -1
  26. package/lib/cmap/auth/x509.js +1 -1
  27. package/lib/cmap/auth/x509.js.map +1 -1
  28. package/lib/cmap/command_monitoring_events.js +6 -3
  29. package/lib/cmap/command_monitoring_events.js.map +1 -1
  30. package/lib/cmap/commands.js +2 -0
  31. package/lib/cmap/commands.js.map +1 -1
  32. package/lib/cmap/connect.js +88 -110
  33. package/lib/cmap/connect.js.map +1 -1
  34. package/lib/cmap/connection.js +280 -726
  35. package/lib/cmap/connection.js.map +1 -1
  36. package/lib/cmap/connection_pool.js +35 -95
  37. package/lib/cmap/connection_pool.js.map +1 -1
  38. package/lib/cmap/stream_description.js +19 -0
  39. package/lib/cmap/stream_description.js.map +1 -1
  40. package/lib/cmap/wire_protocol/compression.js.map +1 -1
  41. package/lib/cmap/wire_protocol/on_data.js +112 -0
  42. package/lib/cmap/wire_protocol/on_data.js.map +1 -0
  43. package/lib/collection.js +11 -3
  44. package/lib/collection.js.map +1 -1
  45. package/lib/connection_string.js +34 -2
  46. package/lib/connection_string.js.map +1 -1
  47. package/lib/constants.js +22 -2
  48. package/lib/constants.js.map +1 -1
  49. package/lib/cursor/abstract_cursor.js +5 -1
  50. package/lib/cursor/abstract_cursor.js.map +1 -1
  51. package/lib/error.js +7 -7
  52. package/lib/error.js.map +1 -1
  53. package/lib/index.js +9 -1
  54. package/lib/index.js.map +1 -1
  55. package/lib/mongo_client.js +8 -3
  56. package/lib/mongo_client.js.map +1 -1
  57. package/lib/mongo_client_auth_providers.js +55 -0
  58. package/lib/mongo_client_auth_providers.js.map +1 -0
  59. package/lib/mongo_logger.js +205 -27
  60. package/lib/mongo_logger.js.map +1 -1
  61. package/lib/mongo_types.js +26 -0
  62. package/lib/mongo_types.js.map +1 -1
  63. package/lib/operations/aggregate.js +3 -0
  64. package/lib/operations/aggregate.js.map +1 -1
  65. package/lib/operations/bulk_write.js +3 -0
  66. package/lib/operations/bulk_write.js.map +1 -1
  67. package/lib/operations/collections.js +3 -0
  68. package/lib/operations/collections.js.map +1 -1
  69. package/lib/operations/command.js +1 -1
  70. package/lib/operations/command.js.map +1 -1
  71. package/lib/operations/count.js +3 -0
  72. package/lib/operations/count.js.map +1 -1
  73. package/lib/operations/create_collection.js +3 -0
  74. package/lib/operations/create_collection.js.map +1 -1
  75. package/lib/operations/delete.js +3 -0
  76. package/lib/operations/delete.js.map +1 -1
  77. package/lib/operations/distinct.js +3 -0
  78. package/lib/operations/distinct.js.map +1 -1
  79. package/lib/operations/drop.js +6 -0
  80. package/lib/operations/drop.js.map +1 -1
  81. package/lib/operations/estimated_document_count.js +3 -0
  82. package/lib/operations/estimated_document_count.js.map +1 -1
  83. package/lib/operations/execute_operation.js +35 -9
  84. package/lib/operations/execute_operation.js.map +1 -1
  85. package/lib/operations/find.js +4 -1
  86. package/lib/operations/find.js.map +1 -1
  87. package/lib/operations/find_and_modify.js +5 -1
  88. package/lib/operations/find_and_modify.js.map +1 -1
  89. package/lib/operations/get_more.js +4 -1
  90. package/lib/operations/get_more.js.map +1 -1
  91. package/lib/operations/indexes.js +21 -0
  92. package/lib/operations/indexes.js.map +1 -1
  93. package/lib/operations/insert.js +6 -0
  94. package/lib/operations/insert.js.map +1 -1
  95. package/lib/operations/is_capped.js +3 -0
  96. package/lib/operations/is_capped.js.map +1 -1
  97. package/lib/operations/kill_cursors.js +4 -1
  98. package/lib/operations/kill_cursors.js.map +1 -1
  99. package/lib/operations/list_collections.js +3 -0
  100. package/lib/operations/list_collections.js.map +1 -1
  101. package/lib/operations/list_databases.js +3 -0
  102. package/lib/operations/list_databases.js.map +1 -1
  103. package/lib/operations/operation.js.map +1 -1
  104. package/lib/operations/options_operation.js +3 -0
  105. package/lib/operations/options_operation.js.map +1 -1
  106. package/lib/operations/profiling_level.js +3 -0
  107. package/lib/operations/profiling_level.js.map +1 -1
  108. package/lib/operations/remove_user.js +3 -0
  109. package/lib/operations/remove_user.js.map +1 -1
  110. package/lib/operations/rename.js +3 -0
  111. package/lib/operations/rename.js.map +1 -1
  112. package/lib/operations/run_command.js +8 -2
  113. package/lib/operations/run_command.js.map +1 -1
  114. package/lib/operations/search_indexes/create.js +4 -1
  115. package/lib/operations/search_indexes/create.js.map +1 -1
  116. package/lib/operations/search_indexes/drop.js +4 -1
  117. package/lib/operations/search_indexes/drop.js.map +1 -1
  118. package/lib/operations/search_indexes/update.js +4 -1
  119. package/lib/operations/search_indexes/update.js.map +1 -1
  120. package/lib/operations/set_profiling_level.js +3 -0
  121. package/lib/operations/set_profiling_level.js.map +1 -1
  122. package/lib/operations/stats.js +3 -0
  123. package/lib/operations/stats.js.map +1 -1
  124. package/lib/operations/update.js +3 -0
  125. package/lib/operations/update.js.map +1 -1
  126. package/lib/operations/validate_collection.js +3 -0
  127. package/lib/operations/validate_collection.js.map +1 -1
  128. package/lib/sdam/events.js +18 -0
  129. package/lib/sdam/events.js.map +1 -1
  130. package/lib/sdam/monitor.js +86 -71
  131. package/lib/sdam/monitor.js.map +1 -1
  132. package/lib/sdam/server.js +92 -98
  133. package/lib/sdam/server.js.map +1 -1
  134. package/lib/sdam/server_selection.js +13 -5
  135. package/lib/sdam/server_selection.js.map +1 -1
  136. package/lib/sdam/server_selection_events.js +85 -0
  137. package/lib/sdam/server_selection_events.js.map +1 -0
  138. package/lib/sdam/topology.js +61 -18
  139. package/lib/sdam/topology.js.map +1 -1
  140. package/lib/sessions.js +11 -9
  141. package/lib/sessions.js.map +1 -1
  142. package/lib/utils.js +25 -17
  143. package/lib/utils.js.map +1 -1
  144. package/mongodb.d.ts +131 -57
  145. package/package.json +28 -27
  146. package/src/bson.ts +2 -0
  147. package/src/bulk/common.ts +29 -22
  148. package/src/change_stream.ts +11 -5
  149. package/src/client-side-encryption/state_machine.ts +77 -62
  150. package/src/cmap/auth/auth_provider.ts +4 -0
  151. package/src/cmap/auth/gssapi.ts +1 -1
  152. package/src/cmap/auth/mongo_credentials.ts +2 -2
  153. package/src/cmap/auth/mongocr.ts +2 -6
  154. package/src/cmap/auth/mongodb_aws.ts +69 -64
  155. package/src/cmap/auth/mongodb_oidc/callback_workflow.ts +2 -2
  156. package/src/cmap/auth/mongodb_oidc/service_workflow.ts +1 -1
  157. package/src/cmap/auth/plain.ts +1 -1
  158. package/src/cmap/auth/scram.ts +7 -9
  159. package/src/cmap/auth/x509.ts +1 -5
  160. package/src/cmap/command_monitoring_events.ts +32 -4
  161. package/src/cmap/commands.ts +4 -0
  162. package/src/cmap/connect.ts +119 -159
  163. package/src/cmap/connection.ts +408 -961
  164. package/src/cmap/connection_pool.ts +93 -155
  165. package/src/cmap/stream_description.ts +21 -1
  166. package/src/cmap/wire_protocol/compression.ts +1 -2
  167. package/src/cmap/wire_protocol/on_data.ts +132 -0
  168. package/src/collection.ts +14 -6
  169. package/src/connection_string.ts +49 -3
  170. package/src/constants.ts +20 -0
  171. package/src/cursor/abstract_cursor.ts +7 -1
  172. package/src/error.ts +9 -9
  173. package/src/index.ts +33 -12
  174. package/src/mongo_client.ts +20 -7
  175. package/src/mongo_client_auth_providers.ts +54 -0
  176. package/src/mongo_logger.ts +376 -50
  177. package/src/mongo_types.ts +58 -3
  178. package/src/operations/aggregate.ts +4 -0
  179. package/src/operations/bulk_write.ts +4 -0
  180. package/src/operations/collections.ts +4 -0
  181. package/src/operations/command.ts +1 -1
  182. package/src/operations/count.ts +4 -0
  183. package/src/operations/create_collection.ts +4 -0
  184. package/src/operations/delete.ts +4 -0
  185. package/src/operations/distinct.ts +4 -0
  186. package/src/operations/drop.ts +8 -0
  187. package/src/operations/estimated_document_count.ts +4 -0
  188. package/src/operations/execute_operation.ts +28 -31
  189. package/src/operations/find.ts +5 -1
  190. package/src/operations/find_and_modify.ts +7 -5
  191. package/src/operations/get_more.ts +4 -1
  192. package/src/operations/indexes.ts +29 -0
  193. package/src/operations/insert.ts +8 -0
  194. package/src/operations/is_capped.ts +4 -0
  195. package/src/operations/kill_cursors.ts +5 -1
  196. package/src/operations/list_collections.ts +4 -0
  197. package/src/operations/list_databases.ts +4 -0
  198. package/src/operations/operation.ts +4 -0
  199. package/src/operations/options_operation.ts +3 -0
  200. package/src/operations/profiling_level.ts +4 -0
  201. package/src/operations/remove_user.ts +4 -0
  202. package/src/operations/rename.ts +4 -0
  203. package/src/operations/run_command.ts +10 -2
  204. package/src/operations/search_indexes/create.ts +5 -1
  205. package/src/operations/search_indexes/drop.ts +5 -1
  206. package/src/operations/search_indexes/update.ts +5 -1
  207. package/src/operations/set_profiling_level.ts +4 -0
  208. package/src/operations/stats.ts +4 -0
  209. package/src/operations/update.ts +4 -0
  210. package/src/operations/validate_collection.ts +4 -0
  211. package/src/sdam/events.ts +31 -3
  212. package/src/sdam/monitor.ts +119 -97
  213. package/src/sdam/server.ts +113 -152
  214. package/src/sdam/server_selection.ts +21 -13
  215. package/src/sdam/server_selection_events.ts +142 -0
  216. package/src/sdam/topology.ts +200 -46
  217. package/src/sessions.ts +33 -32
  218. package/src/utils.ts +28 -32
  219. package/lib/cmap/message_stream.js +0 -149
  220. package/lib/cmap/message_stream.js.map +0 -1
  221. package/src/cmap/message_stream.ts +0 -220
@@ -12,7 +12,16 @@ import type {
12
12
  ObjectId,
13
13
  Timestamp
14
14
  } from './bson';
15
- import type { MongoLoggableComponent, MongoLogger } from './mongo_logger';
15
+ import { type CommandStartedEvent } from './cmap/command_monitoring_events';
16
+ import {
17
+ type LoggableCommandFailedEvent,
18
+ type LoggableCommandSucceededEvent,
19
+ type LoggableServerHeartbeatFailedEvent,
20
+ type LoggableServerHeartbeatStartedEvent,
21
+ type LoggableServerHeartbeatSucceededEvent,
22
+ MongoLoggableComponent,
23
+ type MongoLogger
24
+ } from './mongo_logger';
16
25
  import type { Sort } from './sort';
17
26
 
18
27
  /** @internal */
@@ -237,7 +246,11 @@ export type SetFields<TSchema> = ({
237
246
  readonly [key in KeysOfAType<TSchema, ReadonlyArray<any> | undefined>]?:
238
247
  | OptionalId<Flatten<TSchema[key]>>
239
248
  | AddToSetOperators<Array<OptionalId<Flatten<TSchema[key]>>>>;
240
- } & NotAcceptedFields<TSchema, ReadonlyArray<any> | undefined>) & {
249
+ } & IsAny<
250
+ TSchema[keyof TSchema],
251
+ object,
252
+ NotAcceptedFields<TSchema, ReadonlyArray<any> | undefined>
253
+ >) & {
241
254
  readonly [key: string]: AddToSetOperators<any> | any;
242
255
  };
243
256
 
@@ -405,13 +418,55 @@ export class TypedEventEmitter<Events extends EventsDescription> extends EventEm
405
418
  /** @internal */
406
419
  protected component?: MongoLoggableComponent;
407
420
  /** @internal */
408
- protected emitAndLog<EventKey extends keyof Events>(
421
+ emitAndLog<EventKey extends keyof Events>(
409
422
  event: EventKey | symbol,
410
423
  ...args: Parameters<Events[EventKey]>
411
424
  ): void {
412
425
  this.emit(event, ...args);
413
426
  if (this.component) this.mongoLogger?.debug(this.component, args[0]);
414
427
  }
428
+ /** @internal */
429
+ emitAndLogHeartbeat<EventKey extends keyof Events>(
430
+ event: EventKey | symbol,
431
+ topologyId: number,
432
+ serverConnectionId?: number | '<monitor>',
433
+ ...args: Parameters<Events[EventKey]>
434
+ ): void {
435
+ this.emit(event, ...args);
436
+ if (this.component) {
437
+ const loggableHeartbeatEvent:
438
+ | LoggableServerHeartbeatFailedEvent
439
+ | LoggableServerHeartbeatSucceededEvent
440
+ | LoggableServerHeartbeatStartedEvent = {
441
+ topologyId: topologyId,
442
+ serverConnectionId: serverConnectionId ?? null,
443
+ ...args[0]
444
+ };
445
+ this.mongoLogger?.debug(this.component, loggableHeartbeatEvent);
446
+ }
447
+ }
448
+ /** @internal */
449
+ emitAndLogCommand<EventKey extends keyof Events>(
450
+ monitorCommands: boolean,
451
+ event: EventKey | symbol,
452
+ databaseName: string,
453
+ connectionEstablished: boolean,
454
+ ...args: Parameters<Events[EventKey]>
455
+ ): void {
456
+ if (monitorCommands) {
457
+ this.emit(event, ...args);
458
+ }
459
+ if (connectionEstablished) {
460
+ const loggableCommandEvent:
461
+ | CommandStartedEvent
462
+ | LoggableCommandFailedEvent
463
+ | LoggableCommandSucceededEvent = {
464
+ databaseName: databaseName,
465
+ ...args[0]
466
+ };
467
+ this.mongoLogger?.debug(MongoLoggableComponent.COMMAND, loggableCommandEvent);
468
+ }
469
+ }
415
470
  }
416
471
 
417
472
  /** @public */
@@ -82,6 +82,10 @@ export class AggregateOperation<T = Document> extends CommandOperation<T> {
82
82
  }
83
83
  }
84
84
 
85
+ override get commandName() {
86
+ return 'aggregate' as const;
87
+ }
88
+
85
89
  override get canRetryRead(): boolean {
86
90
  return !this.hasWriteStage;
87
91
  }
@@ -26,6 +26,10 @@ export class BulkWriteOperation extends AbstractOperation<BulkWriteResult> {
26
26
  this.operations = operations;
27
27
  }
28
28
 
29
+ override get commandName() {
30
+ return 'bulkWrite' as const;
31
+ }
32
+
29
33
  override async execute(
30
34
  server: Server,
31
35
  session: ClientSession | undefined
@@ -19,6 +19,10 @@ export class CollectionsOperation extends AbstractOperation<Collection[]> {
19
19
  this.db = db;
20
20
  }
21
21
 
22
+ override get commandName() {
23
+ return 'listCollections' as const;
24
+ }
25
+
22
26
  override async execute(
23
27
  server: Server,
24
28
  session: ClientSession | undefined
@@ -152,6 +152,6 @@ export abstract class CommandOperation<T> extends AbstractOperation<T> {
152
152
  cmd = decorateWithExplain(cmd, this.explain);
153
153
  }
154
154
 
155
- return server.commandAsync(this.ns, cmd, options);
155
+ return server.command(this.ns, cmd, options);
156
156
  }
157
157
  }
@@ -32,6 +32,10 @@ export class CountOperation extends CommandOperation<number> {
32
32
  this.query = filter;
33
33
  }
34
34
 
35
+ override get commandName() {
36
+ return 'count' as const;
37
+ }
38
+
35
39
  override async execute(server: Server, session: ClientSession | undefined): Promise<number> {
36
40
  const options = this.options;
37
41
  const cmd: Document = {
@@ -120,6 +120,10 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
120
120
  this.name = name;
121
121
  }
122
122
 
123
+ override get commandName() {
124
+ return 'create' as const;
125
+ }
126
+
123
127
  override async execute(server: Server, session: ClientSession | undefined): Promise<Collection> {
124
128
  const db = this.db;
125
129
  const name = this.name;
@@ -53,6 +53,10 @@ export class DeleteOperation extends CommandOperation<DeleteResult> {
53
53
  this.statements = statements;
54
54
  }
55
55
 
56
+ override get commandName() {
57
+ return 'delete' as const;
58
+ }
59
+
56
60
  override get canRetryWrite(): boolean {
57
61
  if (super.canRetryWrite === false) {
58
62
  return false;
@@ -38,6 +38,10 @@ export class DistinctOperation extends CommandOperation<any[]> {
38
38
  this.query = query;
39
39
  }
40
40
 
41
+ override get commandName() {
42
+ return 'distinct' as const;
43
+ }
44
+
41
45
  override async execute(server: Server, session: ClientSession | undefined): Promise<any[]> {
42
46
  const coll = this.collection;
43
47
  const key = this.key;
@@ -25,6 +25,10 @@ export class DropCollectionOperation extends CommandOperation<boolean> {
25
25
  this.name = name;
26
26
  }
27
27
 
28
+ override get commandName() {
29
+ return 'drop' as const;
30
+ }
31
+
28
32
  override async execute(server: Server, session: ClientSession | undefined): Promise<boolean> {
29
33
  const db = this.db;
30
34
  const options = this.options;
@@ -88,6 +92,10 @@ export class DropDatabaseOperation extends CommandOperation<boolean> {
88
92
  super(db, options);
89
93
  this.options = options;
90
94
  }
95
+ override get commandName() {
96
+ return 'dropDatabase' as const;
97
+ }
98
+
91
99
  override async execute(server: Server, session: ClientSession | undefined): Promise<boolean> {
92
100
  await super.executeCommand(server, session, { dropDatabase: 1 });
93
101
  return true;
@@ -26,6 +26,10 @@ export class EstimatedDocumentCountOperation extends CommandOperation<number> {
26
26
  this.collectionName = collection.collectionName;
27
27
  }
28
28
 
29
+ override get commandName() {
30
+ return 'count' as const;
31
+ }
32
+
29
33
  override async execute(server: Server, session: ClientSession | undefined): Promise<number> {
30
34
  const cmd: Document = { count: this.collectionName };
31
35
 
@@ -18,6 +18,7 @@ import {
18
18
  import type { MongoClient } from '../mongo_client';
19
19
  import { ReadPreference } from '../read_preference';
20
20
  import type { Server } from '../sdam/server';
21
+ import type { ServerDescription } from '../sdam/server_description';
21
22
  import {
22
23
  sameServerSelector,
23
24
  secondaryWritableServerSelector,
@@ -25,7 +26,7 @@ import {
25
26
  } from '../sdam/server_selection';
26
27
  import type { Topology } from '../sdam/topology';
27
28
  import type { ClientSession } from '../sessions';
28
- import { type Callback, maybeCallback, supportsRetryableWrites } from '../utils';
29
+ import { supportsRetryableWrites } from '../utils';
29
30
  import { AbstractOperation, Aspect } from './operation';
30
31
 
31
32
  const MMAPv1_RETRY_WRITES_ERROR_CODE = MONGODB_ERROR_CODES.IllegalOperation;
@@ -51,36 +52,23 @@ export interface ExecutionResult {
51
52
  * @internal
52
53
  *
53
54
  * @remarks
54
- * This method reduces large amounts of duplication in the entire codebase by providing
55
- * a single point for determining whether callbacks or promises should be used. Additionally
56
- * it allows for a single point of entry to provide features such as implicit sessions, which
55
+ * Allows for a single point of entry to provide features such as implicit sessions, which
57
56
  * are required by the Driver Sessions specification in the event that a ClientSession is
58
- * not provided
57
+ * not provided.
59
58
  *
60
- * @param topology - The topology to execute this operation on
59
+ * The expectation is that this function:
60
+ * - Connects the MongoClient if it has not already been connected
61
+ * - Creates a session if none is provided and cleans up the session it creates
62
+ * - Selects a server based on readPreference or various factors
63
+ * - Retries an operation if it fails for certain errors, see {@link retryOperation}
64
+ *
65
+ * @typeParam T - The operation's type
66
+ * @typeParam TResult - The type of the operation's result, calculated from T
67
+ *
68
+ * @param client - The MongoClient to execute this operation with
61
69
  * @param operation - The operation to execute
62
- * @param callback - The command result callback
63
70
  */
64
- export function executeOperation<
65
- T extends AbstractOperation<TResult>,
66
- TResult = ResultTypeFromOperation<T>
67
- >(client: MongoClient, operation: T): Promise<TResult>;
68
- export function executeOperation<
69
- T extends AbstractOperation<TResult>,
70
- TResult = ResultTypeFromOperation<T>
71
- >(client: MongoClient, operation: T, callback: Callback<TResult>): void;
72
- export function executeOperation<
73
- T extends AbstractOperation<TResult>,
74
- TResult = ResultTypeFromOperation<T>
75
- >(client: MongoClient, operation: T, callback?: Callback<TResult>): Promise<TResult> | void;
76
- export function executeOperation<
77
- T extends AbstractOperation<TResult>,
78
- TResult = ResultTypeFromOperation<T>
79
- >(client: MongoClient, operation: T, callback?: Callback<TResult>): Promise<TResult> | void {
80
- return maybeCallback(() => executeOperationAsync(client, operation), callback);
81
- }
82
-
83
- async function executeOperationAsync<
71
+ export async function executeOperation<
84
72
  T extends AbstractOperation<TResult>,
85
73
  TResult = ResultTypeFromOperation<T>
86
74
  >(client: MongoClient, operation: T): Promise<TResult> {
@@ -151,7 +139,10 @@ async function executeOperationAsync<
151
139
  selector = readPreference;
152
140
  }
153
141
 
154
- const server = await topology.selectServerAsync(selector, { session });
142
+ const server = await topology.selectServerAsync(selector, {
143
+ session,
144
+ operationName: operation.commandName
145
+ });
155
146
 
156
147
  if (session == null) {
157
148
  // No session also means it is not retryable, early exit
@@ -193,7 +184,8 @@ async function executeOperationAsync<
193
184
  return await retryOperation(operation, operationError, {
194
185
  session,
195
186
  topology,
196
- selector
187
+ selector,
188
+ previousServer: server.description
197
189
  });
198
190
  }
199
191
  throw operationError;
@@ -209,6 +201,7 @@ type RetryOptions = {
209
201
  session: ClientSession;
210
202
  topology: Topology;
211
203
  selector: ReadPreference | ServerSelector;
204
+ previousServer: ServerDescription;
212
205
  };
213
206
 
214
207
  async function retryOperation<
@@ -217,7 +210,7 @@ async function retryOperation<
217
210
  >(
218
211
  operation: T,
219
212
  originalError: MongoError,
220
- { session, topology, selector }: RetryOptions
213
+ { session, topology, selector, previousServer }: RetryOptions
221
214
  ): Promise<TResult> {
222
215
  const isWriteOperation = operation.hasAspect(Aspect.WRITE_OPERATION);
223
216
  const isReadOperation = operation.hasAspect(Aspect.READ_OPERATION);
@@ -251,7 +244,11 @@ async function retryOperation<
251
244
  }
252
245
 
253
246
  // select a new server, and attempt to retry the operation
254
- const server = await topology.selectServerAsync(selector, { session });
247
+ const server = await topology.selectServerAsync(selector, {
248
+ session,
249
+ operationName: operation.commandName,
250
+ previousServer
251
+ });
255
252
 
256
253
  if (isWriteOperation && !supportsRetryableWrites(server)) {
257
254
  throw new MongoUnexpectedServerResponseError(
@@ -97,6 +97,10 @@ export class FindOperation extends CommandOperation<Document> {
97
97
  this.filter = filter != null && filter._bsontype === 'ObjectId' ? { _id: filter } : filter;
98
98
  }
99
99
 
100
+ override get commandName() {
101
+ return 'find' as const;
102
+ }
103
+
100
104
  override async execute(server: Server, session: ClientSession | undefined): Promise<Document> {
101
105
  this.server = server;
102
106
 
@@ -107,7 +111,7 @@ export class FindOperation extends CommandOperation<Document> {
107
111
  findCommand = decorateWithExplain(findCommand, this.explain);
108
112
  }
109
113
 
110
- return server.commandAsync(this.ns, findCommand, {
114
+ return server.command(this.ns, findCommand, {
111
115
  ...this.options,
112
116
  ...this.bsonOptions,
113
117
  documentsReturnedIn: 'firstBatch',
@@ -52,8 +52,7 @@ export interface FindOneAndReplaceOptions extends CommandOperationOptions {
52
52
  /** Map of parameter names and values that can be accessed using $$var (requires MongoDB 5.0). */
53
53
  let?: Document;
54
54
  /**
55
- * Return the ModifyResult instead of the modified document. Defaults to true
56
- * but will default to false in the next major version.
55
+ * Return the ModifyResult instead of the modified document. Defaults to false
57
56
  */
58
57
  includeResultMetadata?: boolean;
59
58
  }
@@ -77,8 +76,7 @@ export interface FindOneAndUpdateOptions extends CommandOperationOptions {
77
76
  /** Map of parameter names and values that can be accessed using $$var (requires MongoDB 5.0). */
78
77
  let?: Document;
79
78
  /**
80
- * Return the ModifyResult instead of the modified document. Defaults to true
81
- * but will default to false in the next major version.
79
+ * Return the ModifyResult instead of the modified document. Defaults to false
82
80
  */
83
81
  includeResultMetadata?: boolean;
84
82
  }
@@ -121,7 +119,7 @@ function configureFindAndModifyCmdBaseUpdateOpts(
121
119
  }
122
120
 
123
121
  /** @internal */
124
- class FindAndModifyOperation extends CommandOperation<Document> {
122
+ export class FindAndModifyOperation extends CommandOperation<Document> {
125
123
  override options: FindOneAndReplaceOptions | FindOneAndUpdateOptions | FindOneAndDeleteOptions;
126
124
  cmdBase: FindAndModifyCmdBase;
127
125
  collection: Collection;
@@ -178,6 +176,10 @@ class FindAndModifyOperation extends CommandOperation<Document> {
178
176
  this.query = query;
179
177
  }
180
178
 
179
+ override get commandName() {
180
+ return 'findAndModify' as const;
181
+ }
182
+
181
183
  override async execute(server: Server, session: ClientSession | undefined): Promise<Document> {
182
184
  const coll = this.collection;
183
185
  const query = this.query;
@@ -48,6 +48,9 @@ export class GetMoreOperation extends AbstractOperation {
48
48
  this.server = server;
49
49
  }
50
50
 
51
+ override get commandName() {
52
+ return 'getMore' as const;
53
+ }
51
54
  /**
52
55
  * Although there is a server already associated with the get more operation, the signature
53
56
  * for execute passes a server so we will just use that one.
@@ -93,7 +96,7 @@ export class GetMoreOperation extends AbstractOperation {
93
96
  ...this.options
94
97
  };
95
98
 
96
- return server.commandAsync(this.ns, getMoreCmd, commandOptions);
99
+ return server.command(this.ns, getMoreCmd, commandOptions);
97
100
  }
98
101
  }
99
102
 
@@ -186,6 +186,10 @@ export class IndexesOperation extends AbstractOperation<Document[]> {
186
186
  this.collection = collection;
187
187
  }
188
188
 
189
+ override get commandName() {
190
+ return 'listIndexes' as const;
191
+ }
192
+
189
193
  override async execute(_server: Server, session: ClientSession | undefined): Promise<Document[]> {
190
194
  const coll = this.collection;
191
195
  const options = this.options;
@@ -235,6 +239,10 @@ export class CreateIndexesOperation<
235
239
  });
236
240
  }
237
241
 
242
+ override get commandName() {
243
+ return 'createIndexes';
244
+ }
245
+
238
246
  override async execute(server: Server, session: ClientSession | undefined): Promise<T> {
239
247
  const options = this.options;
240
248
  const indexes = this.indexes;
@@ -272,6 +280,7 @@ export class CreateIndexOperation extends CreateIndexesOperation<string> {
272
280
  ) {
273
281
  super(parent, collectionName, [makeIndexSpec(indexSpec, options)], options);
274
282
  }
283
+
275
284
  override async execute(server: Server, session: ClientSession | undefined): Promise<string> {
276
285
  const indexNames = await super.execute(server, session);
277
286
  return indexNames[0];
@@ -295,6 +304,10 @@ export class EnsureIndexOperation extends CreateIndexOperation {
295
304
  this.collectionName = collectionName;
296
305
  }
297
306
 
307
+ override get commandName() {
308
+ return 'listIndexes';
309
+ }
310
+
298
311
  override async execute(server: Server, session: ClientSession | undefined): Promise<string> {
299
312
  const indexName = this.indexes[0].name;
300
313
  const indexes = await this.db
@@ -328,6 +341,10 @@ export class DropIndexOperation extends CommandOperation<Document> {
328
341
  this.indexName = indexName;
329
342
  }
330
343
 
344
+ override get commandName() {
345
+ return 'dropIndexes' as const;
346
+ }
347
+
331
348
  override async execute(server: Server, session: ClientSession | undefined): Promise<Document> {
332
349
  const cmd = { dropIndexes: this.collection.collectionName, index: this.indexName };
333
350
  return super.executeCommand(server, session, cmd);
@@ -360,6 +377,10 @@ export class ListIndexesOperation extends CommandOperation<Document> {
360
377
  this.collectionNamespace = collection.s.namespace;
361
378
  }
362
379
 
380
+ override get commandName() {
381
+ return 'listIndexes' as const;
382
+ }
383
+
363
384
  override async execute(server: Server, session: ClientSession | undefined): Promise<Document> {
364
385
  const serverWireVersion = maxWireVersion(server);
365
386
 
@@ -394,6 +415,10 @@ export class IndexExistsOperation extends AbstractOperation<boolean> {
394
415
  this.indexes = indexes;
395
416
  }
396
417
 
418
+ override get commandName() {
419
+ return 'listIndexes' as const;
420
+ }
421
+
397
422
  override async execute(server: Server, session: ClientSession | undefined): Promise<boolean> {
398
423
  const coll = this.collection;
399
424
  const indexes = this.indexes;
@@ -423,6 +448,10 @@ export class IndexInformationOperation extends AbstractOperation<Document> {
423
448
  this.name = name;
424
449
  }
425
450
 
451
+ override get commandName() {
452
+ return 'listIndexes' as const;
453
+ }
454
+
426
455
  override async execute(server: Server, session: ClientSession | undefined): Promise<Document> {
427
456
  const db = this.db;
428
457
  const name = this.name;
@@ -24,6 +24,10 @@ export class InsertOperation extends CommandOperation<Document> {
24
24
  this.documents = documents;
25
25
  }
26
26
 
27
+ override get commandName() {
28
+ return 'insert' as const;
29
+ }
30
+
27
31
  override async execute(server: Server, session: ClientSession | undefined): Promise<Document> {
28
32
  const options = this.options ?? {};
29
33
  const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
@@ -114,6 +118,10 @@ export class InsertManyOperation extends AbstractOperation<InsertManyResult> {
114
118
  this.docs = docs;
115
119
  }
116
120
 
121
+ override get commandName() {
122
+ return 'insert' as const;
123
+ }
124
+
117
125
  override async execute(
118
126
  server: Server,
119
127
  session: ClientSession | undefined
@@ -15,6 +15,10 @@ export class IsCappedOperation extends AbstractOperation<boolean> {
15
15
  this.collection = collection;
16
16
  }
17
17
 
18
+ override get commandName() {
19
+ return 'listCollections' as const;
20
+ }
21
+
18
22
  override async execute(server: Server, session: ClientSession | undefined): Promise<boolean> {
19
23
  const coll = this.collection;
20
24
  const [collection] = await coll.s.db
@@ -25,6 +25,10 @@ export class KillCursorsOperation extends AbstractOperation {
25
25
  this.server = server;
26
26
  }
27
27
 
28
+ override get commandName() {
29
+ return 'killCursors' as const;
30
+ }
31
+
28
32
  override async execute(server: Server, session: ClientSession | undefined): Promise<void> {
29
33
  if (server !== this.server) {
30
34
  throw new MongoRuntimeError('Killcursor must run on the same server operation began on');
@@ -42,7 +46,7 @@ export class KillCursorsOperation extends AbstractOperation {
42
46
  cursors: [this.cursorId]
43
47
  };
44
48
  try {
45
- await server.commandAsync(this.ns, killCursorsCommand, { session });
49
+ await server.command(this.ns, killCursorsCommand, { session });
46
50
  } catch {
47
51
  // The driver should never emit errors from killCursors, this is spec-ed behavior
48
52
  }
@@ -47,6 +47,10 @@ export class ListCollectionsOperation extends CommandOperation<Document> {
47
47
  }
48
48
  }
49
49
 
50
+ override get commandName() {
51
+ return 'listCollections' as const;
52
+ }
53
+
50
54
  override async execute(server: Server, session: ClientSession | undefined): Promise<Document> {
51
55
  return super.executeCommand(server, session, this.generateCommand(maxWireVersion(server)));
52
56
  }
@@ -35,6 +35,10 @@ export class ListDatabasesOperation extends CommandOperation<ListDatabasesResult
35
35
  this.ns = new MongoDBNamespace('admin', '$cmd');
36
36
  }
37
37
 
38
+ override get commandName() {
39
+ return 'listDatabases' as const;
40
+ }
41
+
38
42
  override async execute(
39
43
  server: Server,
40
44
  session: ClientSession | undefined
@@ -75,6 +75,10 @@ export abstract class AbstractOperation<TResult = any> {
75
75
  this.trySecondaryWrite = false;
76
76
  }
77
77
 
78
+ /** Must match the first key of the command object sent to the server.
79
+ Command name should be stateless (should not use 'this' keyword) */
80
+ abstract get commandName(): string;
81
+
78
82
  abstract execute(server: Server, session: ClientSession | undefined): Promise<TResult>;
79
83
 
80
84
  hasAspect(aspect: symbol): boolean {
@@ -15,6 +15,9 @@ export class OptionsOperation extends AbstractOperation<Document> {
15
15
  this.options = options;
16
16
  this.collection = collection;
17
17
  }
18
+ override get commandName() {
19
+ return 'listCollections' as const;
20
+ }
18
21
 
19
22
  override async execute(server: Server, session: ClientSession | undefined): Promise<Document> {
20
23
  const coll = this.collection;
@@ -16,6 +16,10 @@ export class ProfilingLevelOperation extends CommandOperation<string> {
16
16
  this.options = options;
17
17
  }
18
18
 
19
+ override get commandName() {
20
+ return 'profile' as const;
21
+ }
22
+
19
23
  override async execute(server: Server, session: ClientSession | undefined): Promise<string> {
20
24
  const doc = await super.executeCommand(server, session, { profile: -1 });
21
25
  if (doc.ok === 1) {
@@ -18,6 +18,10 @@ export class RemoveUserOperation extends CommandOperation<boolean> {
18
18
  this.username = username;
19
19
  }
20
20
 
21
+ override get commandName() {
22
+ return 'dropUser' as const;
23
+ }
24
+
21
25
  override async execute(server: Server, session: ClientSession | undefined): Promise<boolean> {
22
26
  await super.executeCommand(server, session, { dropUser: this.username });
23
27
  return true;
@@ -25,6 +25,10 @@ export class RenameOperation extends CommandOperation<Document> {
25
25
  this.ns = new MongoDBNamespace('admin', '$cmd');
26
26
  }
27
27
 
28
+ override get commandName(): string {
29
+ return 'renameCollection' as const;
30
+ }
31
+
28
32
  override async execute(server: Server, session: ClientSession | undefined): Promise<Collection> {
29
33
  // Build the command
30
34
  const renameCollection = this.collection.namespace;
@@ -22,9 +22,13 @@ export class RunCommandOperation<T = Document> extends AbstractOperation<T> {
22
22
  this.ns = parent.s.namespace.withCollection('$cmd');
23
23
  }
24
24
 
25
+ override get commandName() {
26
+ return 'runCommand' as const;
27
+ }
28
+
25
29
  override async execute(server: Server, session: ClientSession | undefined): Promise<T> {
26
30
  this.server = server;
27
- return server.commandAsync(this.ns, this.command, {
31
+ return server.command(this.ns, this.command, {
28
32
  ...this.options,
29
33
  readPreference: this.readPreference,
30
34
  session
@@ -44,9 +48,13 @@ export class RunAdminCommandOperation<T = Document> extends AbstractOperation<T>
44
48
  this.ns = new MongoDBNamespace('admin', '$cmd');
45
49
  }
46
50
 
51
+ override get commandName() {
52
+ return 'runCommand' as const;
53
+ }
54
+
47
55
  override async execute(server: Server, session: ClientSession | undefined): Promise<T> {
48
56
  this.server = server;
49
- return server.commandAsync(this.ns, this.command, {
57
+ return server.command(this.ns, this.command, {
50
58
  ...this.options,
51
59
  readPreference: this.readPreference,
52
60
  session