mongodb 6.18.0-dev.20250805.sha.ff9a7858 → 6.18.0-dev.20250806.sha.e628296a

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 (53) hide show
  1. package/lib/beta.d.ts +2 -1
  2. package/lib/cmap/connection.js.map +1 -1
  3. package/lib/cursor/aggregation_cursor.js +2 -1
  4. package/lib/cursor/aggregation_cursor.js.map +1 -1
  5. package/lib/cursor/explainable_cursor.js +36 -0
  6. package/lib/cursor/explainable_cursor.js.map +1 -0
  7. package/lib/cursor/find_cursor.js +2 -1
  8. package/lib/cursor/find_cursor.js.map +1 -1
  9. package/lib/explain.js +1 -33
  10. package/lib/explain.js.map +1 -1
  11. package/lib/index.js +6 -6
  12. package/lib/index.js.map +1 -1
  13. package/lib/operations/aggregate.js +10 -8
  14. package/lib/operations/aggregate.js.map +1 -1
  15. package/lib/operations/command.js +0 -9
  16. package/lib/operations/command.js.map +1 -1
  17. package/lib/operations/execute_operation.js +2 -1
  18. package/lib/operations/execute_operation.js.map +1 -1
  19. package/lib/operations/find.js +13 -24
  20. package/lib/operations/find.js.map +1 -1
  21. package/lib/operations/get_more.js +11 -12
  22. package/lib/operations/get_more.js.map +1 -1
  23. package/lib/operations/indexes.js +8 -4
  24. package/lib/operations/indexes.js.map +1 -1
  25. package/lib/operations/kill_cursors.js +14 -16
  26. package/lib/operations/kill_cursors.js.map +1 -1
  27. package/lib/operations/list_collections.js +8 -7
  28. package/lib/operations/list_collections.js.map +1 -1
  29. package/lib/operations/operation.js +0 -1
  30. package/lib/operations/operation.js.map +1 -1
  31. package/lib/sdam/server.js +6 -12
  32. package/lib/sdam/server.js.map +1 -1
  33. package/lib/sdam/topology.js +3 -2
  34. package/lib/sdam/topology.js.map +1 -1
  35. package/mongodb.d.ts +2 -1
  36. package/package.json +1 -1
  37. package/src/cmap/connection.ts +0 -1
  38. package/src/cursor/aggregation_cursor.ts +1 -1
  39. package/src/cursor/explainable_cursor.ts +51 -0
  40. package/src/cursor/find_cursor.ts +1 -1
  41. package/src/explain.ts +0 -49
  42. package/src/index.ts +2 -2
  43. package/src/operations/aggregate.ts +21 -22
  44. package/src/operations/command.ts +1 -12
  45. package/src/operations/execute_operation.ts +2 -1
  46. package/src/operations/find.ts +28 -49
  47. package/src/operations/get_more.ts +18 -20
  48. package/src/operations/indexes.ts +13 -8
  49. package/src/operations/kill_cursors.ts +22 -23
  50. package/src/operations/list_collections.ts +15 -23
  51. package/src/operations/operation.ts +0 -3
  52. package/src/sdam/server.ts +8 -13
  53. package/src/sdam/topology.ts +4 -3
@@ -1,11 +1,11 @@
1
- import type { Long } from '../bson';
1
+ import type { Document, Long } from '../bson';
2
+ import { type Connection } from '../cmap/connection';
2
3
  import { CursorResponse } from '../cmap/wire_protocol/responses';
3
4
  import { MongoRuntimeError } from '../error';
4
- import type { Server } from '../sdam/server';
5
- import type { ClientSession } from '../sessions';
5
+ import type { Server, ServerCommandOptions } from '../sdam/server';
6
6
  import { type TimeoutContext } from '../timeout';
7
7
  import { maxWireVersion, type MongoDBNamespace } from '../utils';
8
- import { AbstractOperation, Aspect, defineAspects, type OperationOptions } from './operation';
8
+ import { Aspect, defineAspects, ModernizedOperation, type OperationOptions } from './operation';
9
9
 
10
10
  /** @internal */
