mongodb 6.7.0-dev.20240613.sha.c1af6adc → 6.7.0-dev.20240614.sha.3ed6a2ad

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 (93) hide show
  1. package/lib/bson.js.map +1 -1
  2. package/lib/client-side-encryption/auto_encrypter.js +8 -61
  3. package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
  4. package/lib/client-side-encryption/client_encryption.js +5 -5
  5. package/lib/client-side-encryption/client_encryption.js.map +1 -1
  6. package/lib/client-side-encryption/state_machine.js +15 -11
  7. package/lib/client-side-encryption/state_machine.js.map +1 -1
  8. package/lib/cmap/connection.js +22 -20
  9. package/lib/cmap/connection.js.map +1 -1
  10. package/lib/cmap/wire_protocol/on_demand/document.js +8 -5
  11. package/lib/cmap/wire_protocol/on_demand/document.js.map +1 -1
  12. package/lib/cmap/wire_protocol/responses.js +116 -40
  13. package/lib/cmap/wire_protocol/responses.js.map +1 -1
  14. package/lib/constants.js +9 -1
  15. package/lib/constants.js.map +1 -1
  16. package/lib/cursor/abstract_cursor.js +24 -60
  17. package/lib/cursor/abstract_cursor.js.map +1 -1
  18. package/lib/cursor/aggregation_cursor.js +2 -3
  19. package/lib/cursor/aggregation_cursor.js.map +1 -1
  20. package/lib/cursor/change_stream_cursor.js +6 -8
  21. package/lib/cursor/change_stream_cursor.js.map +1 -1
  22. package/lib/cursor/find_cursor.js +5 -17
  23. package/lib/cursor/find_cursor.js.map +1 -1
  24. package/lib/cursor/list_collections_cursor.js +0 -1
  25. package/lib/cursor/list_collections_cursor.js.map +1 -1
  26. package/lib/cursor/list_indexes_cursor.js +0 -1
  27. package/lib/cursor/list_indexes_cursor.js.map +1 -1
  28. package/lib/cursor/run_command_cursor.js +4 -6
  29. package/lib/cursor/run_command_cursor.js.map +1 -1
  30. package/lib/error.js +6 -21
  31. package/lib/error.js.map +1 -1
  32. package/lib/operations/aggregate.js +2 -2
  33. package/lib/operations/aggregate.js.map +1 -1
  34. package/lib/operations/bulk_write.js +1 -2
  35. package/lib/operations/bulk_write.js.map +1 -1
  36. package/lib/operations/command.js +2 -3
  37. package/lib/operations/command.js.map +1 -1
  38. package/lib/operations/count_documents.js +1 -7
  39. package/lib/operations/count_documents.js.map +1 -1
  40. package/lib/operations/execute_operation.js.map +1 -1
  41. package/lib/operations/find.js +2 -1
  42. package/lib/operations/find.js.map +1 -1
  43. package/lib/operations/get_more.js +1 -1
  44. package/lib/operations/get_more.js.map +1 -1
  45. package/lib/operations/indexes.js +2 -1
  46. package/lib/operations/indexes.js.map +1 -1
  47. package/lib/operations/list_collections.js +2 -1
  48. package/lib/operations/list_collections.js.map +1 -1
  49. package/lib/operations/run_command.js +1 -1
  50. package/lib/operations/run_command.js.map +1 -1
  51. package/lib/operations/update.js +2 -1
  52. package/lib/operations/update.js.map +1 -1
  53. package/lib/sdam/server.js +7 -2
  54. package/lib/sdam/server.js.map +1 -1
  55. package/lib/utils.js +45 -1
  56. package/lib/utils.js.map +1 -1
  57. package/lib/write_concern.js +17 -1
  58. package/lib/write_concern.js.map +1 -1
  59. package/mongodb.d.ts +17 -8
  60. package/package.json +1 -1
  61. package/src/bson.ts +1 -0
  62. package/src/client-side-encryption/auto_encrypter.ts +9 -70
  63. package/src/client-side-encryption/client_encryption.ts +6 -6
  64. package/src/client-side-encryption/state_machine.ts +18 -16
  65. package/src/cmap/connection.ts +46 -50
  66. package/src/cmap/wire_protocol/on_demand/document.ts +13 -6
  67. package/src/cmap/wire_protocol/responses.ts +140 -45
  68. package/src/constants.ts +9 -0
  69. package/src/cursor/abstract_cursor.ts +51 -71
  70. package/src/cursor/aggregation_cursor.ts +13 -12
  71. package/src/cursor/change_stream_cursor.ts +20 -34
  72. package/src/cursor/find_cursor.ts +17 -25
  73. package/src/cursor/list_collections_cursor.ts +3 -4
  74. package/src/cursor/list_indexes_cursor.ts +3 -4
  75. package/src/cursor/run_command_cursor.ts +13 -19
  76. package/src/error.ts +16 -28
  77. package/src/index.ts +6 -7
  78. package/src/operations/aggregate.ts +12 -5
  79. package/src/operations/bulk_write.ts +1 -2
  80. package/src/operations/command.ts +17 -3
  81. package/src/operations/count_documents.ts +7 -11
  82. package/src/operations/delete.ts +2 -2
  83. package/src/operations/execute_operation.ts +0 -13
  84. package/src/operations/find.ts +7 -3
  85. package/src/operations/find_and_modify.ts +1 -1
  86. package/src/operations/get_more.ts +6 -10
  87. package/src/operations/indexes.ts +7 -3
  88. package/src/operations/list_collections.ts +8 -3
  89. package/src/operations/run_command.ts +16 -6
  90. package/src/operations/update.ts +2 -1
  91. package/src/sdam/server.ts +7 -2
  92. package/src/utils.ts +52 -2
  93. package/src/write_concern.ts +18 -0