11
11
  export interface GetMoreOptions extends OperationOptions {
@@ -37,7 +37,8 @@ export interface GetMoreCommand {
37
37
  }
38
38
 
39
39
  /** @internal */
40
- export class GetMoreOperation extends AbstractOperation {
40
+ export class GetMoreOperation extends ModernizedOperation<CursorResponse> {
41
+ override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
41
42
  cursorId: Long;
42
43
  override options: GetMoreOptions;
43
44
 
@@ -53,19 +54,8 @@ export class GetMoreOperation extends AbstractOperation {
53
54
  override get commandName() {
54
55
  return 'getMore' as const;
55
56
  }
56
- /**
57
- * Although there is a server already associated with the get more operation, the signature
58
- * for execute passes a server so we will just use that one.
59
- */
60
- override async execute(
61
- server: Server,
62
- _session: ClientSession | undefined,
63
- timeoutContext: TimeoutContext
64
- ): Promise<CursorResponse> {
65
- if (server !== this.server) {
66
- throw new MongoRuntimeError('Getmore must run on the same server operation began on');
67
- }
68
57
 
58
+ override buildCommand(connection: Connection): Document {
69
59
  if (this.cursorId == null || this.cursorId.isZero()) {
70
60
  throw new MongoRuntimeError('Unable to iterate cursor with no id');
71
61
  }
@@ -92,18 +82,26 @@ export class GetMoreOperation extends AbstractOperation {
92
82
 
93
83
  // we check for undefined specifically here to allow falsy values
94
84
  // eslint-disable-next-line no-restricted-syntax
95
- if (this.options.comment !== undefined && maxWireVersion(server) >= 9) {
85
+ if (this.options.comment !== undefined && maxWireVersion(connection) >= 9) {
96
86
  getMoreCmd.comment = this.options.comment;
97
87
  }
98
88
 
99
- const commandOptions = {
89
+ return getMoreCmd;
90
+ }
91
+
92
+ override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
93
+ return {
100
94
  returnFieldSelector: null,
101
95
  documentsReturnedIn: 'nextBatch',
102
96
  timeoutContext,
103
97
  ...this.options
104
98
  };
99
+ }
105
100
 
106
- return await server.command(this.ns, getMoreCmd, commandOptions, CursorResponse);
101
+ override handleOk(
102
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
103
+ ): CursorResponse {
104
+ return response;
107
105
  }
108
106
  }
109
107
 
@@ -1,4 +1,5 @@
1
1
  import type { Document } from '../bson';
2
+ import { type Connection } from '../cmap/connection';
2
3
  import { CursorResponse } from '../cmap/wire_protocol/responses';
3
4
  import type { Collection } from '../collection';
4
5
  import { type AbstractCursorOptions } from '../cursor/abstract_cursor';
@@ -12,6 +13,7 @@ import {
12
13
  type CollationOptions,
13
14
  CommandOperation,
14
15
  type CommandOperationOptions,
16
+ ModernizedCommandOperation,
15
17
  type OperationParent
16
18
  } from './command';
17
19
  import { Aspect, defineAspects } from './operation';
@@ -366,7 +368,8 @@ export type ListIndexesOptions = AbstractCursorOptions & {
366
368
  };
367
369
 
368
370
  /** @internal */
369
- export class ListIndexesOperation extends CommandOperation<CursorResponse> {
371
+ export class ListIndexesOperation extends ModernizedCommandOperation<CursorResponse> {
372
+ override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
370
373
  /**
371
374
  * @remarks WriteConcern can still be present on the options because
372
375
  * we inherit options from the client/db/collection. The
@@ -389,12 +392,8 @@ export class ListIndexesOperation extends CommandOperation<CursorResponse> {
389
392
  return 'listIndexes' as const;
390
393
  }
391
394
 
392
- override async execute(
393
- server: Server,
394
- session: ClientSession | undefined,
395
- timeoutContext: TimeoutContext
396
- ): Promise<CursorResponse> {
397
- const serverWireVersion = maxWireVersion(server);
395
+ override buildCommandDocument(connection: Connection): Document {
396
+ const serverWireVersion = maxWireVersion(connection);
398
397
 
399
398
  const cursor = this.options.batchSize ? { batchSize: this.options.batchSize } : {};
400
399
 
@@ -406,7 +405,13 @@ export class ListIndexesOperation extends CommandOperation<CursorResponse> {
406
405
  command.comment = this.options.comment;
407
406
  }
408
407
 
409
- return await super.executeCommand(server, session, command, timeoutContext, CursorResponse);
408
+ return command;
409
+ }
410
+
411
+ override handleOk(
412
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
413
+ ): CursorResponse {
414
+ return response;
410
415
  }
411
416
  }
412
417
 
@@ -1,10 +1,12 @@
1
1
  import type { Long } from '../bson';
2
- import { MongoRuntimeError } from '../error';
3
- import type { Server } from '../sdam/server';
2
+ import { type Connection } from '../cmap/connection';
3
+ import { MongoDBResponse } from '../cmap/wire_protocol/responses';
4
+ import { type MongoError, MongoRuntimeError } from '../error';
5
+ import type { Server, ServerCommandOptions } from '../sdam/server';
4
6
  import type { ClientSession } from '../sessions';
5
7
  import { type TimeoutContext } from '../timeout';
6
- import { type MongoDBNamespace, squashError } from '../utils';
7
- import { AbstractOperation, Aspect, defineAspects, type OperationOptions } from './operation';
8
+ import { type MongoDBNamespace } from '../utils';
9
+ import { Aspect, defineAspects, ModernizedOperation, type OperationOptions } from './operation';
8
10
 
9
11
  /**
10
12
  * https://www.mongodb.com/docs/manual/reference/command/killCursors/
@@ -16,7 +18,8 @@ interface KillCursorsCommand {
16
18
  comment?: unknown;
17
19
  }
18
20
 
19
- export class KillCursorsOperation extends AbstractOperation {
21
+ export class KillCursorsOperation extends ModernizedOperation<void> {
22
+ override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
20
23
  cursorId: Long;
21
24
 
22
25
  constructor(cursorId: Long, ns: MongoDBNamespace, server: Server, options: OperationOptions) {
@@ -30,15 +33,7 @@ export class KillCursorsOperation extends AbstractOperation {
30
33
  return 'killCursors' as const;
31
34
  }
32
35
 
33
- override async execute(
34
- server: Server,
35
- session: ClientSession | undefined,
36
- timeoutContext: TimeoutContext
37
- ): Promise<void> {
38
- if (server !== this.server) {
39
- throw new MongoRuntimeError('Killcursor must run on the same server operation began on');
40
- }
41
-
36
+ override buildCommand(_connection: Connection, _session?: ClientSession): KillCursorsCommand {
42
37
  const killCursors = this.ns.collection;
43
38
  if (killCursors == null) {
44
39
  // Cursors should have adopted the namespace returned by MongoDB
@@ -50,15 +45,19 @@ export class KillCursorsOperation extends AbstractOperation {
50
45
  killCursors,
51
46
  cursors: [this.cursorId]
52
47
  };
53
- try {
54
- await server.command(this.ns, killCursorsCommand, {
55
- session,
56
- timeoutContext
57
- });
58
- } catch (error) {
59
- // The driver should never emit errors from killCursors, this is spec-ed behavior
60
- squashError(error);
61
- }
48
+
49
+ return killCursorsCommand;
50
+ }
51
+
52
+ override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
53
+ return {
54
+ session: this.session,
55
+ timeoutContext
56
+ };
57
+ }
58
+
59
+ override handleError(_error: MongoError): void {
60
+ // The driver should never emit errors from killCursors, this is spec-ed behavior
62
61
  }
63
62
  }
64
63
 
@@ -1,13 +1,11 @@
1
+ import { type Connection } from '..';
1
2
  import type { Binary, Document } from '../bson';
2
- import { CursorResponse } from '../cmap/wire_protocol/responses';
3
+ import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/responses';
3
4
  import { type CursorTimeoutContext, type CursorTimeoutMode } from '../cursor/abstract_cursor';
4
5
  import type { Db } from '../db';
5
6
  import { type Abortable } from '../mongo_types';
6
- import type { Server } from '../sdam/server';
7
- import type { ClientSession } from '../sessions';
8
- import { type TimeoutContext } from '../timeout';
9
7
  import { maxWireVersion } from '../utils';
10
- import { CommandOperation, type CommandOperationOptions } from './command';
8
+ import { type CommandOperationOptions, ModernizedCommandOperation } from './command';
11
9
  import { Aspect, defineAspects } from './operation';
12
10
 
13
11
  /** @public */
@@ -28,7 +26,8 @@ export interface ListCollectionsOptions
28
26
  }
29
27
 
30
28
  /** @internal */
31
- export class ListCollectionsOperation extends CommandOperation<CursorResponse> {
29
+ export class ListCollectionsOperation extends ModernizedCommandOperation<CursorResponse> {
30
+ override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
32
31
  /**
33
32
  * @remarks WriteConcern can still be present on the options because
34
33
  * we inherit options from the client/db/collection. The
@@ -56,28 +55,15 @@ export class ListCollectionsOperation extends CommandOperation<CursorResponse> {
56
55
  if (typeof this.options.batchSize === 'number') {
57
56
  this.batchSize = this.options.batchSize;
58
57
  }
58
+
59
+ this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? ExplainedCursorResponse : CursorResponse;
59
60
  }
60
61
 
61
62
  override get commandName() {
62
63
  return 'listCollections' as const;
63
64
  }
64
65
 
65
- override async execute(
66
- server: Server,
67
- session: ClientSession | undefined,
68
- timeoutContext: TimeoutContext
69
- ): Promise<CursorResponse> {
70
- return await super.executeCommand(
71
- server,
72
- session,
73
- this.generateCommand(maxWireVersion(server)),
74
- timeoutContext,
75
- CursorResponse
76
- );
77
- }
78
-
79
- /* This is here for the purpose of unit testing the final command that gets sent. */
80
- generateCommand(wireVersion: number): Document {
66
+ override buildCommandDocument(connection: Connection): Document {
81
67
  const command: Document = {
82
68
  listCollections: 1,
83
69
  filter: this.filter,
@@ -88,12 +74,18 @@ export class ListCollectionsOperation extends CommandOperation<CursorResponse> {
88
74
 
89
75
  // we check for undefined specifically here to allow falsy values
90
76
  // eslint-disable-next-line no-restricted-syntax
91
- if (wireVersion >= 9 && this.options.comment !== undefined) {
77
+ if (maxWireVersion(connection) >= 9 && this.options.comment !== undefined) {
92
78
  command.comment = this.options.comment;
93
79
  }
94
80
 
95
81
  return command;
96
82
  }
83
+
84
+ override handleOk(
85
+ response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
86
+ ): CursorResponse {
87
+ return response;
88
+ }
97
89
  }
98
90
 
99
91
  /** @public */
@@ -33,7 +33,6 @@ export interface OperationOptions extends BSONSerializeOptions {
33
33
 
34
34
  /** @internal Hints to `executeOperation` that this operation should not unpin on an ended transaction */
35
35
  bypassPinningCheck?: boolean;
36
- omitReadPreference?: boolean;
37
36
 
38
37
  /** @internal Hint to `executeOperation` to omit maxTimeMS */
39
38
  omitMaxTimeMS?: boolean;
@@ -57,7 +56,6 @@ export abstract class AbstractOperation<TResult = any> {
57
56
  readPreference: ReadPreference;
58
57
  server!: Server;
59
58
  bypassPinningCheck: boolean;
60
- trySecondaryWrite: boolean;
61
59
 
62
60
  // BSON serialization options
63
61
  bsonOptions?: BSONSerializeOptions;
@@ -83,7 +81,6 @@ export abstract class AbstractOperation<TResult = any> {
83
81
 
84
82
  this.options = options;
85
83
  this.bypassPinningCheck = !!options.bypassPinningCheck;
86
- this.trySecondaryWrite = false;
87
84
  }
88
85
 
89
86
  /** Must match the first key of the command object sent to the server.
@@ -37,6 +37,7 @@ import {
37
37
  } from '../error';
38
38
  import type { ServerApi } from '../mongo_client';
39
39
  import { type Abortable, TypedEventEmitter } from '../mongo_types';
40
+ import { AggregateOperation } from '../operations/aggregate';
40
41
  import type { GetMoreOptions } from '../operations/get_more';
41
42
  import { type ModernizedOperation } from '../operations/operation';
42
43
  import type { ClientSession } from '../sessions';
@@ -68,6 +69,7 @@ import type {
68
69
  } from './events';
69
70
  import { Monitor, type MonitorOptions } from './monitor';
70
71
  import { compareTopologyVersion, ServerDescription } from './server_description';
72
+ import { MIN_SECONDARY_WRITE_WIRE_VERSION } from './server_selection';
71
73
  import type { Topology } from './topology';
72
74
 
73
75
  const stateTransition = makeStateMachine({
@@ -111,6 +113,7 @@ export type ServerEvents = {
111
113
  /** @internal */
112
114
  export type ServerCommandOptions = Omit<CommandOptions, 'timeoutContext' | 'socketTimeoutMS'> & {
113
115
  timeoutContext: TimeoutContext;
116
+ returnFieldSelector?: Document | null;
114
117
  } & Abortable;
115
118
 
116
119
  /** @internal */
@@ -310,11 +313,11 @@ export class Server extends TypedEventEmitter<ServerEvents> {
310
313
 
311
314
  options.directConnection = this.topology.s.options.directConnection;
312
315
 
313
- // There are cases where we need to flag the read preference not to get sent in
314
- // the command, such as pre-5.0 servers attempting to perform an aggregate write
315
- // with a non-primary read preference. In this case the effective read preference
316
- // (primary) is not the same as the provided and must be removed completely.
317
- if (options.omitReadPreference) {
316
+ const omitReadPreference =
317
+ operation instanceof AggregateOperation &&
318
+ operation.hasWriteStage &&
319
+ maxWireVersion(conn) < MIN_SECONDARY_WRITE_WIRE_VERSION;
320
+ if (omitReadPreference) {
318
321
  delete options.readPreference;
319
322
  }
320
323
 
@@ -401,14 +404,6 @@ export class Server extends TypedEventEmitter<ServerEvents> {
401
404
 
402
405
  options.directConnection = this.topology.s.options.directConnection;
403
406
 
404
- // There are cases where we need to flag the read preference not to get sent in
405
- // the command, such as pre-5.0 servers attempting to perform an aggregate write
406
- // with a non-primary read preference. In this case the effective read preference
407
- // (primary) is not the same as the provided and must be removed completely.
408
- if (options.omitReadPreference) {
409
- delete options.readPreference;
410
- }
411
-
412
407
  if (this.description.iscryptd) {
413
408
  options.omitMaxTimeMS = true;
414
409
  }
@@ -46,7 +46,6 @@ import {
46
46
  makeStateMachine,
47
47
  noop,
48
48
  now,
49
- ns,
50
49
  promiseWithResolvers,
51
50
  shuffle
52
51
  } from '../utils';
@@ -459,7 +458,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
459
458
  waitQueueTimeoutMS: this.client.s.options.waitQueueTimeoutMS
460
459
  });
461
460
  const selectServerOptions = {
462
- operationName: 'ping',
461
+ operationName: 'handshake',
463
462
  ...options,
464
463
  timeoutContext
465
464
  };
@@ -469,9 +468,11 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
469
468
  readPreferenceServerSelector(readPreference),
470
469
  selectServerOptions
471
470
  );
471
+
472
472
  const skipPingOnConnect = this.s.options.__skipPingOnConnect === true;
473
473
  if (!skipPingOnConnect && this.s.credentials) {
474
- await server.command(ns('admin.$cmd'), { ping: 1 }, { timeoutContext });
474
+ const connection = await server.pool.checkOut({ timeoutContext: timeoutContext });
475
+ server.pool.checkIn(connection);
475
476
  stateTransition(this, STATE_CONNECTED);
476
477
  this.emit(Topology.OPEN, this);
477
478
  this.emit(Topology.CONNECT, this);