@@ -1,7 +1,7 @@
1
1
  import { Readable, Transform } from 'stream';
2
2
 
3
3
  import { type BSONSerializeOptions, type Document, Long, pluckBSONSerializeOptions } from '../bson';
4
- import { CursorResponse } from '../cmap/wire_protocol/responses';
4
+ import { type CursorResponse } from '../cmap/wire_protocol/responses';
5
5
  import {
6
6
  MongoAPIError,
7
7
  MongoCursorExhaustedError,
@@ -11,15 +11,33 @@ import {
11
11
  MongoTailableCursorError
12
12
  } from '../error';
13
13
  import type { MongoClient } from '../mongo_client';
14
- import { type TODO_NODE_3286, TypedEventEmitter } from '../mongo_types';
15
- import { executeOperation, type ExecutionResult } from '../operations/execute_operation';
14
+ import { TypedEventEmitter } from '../mongo_types';
15
+ import { executeOperation } from '../operations/execute_operation';
16
16
  import { GetMoreOperation } from '../operations/get_more';
17
17
  import { KillCursorsOperation } from '../operations/kill_cursors';
18
18
  import { ReadConcern, type ReadConcernLike } from '../read_concern';
19
19
  import { ReadPreference, type ReadPreferenceLike } from '../read_preference';
20
20
  import type { Server } from '../sdam/server';
21
21
  import { ClientSession, maybeClearPinnedConnection } from '../sessions';
22
- import { List, type MongoDBNamespace, ns, squashError } from '../utils';
22
+ import { type MongoDBNamespace, squashError } from '../utils';
23
+
24
+ /**
25
+ * @internal
26
+ * TODO(NODE-2882): A cursor's getMore commands must be run on the same server it was started on
27
+ * and the same session must be used for the lifetime of the cursor. This object serves to get the
28
+ * server and session (along with the response) out of executeOperation back to the AbstractCursor.
29
+ *
30
+ * There may be a better design for communicating these values back to the cursor, currently an operation
31
+ * MUST store the selected server on itself so it can be read after executeOperation has returned.
32
+ */
33
+ export interface InitialCursorResponse {
34
+ /** The server selected for the operation */
35
+ server: Server;
36
+ /** The session used for this operation, may be implicitly created */
37
+ session?: ClientSession;
38
+ /** The raw server response for the operation */
39
+ response: CursorResponse;
40
+ }
23
41
 
24
42
  /** @public */
25
43
  export const CURSOR_FLAGS = [
@@ -118,13 +136,7 @@ export abstract class AbstractCursor<
118
136
  /** @internal */
119
137
  private cursorNamespace: MongoDBNamespace;
120
138
  /** @internal */
121
- private documents: {
122
- length: number;
123
- shift(bsonOptions?: any): TSchema | null;
124
- clear(): void;
125
- pushMany(many: Iterable<TSchema>): void;
126
- push(item: TSchema): void;
127
- };
139
+ private documents: CursorResponse | null = null;
128
140
  /** @internal */
129
141
  private cursorClient: MongoClient;
130
142
  /** @internal */
@@ -155,7 +167,6 @@ export abstract class AbstractCursor<
155
167
  this.cursorClient = client;
156
168
  this.cursorNamespace = namespace;
157
169
  this.cursorId = null;
158
- this.documents = new List();
159
170
  this.initialized = false;
160
171
  this.isClosed = false;
161
172
  this.isKilled = false;
@@ -252,16 +263,19 @@ export abstract class AbstractCursor<
252
263
 
253
264
  /** Returns current buffered documents length */
254
265
  bufferedCount(): number {
255
- return this.documents.length;
266
+ return this.documents?.length ?? 0;
256
267
  }
257
268
 
258
269
  /** Returns current buffered documents */
259
270
  readBufferedDocuments(number?: number): TSchema[] {
260
271
  const bufferedDocs: TSchema[] = [];
261
- const documentsToRead = Math.min(number ?? this.documents.length, this.documents.length);
272
+ const documentsToRead = Math.min(
273
+ number ?? this.documents?.length ?? 0,
274
+ this.documents?.length ?? 0
275
+ );
262
276
 
263
277
  for (let count = 0; count < documentsToRead; count++) {
264
- const document = this.documents.shift(this.cursorOptions);
278
+ const document = this.documents?.shift(this.cursorOptions);
265
279
  if (document != null) {
266
280
  bufferedDocs.push(document);
267
281
  }
@@ -269,7 +283,6 @@ export abstract class AbstractCursor<
269
283
 
270
284
  return bufferedDocs;
271
285
  }
272
-
273
286
  async *[Symbol.asyncIterator](): AsyncGenerator<TSchema, void, void> {
274
287
  if (this.isClosed) {
275
288
  return;
@@ -281,11 +294,11 @@ export abstract class AbstractCursor<
281
294
  return;
282
295
  }
283
296
 
284
- if (this.isClosed && this.documents.length === 0) {
297
+ if (this.closed && (this.documents?.length ?? 0) === 0) {
285
298
  return;
286
299
  }
287
300
 
288
- if (this.cursorId != null && this.isDead && this.documents.length === 0) {
301
+ if (this.cursorId != null && this.isDead && (this.documents?.length ?? 0) === 0) {
289
302
  return;
290
303
  }
291
304
 
@@ -347,11 +360,11 @@ export abstract class AbstractCursor<
347
360
  }
348
361
 
349
362
  do {
350
- if (this.documents.length !== 0) {
363
+ if ((this.documents?.length ?? 0) !== 0) {
351
364
  return true;
352
365
  }
353
366
  await this.fetchBatch();
354
- } while (!this.isDead || this.documents.length !== 0);
367
+ } while (!this.isDead || (this.documents?.length ?? 0) !== 0);
355
368
 
356
369
  return false;
357
370
  }
@@ -363,13 +376,13 @@ export abstract class AbstractCursor<
363
376
  }
364
377
 
365
378
  do {
366
- const doc = this.documents.shift();
379
+ const doc = this.documents?.shift(this.cursorOptions);
367
380
  if (doc != null) {
368
381
  if (this.transform != null) return await this.transformDocument(doc);
369
382
  return doc;
370
383
  }
371
384
  await this.fetchBatch();
372
- } while (!this.isDead || this.documents.length !== 0);
385
+ } while (!this.isDead || (this.documents?.length ?? 0) !== 0);
373
386
 
374
387
  return null;
375
388
  }
@@ -382,7 +395,7 @@ export abstract class AbstractCursor<
382
395
  throw new MongoCursorExhaustedError();
383
396
  }
384
397
 
385
- let doc = this.documents.shift();
398
+ let doc = this.documents?.shift(this.cursorOptions);
386
399
  if (doc != null) {
387
400
  if (this.transform != null) return await this.transformDocument(doc);
388
401
  return doc;
@@ -390,7 +403,7 @@ export abstract class AbstractCursor<
390
403
 
391
404
  await this.fetchBatch();
392
405
 
393
- doc = this.documents.shift();
406
+ doc = this.documents?.shift(this.cursorOptions);
394
407
  if (doc != null) {
395
408
  if (this.transform != null) return await this.transformDocument(doc);
396
409
  return doc;
@@ -591,7 +604,7 @@ export abstract class AbstractCursor<
591
604
  }
592
605
 
593
606
  this.cursorId = null;
594
- this.documents.clear();
607
+ this.documents?.clear();
595
608
  this.isClosed = false;
596
609
  this.isKilled = false;
597
610
  this.initialized = false;
@@ -615,10 +628,12 @@ export abstract class AbstractCursor<
615
628
  abstract clone(): AbstractCursor<TSchema>;
616
629
 
617
630
  /** @internal */
618
- protected abstract _initialize(session: ClientSession | undefined): Promise<ExecutionResult>;
631
+ protected abstract _initialize(
632
+ session: ClientSession | undefined
633
+ ): Promise<InitialCursorResponse>;
619
634
 
620
635
  /** @internal */
621
- async getMore(batchSize: number, useCursorResponse = false): Promise<Document | null> {
636
+ async getMore(batchSize: number): Promise<CursorResponse> {
622
637
  if (this.cursorId == null) {
623
638
  throw new MongoRuntimeError(
624
639
  'Unexpected null cursor id. A cursor creating command should have set this'
@@ -636,8 +651,7 @@ export abstract class AbstractCursor<
636
651
  {
637
652
  ...this.cursorOptions,
638
653
  session: this.cursorSession,
639
- batchSize,
640
- useCursorResponse
654
+ batchSize
641
655
  }
642
656
  );
643
657
 
@@ -656,27 +670,10 @@ export abstract class AbstractCursor<
656
670
  const state = await this._initialize(this.cursorSession);
657
671
  const response = state.response;
658
672
  this.selectedServer = state.server;
659
- if (CursorResponse.is(response)) {
660
- this.cursorId = response.id;
661
- if (response.ns) this.cursorNamespace = response.ns;
662
- this.documents = response;
663
- } else if (response.cursor) {
664
- // TODO(NODE-2674): Preserve int64 sent from MongoDB
665
- this.cursorId = getCursorId(response);
666
- if (response.cursor.ns) this.cursorNamespace = ns(response.cursor.ns);
667
- this.documents.pushMany(response.cursor.firstBatch);
668
- }
669
-
670
- if (this.cursorId == null) {
671
- // When server responses return without a cursor document, we close this cursor
672
- // and return the raw server response. This is the case for explain commands
673
- this.cursorId = Long.ZERO;
674
- // TODO(NODE-3286): ExecutionResult needs to accept a generic parameter
675
- this.documents.push(state.response as TODO_NODE_3286);
676
- }
677
-
678
- // the cursor is now initialized, even if it is dead
679
- this.initialized = true;
673
+ this.cursorId = response.id;
674
+ this.cursorNamespace = response.ns ?? this.namespace;
675
+ this.documents = response;
676
+ this.initialized = true; // the cursor is now initialized, even if it is dead
680
677
  } catch (error) {
681
678
  // the cursor is now initialized, even if an error occurred
682
679
  this.initialized = true;
@@ -708,7 +705,7 @@ export abstract class AbstractCursor<
708
705
  if (this.cursorId == null) {
709
706
  await this.cursorInit();
710
707
  // If the cursor died or returned documents, return
711
- if (this.documents.length !== 0 || this.isDead) return;
708
+ if ((this.documents?.length ?? 0) !== 0 || this.isDead) return;
712
709
  // Otherwise, run a getMore
713
710
  }
714
711
 
@@ -717,16 +714,8 @@ export abstract class AbstractCursor<
717
714
 
718
715
  try {
719
716
  const response = await this.getMore(batchSize);
720
- // CursorResponse is disabled in this PR
721
- // however the special `emptyGetMore` can be returned from find cursors
722
- if (CursorResponse.is(response)) {
723
- this.cursorId = response.id;
724
- this.documents = response;
725
- } else if (response?.cursor) {
726
- const cursorId = getCursorId(response);
727
- this.documents.pushMany(response.cursor.nextBatch);
728
- this.cursorId = cursorId;
729
- }
717
+ this.cursorId = response.id;
718
+ this.documents = response;
730
719
  } catch (error) {
731
720
  try {
732
721
  await this.cleanup(error);
@@ -789,7 +778,7 @@ export abstract class AbstractCursor<
789
778
  /** @internal */
790
779
  private emitClose() {
791
780
  try {
792
- if (!this.hasEmittedClose && (this.documents.length === 0 || this.isClosed)) {
781
+ if (!this.hasEmittedClose && ((this.documents?.length ?? 0) === 0 || this.isClosed)) {
793
782
  // @ts-expect-error: CursorEvents is generic so Parameters<CursorEvents["close"]> may not be assignable to `[]`. Not sure how to require extenders do not add parameters.
794
783
  this.emit('close');
795
784
  }
@@ -827,15 +816,6 @@ export abstract class AbstractCursor<
827
816
  }
828
817
  }
829
818
 
830
- /** A temporary helper to box up the many possible type issue of cursor ids */
831
- function getCursorId(response: Document) {
832
- return typeof response.cursor.id === 'number'
833
- ? Long.fromNumber(response.cursor.id)
834
- : typeof response.cursor.id === 'bigint'
835
- ? Long.fromBigInt(response.cursor.id)
836
- : response.cursor.id;
837
- }
838
-
839
819
  class ReadableCursorStream extends Readable {
840
820
  private _cursor: AbstractCursor;
841
821
  private _readInProgress = false;
@@ -2,12 +2,12 @@ import type { Document } from '../bson';
2
2
  import type { ExplainVerbosityLike } from '../explain';
3
3
  import type { MongoClient } from '../mongo_client';
4
4
  import { AggregateOperation, type AggregateOptions } from '../operations/aggregate';
5
- import { executeOperation, type ExecutionResult } from '../operations/execute_operation';
5
+ import { executeOperation } from '../operations/execute_operation';
6
6
  import type { ClientSession } from '../sessions';
7
7
  import type { Sort } from '../sort';
8
8
  import type { MongoDBNamespace } from '../utils';
9
9
  import { mergeOptions } from '../utils';
10
- import type { AbstractCursorOptions } from './abstract_cursor';
10
+ import type { AbstractCursorOptions, InitialCursorResponse } from './abstract_cursor';
11
11
  import { AbstractCursor } from './abstract_cursor';
12
12
 
13
13
  /** @public */
@@ -51,7 +51,7 @@ export class AggregationCursor<TSchema = any> extends AbstractCursor<TSchema> {
51
51
  }
52
52
 
53
53
  /** @internal */
54
- async _initialize(session: ClientSession): Promise<ExecutionResult> {
54
+ async _initialize(session: ClientSession): Promise<InitialCursorResponse> {
55
55
  const aggregateOperation = new AggregateOperation(this.namespace, this.pipeline, {
56
56
  ...this.aggregateOptions,
57
57
  ...this.cursorOptions,
@@ -60,20 +60,21 @@ export class AggregationCursor<TSchema = any> extends AbstractCursor<TSchema> {
60
60
 
61
61
  const response = await executeOperation(this.client, aggregateOperation);
62
62
 
63
- // TODO: NODE-2882
64
63
  return { server: aggregateOperation.server, session, response };
65
64
  }
66
65
 
67
66
  /** Execute the explain for the cursor */
68
67
  async explain(verbosity?: ExplainVerbosityLike): Promise<Document> {
69
- return await executeOperation(
70
- this.client,
71
- new AggregateOperation(this.namespace, this.pipeline, {
72
- ...this.aggregateOptions, // NOTE: order matters here, we may need to refine this
73
- ...this.cursorOptions,
74
- explain: verbosity ?? true
75
- })
76
- );
68
+ return (
69
+ await executeOperation(
70
+ this.client,
71
+ new AggregateOperation(this.namespace, this.pipeline, {
72
+ ...this.aggregateOptions, // NOTE: order matters here, we may need to refine this
73
+ ...this.cursorOptions,
74
+ explain: verbosity ?? true
75
+ })
76
+ )
77
+ ).shift(this.aggregateOptions);
77
78
  }
78
79
 
79
80
  /** Add a stage to the aggregation pipeline
@@ -1,4 +1,4 @@
1
- import type { Document, Long, Timestamp } from '../bson';
1
+ import type { Document } from '../bson';
2
2
  import {
3
3
  ChangeStream,
4
4
  type ChangeStreamDocument,
@@ -6,15 +6,19 @@ import {
6
6
  type OperationTime,
7
7
  type ResumeToken
8
8
  } from '../change_stream';
9
+ import { type CursorResponse } from '../cmap/wire_protocol/responses';
9
10
  import { INIT, RESPONSE } from '../constants';
10
11
  import type { MongoClient } from '../mongo_client';
11
- import type { TODO_NODE_3286 } from '../mongo_types';
12
12
  import { AggregateOperation } from '../operations/aggregate';
13
13
  import type { CollationOptions } from '../operations/command';
14
- import { executeOperation, type ExecutionResult } from '../operations/execute_operation';
14
+ import { executeOperation } from '../operations/execute_operation';
15
15
  import type { ClientSession } from '../sessions';
16
16
  import { maxWireVersion, type MongoDBNamespace } from '../utils';
17
- import { AbstractCursor, type AbstractCursorOptions } from './abstract_cursor';
17
+ import {
18
+ AbstractCursor,
19
+ type AbstractCursorOptions,
20
+ type InitialCursorResponse
21
+ } from './abstract_cursor';
18
22
 
19
23
  /** @internal */
20
24
  export interface ChangeStreamCursorOptions extends AbstractCursorOptions {
@@ -26,25 +30,13 @@ export interface ChangeStreamCursorOptions extends AbstractCursorOptions {
26
30
  fullDocument?: string;
27
31
  }
28
32
 
29
- /** @internal */
30
- export type ChangeStreamAggregateRawResult<TChange> = {
31
- $clusterTime: { clusterTime: Timestamp };
32
- cursor: {
33
- postBatchResumeToken: ResumeToken;
34
- ns: string;
35
- id: number | Long;
36
- } & ({ firstBatch: TChange[] } | { nextBatch: TChange[] });
37
- ok: 1;
38
- operationTime: Timestamp;
39
- };
40
-
41
33
  /** @internal */
42
34
  export class ChangeStreamCursor<
43
35
  TSchema extends Document = Document,
44
36
  TChange extends Document = ChangeStreamDocument<TSchema>
45
37
  > extends AbstractCursor<TChange, ChangeStreamEvents> {
46
38
  private _resumeToken: ResumeToken;
47
- private startAtOperationTime?: OperationTime;
39
+ private startAtOperationTime: OperationTime | null;
48
40
  private hasReceived?: boolean;
49
41
  private readonly changeStreamCursorOptions: ChangeStreamCursorOptions;
50
42
  private postBatchResumeToken?: ResumeToken;
@@ -68,7 +60,7 @@ export class ChangeStreamCursor<
68
60
  this.pipeline = pipeline;
69
61
  this.changeStreamCursorOptions = options;
70
62
  this._resumeToken = null;
71
- this.startAtOperationTime = options.startAtOperationTime;
63
+ this.startAtOperationTime = options.startAtOperationTime ?? null;
72
64
 
73
65
  if (options.startAfter) {
74
66
  this.resumeToken = options.startAfter;
@@ -117,15 +109,13 @@ export class ChangeStreamCursor<
117
109
  this.hasReceived = true;
118
110
  }
119
111
 
120
- _processBatch(response: ChangeStreamAggregateRawResult<TChange>): void {
121
- const cursor = response.cursor;
122
- if (cursor.postBatchResumeToken) {
123
- this.postBatchResumeToken = response.cursor.postBatchResumeToken;
112
+ _processBatch(response: CursorResponse): void {
113
+ const { postBatchResumeToken } = response;
114
+ if (postBatchResumeToken) {
115
+ this.postBatchResumeToken = postBatchResumeToken;
124
116
 
125
- const batch =
126
- 'firstBatch' in response.cursor ? response.cursor.firstBatch : response.cursor.nextBatch;
127
- if (batch.length === 0) {
128
- this.resumeToken = cursor.postBatchResumeToken;
117
+ if (response.batchSize === 0) {
118
+ this.resumeToken = postBatchResumeToken;
129
119
  }
130
120
  }
131
121
  }
@@ -136,17 +126,14 @@ export class ChangeStreamCursor<
136
126
  });
137
127
  }
138
128
 
139
- async _initialize(session: ClientSession): Promise<ExecutionResult> {
129
+ async _initialize(session: ClientSession): Promise<InitialCursorResponse> {
140
130
  const aggregateOperation = new AggregateOperation(this.namespace, this.pipeline, {
141
131
  ...this.cursorOptions,
142
132
  ...this.changeStreamCursorOptions,
143
133
  session
144
134
  });
145
135
 
146
- const response = await executeOperation<
147
- TODO_NODE_3286,
148
- ChangeStreamAggregateRawResult<TChange>
149
- >(session.client, aggregateOperation);
136
+ const response = await executeOperation(session.client, aggregateOperation);
150
137
 
151
138
  const server = aggregateOperation.server;
152
139
  this.maxWireVersion = maxWireVersion(server);
@@ -165,15 +152,14 @@ export class ChangeStreamCursor<
165
152
  this.emit(INIT, response);
166
153
  this.emit(RESPONSE);
167
154
 
168
- // TODO: NODE-2882
169
155
  return { server, session, response };
170
156
  }
171
157
 
172
- override async getMore(batchSize: number): Promise<Document | null> {
158
+ override async getMore(batchSize: number): Promise<CursorResponse> {
173
159
  const response = await super.getMore(batchSize);
174
160
 
175
161
  this.maxWireVersion = maxWireVersion(this.server);
176
- this._processBatch(response as ChangeStreamAggregateRawResult<TChange>);
162
+ this._processBatch(response);
177
163
 
178
164
  this.emit(ChangeStream.MORE, response);
179
165
  this.emit(ChangeStream.RESPONSE);
@@ -5,13 +5,13 @@ import { type ExplainVerbosityLike } from '../explain';
5
5
  import type { MongoClient } from '../mongo_client';
6
6
  import type { CollationOptions } from '../operations/command';
7
7
  import { CountOperation, type CountOptions } from '../operations/count';
8
- import { executeOperation, type ExecutionResult } from '../operations/execute_operation';
8
+ import { executeOperation } from '../operations/execute_operation';
9
9
  import { FindOperation, type FindOptions } from '../operations/find';
10
10
  import type { Hint } from '../operations/operation';
11
11
  import type { ClientSession } from '../sessions';
12
12
  import { formatSort, type Sort, type SortDirection } from '../sort';
13
13
  import { emitWarningOnce, mergeOptions, type MongoDBNamespace, squashError } from '../utils';
14
- import { AbstractCursor } from './abstract_cursor';
14
+ import { AbstractCursor, type InitialCursorResponse } from './abstract_cursor';
15
15
 
16
16
  /** @public Flags allowed for cursor */
17
17
  export const FLAGS = [
@@ -62,7 +62,7 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
62
62
  }
63
63
 
64
64
  /** @internal */
65
- async _initialize(session: ClientSession): Promise<ExecutionResult> {
65
+ async _initialize(session: ClientSession): Promise<InitialCursorResponse> {
66
66
  const findOperation = new FindOperation(this.namespace, this.cursorFilter, {
67
67
  ...this.findOptions, // NOTE: order matters here, we may need to refine this
68
68
  ...this.cursorOptions,
@@ -72,19 +72,13 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
72
72
  const response = await executeOperation(this.client, findOperation);
73
73
 
74
74
  // the response is not a cursor when `explain` is enabled
75
- if (CursorResponse.is(response)) {
76
- this.numReturned = response.batchSize;
77
- } else {
78
- // Can be an explain response, hence the ?. on everything
79
- this.numReturned = this.numReturned + (response?.cursor?.firstBatch?.length ?? 0);
80
- }
75
+ this.numReturned = response.batchSize;
81
76
 
82
- // TODO: NODE-2882
83
77
  return { server: findOperation.server, session, response };
84
78
  }
85
79
 
86
80
  /** @internal */
87
- override async getMore(batchSize: number): Promise<Document | null> {
81
+ override async getMore(batchSize: number): Promise<CursorResponse> {
88
82
  const numReturned = this.numReturned;
89
83
  if (numReturned) {
90
84
  // TODO(DRIVERS-1448): Remove logic to enforce `limit` in the driver
@@ -110,13 +104,9 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
110
104
  }
111
105
  }
112
106
 
113
- const response = await super.getMore(batchSize, false);
107
+ const response = await super.getMore(batchSize);
114
108
  // TODO: wrap this in some logic to prevent it from happening if we don't need this support
115
- if (CursorResponse.is(response)) {
116
- this.numReturned = this.numReturned + response.batchSize;
117
- } else {
118
- this.numReturned = this.numReturned + (response?.cursor?.nextBatch?.length ?? 0);
119
- }
109
+ this.numReturned = this.numReturned + response.batchSize;
120
110
 
121
111
  return response;
122
112
  }
@@ -144,14 +134,16 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
144
134
 
145
135
  /** Execute the explain for the cursor */
146
136
  async explain(verbosity?: ExplainVerbosityLike): Promise<Document> {
147
- return await executeOperation(
148
- this.client,
149
- new FindOperation(this.namespace, this.cursorFilter, {
150
- ...this.findOptions, // NOTE: order matters here, we may need to refine this
151
- ...this.cursorOptions,
152
- explain: verbosity ?? true
153
- })
154
- );
137
+ return (
138
+ await executeOperation(
139
+ this.client,
140
+ new FindOperation(this.namespace, this.cursorFilter, {
141
+ ...this.findOptions, // NOTE: order matters here, we may need to refine this
142
+ ...this.cursorOptions,
143
+ explain: verbosity ?? true
144
+ })
145
+ )
146
+ ).shift(this.findOptions);
155
147
  }
156
148
 
157
149
  /** Set the cursor query */
@@ -1,13 +1,13 @@
1
1
  import type { Document } from '../bson';
2
2
  import type { Db } from '../db';
3
- import { executeOperation, type ExecutionResult } from '../operations/execute_operation';
3
+ import { executeOperation } from '../operations/execute_operation';
4
4
  import {
5
5
  type CollectionInfo,
6
6
  ListCollectionsOperation,
7
7
  type ListCollectionsOptions
8
8
  } from '../operations/list_collections';
9
9
  import type { ClientSession } from '../sessions';
10
- import { AbstractCursor } from './abstract_cursor';
10
+ import { AbstractCursor, type InitialCursorResponse } from './abstract_cursor';
11
11
 
12
12
  /** @public */
13
13
  export class ListCollectionsCursor<
@@ -34,7 +34,7 @@ export class ListCollectionsCursor<
34
34
  }
35
35
 
36
36
  /** @internal */
37
- async _initialize(session: ClientSession | undefined): Promise<ExecutionResult> {
37
+ async _initialize(session: ClientSession | undefined): Promise<InitialCursorResponse> {
38
38
  const operation = new ListCollectionsOperation(this.parent, this.filter, {
39
39
  ...this.cursorOptions,
40
40
  ...this.options,
@@ -43,7 +43,6 @@ export class ListCollectionsCursor<
43
43
 
44
44
  const response = await executeOperation(this.parent.client, operation);
45
45
 
46
- // TODO: NODE-2882
47
46
  return { server: operation.server, session, response };
48
47
  }
49
48
  }
@@ -1,8 +1,8 @@
1
1
  import type { Collection } from '../collection';
2
- import { executeOperation, type ExecutionResult } from '../operations/execute_operation';
2
+ import { executeOperation } from '../operations/execute_operation';
3
3
  import { ListIndexesOperation, type ListIndexesOptions } from '../operations/indexes';
4
4
  import type { ClientSession } from '../sessions';
5
- import { AbstractCursor } from './abstract_cursor';
5
+ import { AbstractCursor, type InitialCursorResponse } from './abstract_cursor';
6
6
 
7
7
  /** @public */
8
8
  export class ListIndexesCursor extends AbstractCursor {
@@ -23,7 +23,7 @@ export class ListIndexesCursor extends AbstractCursor {
23
23
  }
24
24
 
25
25
  /** @internal */
26
- async _initialize(session: ClientSession | undefined): Promise<ExecutionResult> {
26
+ async _initialize(session: ClientSession | undefined): Promise<InitialCursorResponse> {
27
27
  const operation = new ListIndexesOperation(this.parent, {
28
28
  ...this.cursorOptions,
29
29
  ...this.options,
@@ -32,7 +32,6 @@ export class ListIndexesCursor extends AbstractCursor {
32
32
 
33
33
  const response = await executeOperation(this.parent.client, operation);
34
34
 
35
- // TODO: NODE-2882
36
35
  return { server: operation.server, session, response };
37
36
  }
38
37
  }
@@ -1,14 +1,15 @@
1
- import type { BSONSerializeOptions, Document, Long } from '../bson';
1
+ import type { BSONSerializeOptions, Document } from '../bson';
2
+ import { CursorResponse } from '../cmap/wire_protocol/responses';
2
3
  import type { Db } from '../db';
3
- import { MongoAPIError, MongoUnexpectedServerResponseError } from '../error';
4
- import { executeOperation, type ExecutionResult } from '../operations/execute_operation';
4
+ import { MongoAPIError } from '../error';
5
+ import { executeOperation } from '../operations/execute_operation';
5
6
  import { GetMoreOperation } from '../operations/get_more';
6
7
  import { RunCommandOperation } from '../operations/run_command';
7
8
  import type { ReadConcernLike } from '../read_concern';
8
9
  import type { ReadPreferenceLike } from '../read_preference';
9
10
  import type { ClientSession } from '../sessions';
10
11
  import { ns } from '../utils';
11
- import { AbstractCursor } from './abstract_cursor';
12
+ import { AbstractCursor, type InitialCursorResponse } from './abstract_cursor';
12
13
 
13
14
  /** @public */
14
15
  export type RunCursorCommandOptions = {
@@ -16,12 +17,6 @@ export type RunCursorCommandOptions = {
16
17
  session?: ClientSession;
17
18
  } & BSONSerializeOptions;
18
19
 
19
- /** @internal */
20
- type RunCursorCommandResponse = {
21
- cursor: { id: bigint | Long | number; ns: string; firstBatch: Document[] };
22
- ok: 1;
23
- };
24
-
25
20
  /** @public */
26
21
  export class RunCommandCursor extends AbstractCursor {
27
22
  public readonly command: Readonly<Record<string, any>>;
@@ -102,16 +97,16 @@ export class RunCommandCursor extends AbstractCursor {
102
97
  }
103
98
 
104
99
  /** @internal */
105
- protected async _initialize(session: ClientSession): Promise<ExecutionResult> {
106
- const operation = new RunCommandOperation<RunCursorCommandResponse>(this.db, this.command, {
100
+ protected async _initialize(session: ClientSession): Promise<InitialCursorResponse> {
101
+ const operation = new RunCommandOperation<CursorResponse>(this.db, this.command, {
107
102
  ...this.cursorOptions,
108
103
  session: session,
109
- readPreference: this.cursorOptions.readPreference
104
+ readPreference: this.cursorOptions.readPreference,
105
+ responseType: CursorResponse
110
106
  });
107
+
111
108
  const response = await executeOperation(this.client, operation);
112
- if (response.cursor == null) {
113
- throw new MongoUnexpectedServerResponseError('Expected server to respond with cursor');
114
- }
109
+
115
110
  return {
116
111
  server: operation.server,
117
112
  session,
@@ -120,13 +115,12 @@ export class RunCommandCursor extends AbstractCursor {
120
115
  }
121
116
 
122
117
  /** @internal */
123
- override async getMore(_batchSize: number): Promise<Document> {
118
+ override async getMore(_batchSize: number): Promise<CursorResponse> {
124
119
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
125
120
  const getMoreOperation = new GetMoreOperation(this.namespace, this.id!, this.server!, {
126
121
  ...this.cursorOptions,
127
122
  session: this.session,
128
- ...this.getMoreOptions,
129
- useCursorResponse: false
123
+ ...this.getMoreOptions
130
124
  });
131
125
 
132
126
  return await executeOperation(this.client, getMoreOperation);