mongodb 6.5.0 → 6.6.0-dev.20240504.sha.2609953
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.
- package/README.md +9 -9
- package/lib/admin.js +9 -9
- package/lib/admin.js.map +1 -1
- package/lib/bson.js +33 -22
- package/lib/bson.js.map +1 -1
- package/lib/bulk/common.js +13 -12
- package/lib/bulk/common.js.map +1 -1
- package/lib/change_stream.js +28 -18
- package/lib/change_stream.js.map +1 -1
- package/lib/client-side-encryption/auto_encrypter.js +2 -2
- package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
- package/lib/client-side-encryption/client_encryption.js +6 -6
- package/lib/client-side-encryption/client_encryption.js.map +1 -1
- package/lib/client-side-encryption/providers/aws.js +13 -10
- package/lib/client-side-encryption/providers/aws.js.map +1 -1
- package/lib/client-side-encryption/providers/azure.js +6 -3
- package/lib/client-side-encryption/providers/azure.js.map +1 -1
- package/lib/cmap/auth/aws_temporary_credentials.js +140 -0
- package/lib/cmap/auth/aws_temporary_credentials.js.map +1 -0
- package/lib/cmap/auth/gssapi.js +7 -6
- package/lib/cmap/auth/gssapi.js.map +1 -1
- package/lib/cmap/auth/mongodb_aws.js +8 -101
- package/lib/cmap/auth/mongodb_aws.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js +1 -1
- package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js +2 -1
- package/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/service_workflow.js +1 -1
- package/lib/cmap/auth/mongodb_oidc/service_workflow.js.map +1 -1
- package/lib/cmap/auth/scram.js +2 -2
- package/lib/cmap/auth/scram.js.map +1 -1
- package/lib/cmap/commands.js +24 -111
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connect.js +4 -4
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +61 -36
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +22 -13
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/handshake/client_metadata.js +2 -2
- package/lib/cmap/handshake/client_metadata.js.map +1 -1
- package/lib/cmap/wire_protocol/compression.js +8 -8
- package/lib/cmap/wire_protocol/compression.js.map +1 -1
- package/lib/cmap/wire_protocol/on_demand/document.js +218 -0
- package/lib/cmap/wire_protocol/on_demand/document.js.map +1 -0
- package/lib/cmap/wire_protocol/responses.js +184 -0
- package/lib/cmap/wire_protocol/responses.js.map +1 -0
- package/lib/collection.js +42 -38
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +4 -6
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +76 -43
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +16 -33
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +36 -18
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/cursor/run_command_cursor.js +3 -2
- package/lib/cursor/run_command_cursor.js.map +1 -1
- package/lib/db.js +15 -19
- package/lib/db.js.map +1 -1
- package/lib/deps.js +31 -26
- package/lib/deps.js.map +1 -1
- package/lib/encrypter.js +14 -5
- package/lib/encrypter.js.map +1 -1
- package/lib/error.js +4 -3
- package/lib/error.js.map +1 -1
- package/lib/gridfs/download.js +19 -14
- package/lib/gridfs/download.js.map +1 -1
- package/lib/gridfs/index.js.map +1 -1
- package/lib/gridfs/upload.js +6 -1
- package/lib/gridfs/upload.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +11 -7
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_logger.js +3 -0
- package/lib/mongo_logger.js.map +1 -1
- package/lib/operations/aggregate.js +2 -1
- package/lib/operations/aggregate.js.map +1 -1
- package/lib/operations/command.js +1 -1
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/create_collection.js +1 -1
- package/lib/operations/create_collection.js.map +1 -1
- package/lib/operations/delete.js +4 -3
- package/lib/operations/delete.js.map +1 -1
- package/lib/operations/drop.js +1 -1
- package/lib/operations/drop.js.map +1 -1
- package/lib/operations/execute_operation.js +23 -8
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js +4 -4
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/get_more.js +2 -1
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js +29 -121
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/insert.js +3 -3
- package/lib/operations/insert.js.map +1 -1
- package/lib/operations/kill_cursors.js +3 -1
- package/lib/operations/kill_cursors.js.map +1 -1
- package/lib/operations/list_collections.js +1 -1
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/list_databases.js +1 -1
- package/lib/operations/list_databases.js.map +1 -1
- package/lib/operations/operation.js.map +1 -1
- package/lib/operations/run_command.js +4 -2
- package/lib/operations/run_command.js.map +1 -1
- package/lib/operations/search_indexes/create.js.map +1 -1
- package/lib/operations/stats.js +1 -1
- package/lib/operations/stats.js.map +1 -1
- package/lib/operations/update.js +1 -1
- package/lib/operations/update.js.map +1 -1
- package/lib/sdam/common.js.map +1 -1
- package/lib/sdam/monitor.js +139 -42
- package/lib/sdam/monitor.js.map +1 -1
- package/lib/sdam/server.js +5 -15
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +1 -0
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/server_selection.js +1 -1
- package/lib/sdam/server_selection.js.map +1 -1
- package/lib/sdam/srv_polling.js +2 -1
- package/lib/sdam/srv_polling.js.map +1 -1
- package/lib/sdam/topology.js +67 -54
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sdam/topology_description.js +10 -0
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +133 -93
- package/lib/sessions.js.map +1 -1
- package/lib/timeout.js +77 -0
- package/lib/timeout.js.map +1 -0
- package/lib/utils.js +61 -28
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +150 -38
- package/package.json +17 -14
- package/src/admin.ts +9 -9
- package/src/bson.ts +14 -0
- package/src/bulk/common.ts +3 -2
- package/src/change_stream.ts +39 -30
- package/src/client-side-encryption/auto_encrypter.ts +2 -2
- package/src/client-side-encryption/client_encryption.ts +6 -6
- package/src/client-side-encryption/providers/aws.ts +17 -10
- package/src/client-side-encryption/providers/azure.ts +5 -3
- package/src/cmap/auth/aws_temporary_credentials.ts +169 -0
- package/src/cmap/auth/gssapi.ts +9 -11
- package/src/cmap/auth/mongodb_aws.ts +19 -126
- package/src/cmap/auth/mongodb_oidc/aws_service_workflow.ts +1 -1
- package/src/cmap/auth/mongodb_oidc/callback_lock_cache.ts +2 -1
- package/src/cmap/auth/mongodb_oidc/service_workflow.ts +1 -1
- package/src/cmap/auth/scram.ts +2 -2
- package/src/cmap/commands.ts +28 -132
- package/src/cmap/connect.ts +4 -4
- package/src/cmap/connection.ts +107 -43
- package/src/cmap/connection_pool.ts +32 -29
- package/src/cmap/handshake/client_metadata.ts +2 -5
- package/src/cmap/wire_protocol/compression.ts +11 -13
- package/src/cmap/wire_protocol/on_demand/document.ts +338 -0
- package/src/cmap/wire_protocol/responses.ts +237 -0
- package/src/collection.ts +87 -58
- package/src/connection_string.ts +9 -7
- package/src/cursor/abstract_cursor.ts +102 -38
- package/src/cursor/aggregation_cursor.ts +32 -34
- package/src/cursor/find_cursor.ts +33 -21
- package/src/cursor/list_search_indexes_cursor.ts +1 -1
- package/src/cursor/run_command_cursor.ts +3 -2
- package/src/db.ts +42 -21
- package/src/deps.ts +52 -40
- package/src/encrypter.ts +14 -5
- package/src/error.ts +9 -3
- package/src/gridfs/download.ts +19 -31
- package/src/gridfs/index.ts +2 -0
- package/src/gridfs/upload.ts +11 -8
- package/src/index.ts +13 -5
- package/src/mongo_client.ts +21 -15
- package/src/mongo_logger.ts +3 -0
- package/src/mongo_types.ts +1 -1
- package/src/operations/aggregate.ts +2 -1
- package/src/operations/command.ts +1 -1
- package/src/operations/create_collection.ts +7 -2
- package/src/operations/delete.ts +4 -3
- package/src/operations/drop.ts +1 -1
- package/src/operations/execute_operation.ts +29 -10
- package/src/operations/find.ts +13 -14
- package/src/operations/get_more.ts +9 -1
- package/src/operations/indexes.ts +103 -176
- package/src/operations/insert.ts +2 -2
- package/src/operations/kill_cursors.ts +3 -2
- package/src/operations/list_collections.ts +5 -1
- package/src/operations/list_databases.ts +1 -1
- package/src/operations/operation.ts +3 -0
- package/src/operations/run_command.ts +6 -4
- package/src/operations/search_indexes/create.ts +4 -1
- package/src/operations/stats.ts +1 -1
- package/src/operations/update.ts +7 -7
- package/src/sdam/common.ts +8 -2
- package/src/sdam/monitor.ts +178 -61
- package/src/sdam/server.ts +27 -20
- package/src/sdam/server_description.ts +8 -3
- package/src/sdam/server_selection.ts +2 -3
- package/src/sdam/srv_polling.ts +3 -2
- package/src/sdam/topology.ts +114 -117
- package/src/sdam/topology_description.ts +14 -4
- package/src/sessions.ts +168 -148
- package/src/timeout.ts +96 -0
- package/src/utils.ts +85 -32
- package/lib/operations/common_functions.js +0 -38
- package/lib/operations/common_functions.js.map +0 -1
- package/src/operations/common_functions.ts +0 -79
|
@@ -1,6 +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
5
|
import {
|
|
5
6
|
type AnyError,
|
|
6
7
|
MongoAPIError,
|
|
@@ -20,7 +21,7 @@ import { ReadConcern, type ReadConcernLike } from '../read_concern';
|
|
|
20
21
|
import { ReadPreference, type ReadPreferenceLike } from '../read_preference';
|
|
21
22
|
import type { Server } from '../sdam/server';
|
|
22
23
|
import { ClientSession, maybeClearPinnedConnection } from '../sessions';
|
|
23
|
-
import { List, type MongoDBNamespace, ns } from '../utils';
|
|
24
|
+
import { List, type MongoDBNamespace, ns, squashError } from '../utils';
|
|
24
25
|
|
|
25
26
|
/** @internal */
|
|
26
27
|
const kId = Symbol('id');
|
|
@@ -109,6 +110,8 @@ export interface AbstractCursorOptions extends BSONSerializeOptions {
|
|
|
109
110
|
*/
|
|
110
111
|
awaitData?: boolean;
|
|
111
112
|
noCursorTimeout?: boolean;
|
|
113
|
+
/** @internal TODO(NODE-5688): make this public */
|
|
114
|
+
timeoutMS?: number;
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
/** @internal */
|
|
@@ -142,7 +145,13 @@ export abstract class AbstractCursor<
|
|
|
142
145
|
/** @internal */
|
|
143
146
|
[kNamespace]: MongoDBNamespace;
|
|
144
147
|
/** @internal */
|
|
145
|
-
[kDocuments]:
|
|
148
|
+
[kDocuments]: {
|
|
149
|
+
length: number;
|
|
150
|
+
shift(bsonOptions?: any): TSchema | null;
|
|
151
|
+
clear(): void;
|
|
152
|
+
pushMany(many: Iterable<TSchema>): void;
|
|
153
|
+
push(item: TSchema): void;
|
|
154
|
+
};
|
|
146
155
|
/** @internal */
|
|
147
156
|
[kClient]: MongoClient;
|
|
148
157
|
/** @internal */
|
|
@@ -184,6 +193,7 @@ export abstract class AbstractCursor<
|
|
|
184
193
|
: ReadPreference.primary,
|
|
185
194
|
...pluckBSONSerializeOptions(options)
|
|
186
195
|
};
|
|
196
|
+
this[kOptions].timeoutMS = options.timeoutMS;
|
|
187
197
|
|
|
188
198
|
const readConcern = ReadConcern.fromOptions(options);
|
|
189
199
|
if (readConcern) {
|
|
@@ -283,7 +293,7 @@ export abstract class AbstractCursor<
|
|
|
283
293
|
const documentsToRead = Math.min(number ?? this[kDocuments].length, this[kDocuments].length);
|
|
284
294
|
|
|
285
295
|
for (let count = 0; count < documentsToRead; count++) {
|
|
286
|
-
const document = this[kDocuments].shift();
|
|
296
|
+
const document = this[kDocuments].shift(this[kOptions]);
|
|
287
297
|
if (document != null) {
|
|
288
298
|
bufferedDocs.push(document);
|
|
289
299
|
}
|
|
@@ -309,7 +319,11 @@ export abstract class AbstractCursor<
|
|
|
309
319
|
const message =
|
|
310
320
|
'Cursor returned a `null` document, but the cursor is not exhausted. Mapping documents to `null` is not supported in the cursor transform.';
|
|
311
321
|
|
|
312
|
-
|
|
322
|
+
try {
|
|
323
|
+
await cleanupCursor(this, { needsToEmitClosed: true });
|
|
324
|
+
} catch (error) {
|
|
325
|
+
squashError(error);
|
|
326
|
+
}
|
|
313
327
|
|
|
314
328
|
throw new MongoAPIError(message);
|
|
315
329
|
}
|
|
@@ -327,7 +341,11 @@ export abstract class AbstractCursor<
|
|
|
327
341
|
// Only close the cursor if it has not already been closed. This finally clause handles
|
|
328
342
|
// the case when a user would break out of a for await of loop early.
|
|
329
343
|
if (!this.closed) {
|
|
330
|
-
|
|
344
|
+
try {
|
|
345
|
+
await this.close();
|
|
346
|
+
} catch (error) {
|
|
347
|
+
squashError(error);
|
|
348
|
+
}
|
|
331
349
|
}
|
|
332
350
|
}
|
|
333
351
|
}
|
|
@@ -371,14 +389,7 @@ export abstract class AbstractCursor<
|
|
|
371
389
|
return true;
|
|
372
390
|
}
|
|
373
391
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
if (doc) {
|
|
377
|
-
this[kDocuments].unshift(doc);
|
|
378
|
-
return true;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return false;
|
|
392
|
+
return await next(this, { blocking: true, transform: false, shift: false });
|
|
382
393
|
}
|
|
383
394
|
|
|
384
395
|
/** Get the next available document from the cursor, returns null if no more documents are available. */
|
|
@@ -387,7 +398,7 @@ export abstract class AbstractCursor<
|
|
|
387
398
|
throw new MongoCursorExhaustedError();
|
|
388
399
|
}
|
|
389
400
|
|
|
390
|
-
return next(this, { blocking: true, transform: true });
|
|
401
|
+
return await next(this, { blocking: true, transform: true, shift: true });
|
|
391
402
|
}
|
|
392
403
|
|
|
393
404
|
/**
|
|
@@ -398,7 +409,7 @@ export abstract class AbstractCursor<
|
|
|
398
409
|
throw new MongoCursorExhaustedError();
|
|
399
410
|
}
|
|
400
411
|
|
|
401
|
-
return next(this, { blocking: false, transform: true });
|
|
412
|
+
return await next(this, { blocking: false, transform: true, shift: true });
|
|
402
413
|
}
|
|
403
414
|
|
|
404
415
|
/**
|
|
@@ -605,7 +616,8 @@ export abstract class AbstractCursor<
|
|
|
605
616
|
// We only want to end this session if we created it, and it hasn't ended yet
|
|
606
617
|
if (session.explicit === false) {
|
|
607
618
|
if (!session.hasEnded) {
|
|
608
|
-
|
|
619
|
+
// eslint-disable-next-line github/no-then
|
|
620
|
+
session.endSession().then(undefined, squashError);
|
|
609
621
|
}
|
|
610
622
|
this[kSession] = this.client.startSession({ owner: this, explicit: false });
|
|
611
623
|
}
|
|
@@ -621,15 +633,16 @@ export abstract class AbstractCursor<
|
|
|
621
633
|
protected abstract _initialize(session: ClientSession | undefined): Promise<ExecutionResult>;
|
|
622
634
|
|
|
623
635
|
/** @internal */
|
|
624
|
-
async getMore(batchSize: number): Promise<Document | null> {
|
|
636
|
+
async getMore(batchSize: number, useCursorResponse = false): Promise<Document | null> {
|
|
625
637
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
626
638
|
const getMoreOperation = new GetMoreOperation(this[kNamespace], this[kId]!, this[kServer]!, {
|
|
627
639
|
...this[kOptions],
|
|
628
640
|
session: this[kSession],
|
|
629
|
-
batchSize
|
|
641
|
+
batchSize,
|
|
642
|
+
useCursorResponse
|
|
630
643
|
});
|
|
631
644
|
|
|
632
|
-
return executeOperation(this[kClient], getMoreOperation);
|
|
645
|
+
return await executeOperation(this[kClient], getMoreOperation);
|
|
633
646
|
}
|
|
634
647
|
|
|
635
648
|
/**
|
|
@@ -644,7 +657,11 @@ export abstract class AbstractCursor<
|
|
|
644
657
|
const state = await this._initialize(this[kSession]);
|
|
645
658
|
const response = state.response;
|
|
646
659
|
this[kServer] = state.server;
|
|
647
|
-
if (response
|
|
660
|
+
if (CursorResponse.is(response)) {
|
|
661
|
+
this[kId] = response.id;
|
|
662
|
+
if (response.ns) this[kNamespace] = response.ns;
|
|
663
|
+
this[kDocuments] = response;
|
|
664
|
+
} else if (response.cursor) {
|
|
648
665
|
// TODO(NODE-2674): Preserve int64 sent from MongoDB
|
|
649
666
|
this[kId] =
|
|
650
667
|
typeof response.cursor.id === 'number'
|
|
@@ -701,13 +718,42 @@ async function next<T>(
|
|
|
701
718
|
cursor: AbstractCursor<T>,
|
|
702
719
|
{
|
|
703
720
|
blocking,
|
|
704
|
-
transform
|
|
721
|
+
transform,
|
|
722
|
+
shift
|
|
723
|
+
}: {
|
|
724
|
+
blocking: boolean;
|
|
725
|
+
transform: boolean;
|
|
726
|
+
shift: false;
|
|
727
|
+
}
|
|
728
|
+
): Promise<boolean>;
|
|
729
|
+
|
|
730
|
+
async function next<T>(
|
|
731
|
+
cursor: AbstractCursor<T>,
|
|
732
|
+
{
|
|
733
|
+
blocking,
|
|
734
|
+
transform,
|
|
735
|
+
shift
|
|
736
|
+
}: {
|
|
737
|
+
blocking: boolean;
|
|
738
|
+
transform: boolean;
|
|
739
|
+
shift: true;
|
|
740
|
+
}
|
|
741
|
+
): Promise<T | null>;
|
|
742
|
+
|
|
743
|
+
async function next<T>(
|
|
744
|
+
cursor: AbstractCursor<T>,
|
|
745
|
+
{
|
|
746
|
+
blocking,
|
|
747
|
+
transform,
|
|
748
|
+
shift
|
|
705
749
|
}: {
|
|
706
750
|
blocking: boolean;
|
|
707
751
|
transform: boolean;
|
|
752
|
+
shift: boolean;
|
|
708
753
|
}
|
|
709
|
-
): Promise<T | null> {
|
|
754
|
+
): Promise<boolean | T | null> {
|
|
710
755
|
if (cursor.closed) {
|
|
756
|
+
if (!shift) return false;
|
|
711
757
|
return null;
|
|
712
758
|
}
|
|
713
759
|
|
|
@@ -718,15 +764,19 @@ async function next<T>(
|
|
|
718
764
|
}
|
|
719
765
|
|
|
720
766
|
if (cursor[kDocuments].length !== 0) {
|
|
721
|
-
|
|
767
|
+
if (!shift) return true;
|
|
768
|
+
const doc = cursor[kDocuments].shift(cursor[kOptions]);
|
|
722
769
|
|
|
723
770
|
if (doc != null && transform && cursor[kTransform]) {
|
|
724
771
|
try {
|
|
725
772
|
return cursor[kTransform](doc);
|
|
726
773
|
} catch (error) {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
774
|
+
try {
|
|
775
|
+
await cleanupCursor(cursor, { error, needsToEmitClosed: true });
|
|
776
|
+
} catch (error) {
|
|
777
|
+
// `cleanupCursor` should never throw, squash and throw the original error
|
|
778
|
+
squashError(error);
|
|
779
|
+
}
|
|
730
780
|
throw error;
|
|
731
781
|
}
|
|
732
782
|
}
|
|
@@ -736,9 +786,10 @@ async function next<T>(
|
|
|
736
786
|
|
|
737
787
|
if (cursor.isDead) {
|
|
738
788
|
// if the cursor is dead, we clean it up
|
|
739
|
-
//
|
|
789
|
+
// cleanupCursor should never throw, but if it does it indicates a bug in the driver
|
|
740
790
|
// and we should surface the error
|
|
741
791
|
await cleanupCursor(cursor, {});
|
|
792
|
+
if (!shift) return false;
|
|
742
793
|
return null;
|
|
743
794
|
}
|
|
744
795
|
|
|
@@ -747,8 +798,10 @@ async function next<T>(
|
|
|
747
798
|
|
|
748
799
|
try {
|
|
749
800
|
const response = await cursor.getMore(batchSize);
|
|
750
|
-
|
|
751
|
-
|
|
801
|
+
if (CursorResponse.is(response)) {
|
|
802
|
+
cursor[kId] = response.id;
|
|
803
|
+
cursor[kDocuments] = response;
|
|
804
|
+
} else if (response) {
|
|
752
805
|
const cursorId =
|
|
753
806
|
typeof response.cursor.id === 'number'
|
|
754
807
|
? Long.fromNumber(response.cursor.id)
|
|
@@ -760,9 +813,12 @@ async function next<T>(
|
|
|
760
813
|
cursor[kId] = cursorId;
|
|
761
814
|
}
|
|
762
815
|
} catch (error) {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
816
|
+
try {
|
|
817
|
+
await cleanupCursor(cursor, { error, needsToEmitClosed: true });
|
|
818
|
+
} catch (error) {
|
|
819
|
+
// `cleanupCursor` should never throw, squash and throw the original error
|
|
820
|
+
squashError(error);
|
|
821
|
+
}
|
|
766
822
|
throw error;
|
|
767
823
|
}
|
|
768
824
|
|
|
@@ -778,10 +834,12 @@ async function next<T>(
|
|
|
778
834
|
}
|
|
779
835
|
|
|
780
836
|
if (cursor[kDocuments].length === 0 && blocking === false) {
|
|
837
|
+
if (!shift) return false;
|
|
781
838
|
return null;
|
|
782
839
|
}
|
|
783
840
|
} while (!cursor.isDead || cursor[kDocuments].length !== 0);
|
|
784
841
|
|
|
842
|
+
if (!shift) return false;
|
|
785
843
|
return null;
|
|
786
844
|
}
|
|
787
845
|
|
|
@@ -802,7 +860,7 @@ async function cleanupCursor(
|
|
|
802
860
|
|
|
803
861
|
if (error) {
|
|
804
862
|
if (cursor.loadBalanced && error instanceof MongoNetworkError) {
|
|
805
|
-
return completeCleanup();
|
|
863
|
+
return await completeCleanup();
|
|
806
864
|
}
|
|
807
865
|
}
|
|
808
866
|
|
|
@@ -850,14 +908,16 @@ async function cleanupCursor(
|
|
|
850
908
|
cursor[kKilled] = true;
|
|
851
909
|
|
|
852
910
|
if (session.hasEnded) {
|
|
853
|
-
return completeCleanup();
|
|
911
|
+
return await completeCleanup();
|
|
854
912
|
}
|
|
855
913
|
|
|
856
914
|
try {
|
|
857
915
|
await executeOperation(
|
|
858
916
|
cursor[kClient],
|
|
859
917
|
new KillCursorsOperation(cursorId, cursorNs, server, { session })
|
|
860
|
-
)
|
|
918
|
+
);
|
|
919
|
+
} catch (error) {
|
|
920
|
+
squashError(error);
|
|
861
921
|
} finally {
|
|
862
922
|
await completeCleanup();
|
|
863
923
|
}
|
|
@@ -892,6 +952,7 @@ class ReadableCursorStream extends Readable {
|
|
|
892
952
|
}
|
|
893
953
|
|
|
894
954
|
override _destroy(error: Error | null, callback: (error?: Error | null) => void): void {
|
|
955
|
+
// eslint-disable-next-line github/no-then
|
|
895
956
|
this._cursor.close().then(
|
|
896
957
|
() => callback(error),
|
|
897
958
|
closeError => callback(closeError)
|
|
@@ -899,12 +960,14 @@ class ReadableCursorStream extends Readable {
|
|
|
899
960
|
}
|
|
900
961
|
|
|
901
962
|
private _readNext() {
|
|
902
|
-
next
|
|
963
|
+
// eslint-disable-next-line github/no-then
|
|
964
|
+
next(this._cursor, { blocking: true, transform: true, shift: true }).then(
|
|
903
965
|
result => {
|
|
904
966
|
if (result == null) {
|
|
905
967
|
this.push(null);
|
|
906
968
|
} else if (this.destroyed) {
|
|
907
|
-
|
|
969
|
+
// eslint-disable-next-line github/no-then
|
|
970
|
+
this._cursor.close().then(undefined, squashError);
|
|
908
971
|
} else {
|
|
909
972
|
if (this.push(result)) {
|
|
910
973
|
return this._readNext();
|
|
@@ -919,7 +982,8 @@ class ReadableCursorStream extends Readable {
|
|
|
919
982
|
// a client during iteration. Alternatively, we could do the "right" thing and
|
|
920
983
|
// propagate the error message by removing this special case.
|
|
921
984
|
if (err.message.match(/server is closed/)) {
|
|
922
|
-
|
|
985
|
+
// eslint-disable-next-line github/no-then
|
|
986
|
+
this._cursor.close().then(undefined, squashError);
|
|
923
987
|
return this.push(null);
|
|
924
988
|
}
|
|
925
989
|
|
|
@@ -76,7 +76,7 @@ export class AggregationCursor<TSchema = any> extends AbstractCursor<TSchema> {
|
|
|
76
76
|
|
|
77
77
|
/** Execute the explain for the cursor */
|
|
78
78
|
async explain(verbosity?: ExplainVerbosityLike): Promise<Document> {
|
|
79
|
-
return executeOperation(
|
|
79
|
+
return await executeOperation(
|
|
80
80
|
this.client,
|
|
81
81
|
new AggregateOperation(this.namespace, this[kPipeline], {
|
|
82
82
|
...this[kOptions], // NOTE: order matters here, we may need to refine this
|
|
@@ -86,33 +86,45 @@ export class AggregationCursor<TSchema = any> extends AbstractCursor<TSchema> {
|
|
|
86
86
|
);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/** Add a stage to the aggregation pipeline
|
|
90
|
+
* @example
|
|
91
|
+
* ```
|
|
92
|
+
* const documents = await users.aggregate().addStage({ $match: { name: /Mike/ } }).toArray();
|
|
93
|
+
* ```
|
|
94
|
+
* @example
|
|
95
|
+
* ```
|
|
96
|
+
* const documents = await users.aggregate()
|
|
97
|
+
* .addStage<{ name: string }>({ $project: { name: true } })
|
|
98
|
+
* .toArray(); // type of documents is { name: string }[]
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
addStage(stage: Document): this;
|
|
102
|
+
addStage<T = Document>(stage: Document): AggregationCursor<T>;
|
|
103
|
+
addStage<T = Document>(stage: Document): AggregationCursor<T> {
|
|
104
|
+
assertUninitialized(this);
|
|
105
|
+
this[kPipeline].push(stage);
|
|
106
|
+
return this as unknown as AggregationCursor<T>;
|
|
107
|
+
}
|
|
108
|
+
|
|
89
109
|
/** Add a group stage to the aggregation pipeline */
|
|
90
110
|
group<T = TSchema>($group: Document): AggregationCursor<T>;
|
|
91
111
|
group($group: Document): this {
|
|
92
|
-
|
|
93
|
-
this[kPipeline].push({ $group });
|
|
94
|
-
return this;
|
|
112
|
+
return this.addStage({ $group });
|
|
95
113
|
}
|
|
96
114
|
|
|
97
115
|
/** Add a limit stage to the aggregation pipeline */
|
|
98
116
|
limit($limit: number): this {
|
|
99
|
-
|
|
100
|
-
this[kPipeline].push({ $limit });
|
|
101
|
-
return this;
|
|
117
|
+
return this.addStage({ $limit });
|
|
102
118
|
}
|
|
103
119
|
|
|
104
120
|
/** Add a match stage to the aggregation pipeline */
|
|
105
121
|
match($match: Document): this {
|
|
106
|
-
|
|
107
|
-
this[kPipeline].push({ $match });
|
|
108
|
-
return this;
|
|
122
|
+
return this.addStage({ $match });
|
|
109
123
|
}
|
|
110
124
|
|
|
111
125
|
/** Add an out stage to the aggregation pipeline */
|
|
112
126
|
out($out: { db: string; coll: string } | string): this {
|
|
113
|
-
|
|
114
|
-
this[kPipeline].push({ $out });
|
|
115
|
-
return this;
|
|
127
|
+
return this.addStage({ $out });
|
|
116
128
|
}
|
|
117
129
|
|
|
118
130
|
/**
|
|
@@ -157,50 +169,36 @@ export class AggregationCursor<TSchema = any> extends AbstractCursor<TSchema> {
|
|
|
157
169
|
* ```
|
|
158
170
|
*/
|
|
159
171
|
project<T extends Document = Document>($project: Document): AggregationCursor<T> {
|
|
160
|
-
|
|
161
|
-
this[kPipeline].push({ $project });
|
|
162
|
-
return this as unknown as AggregationCursor<T>;
|
|
172
|
+
return this.addStage<T>({ $project });
|
|
163
173
|
}
|
|
164
174
|
|
|
165
175
|
/** Add a lookup stage to the aggregation pipeline */
|
|
166
176
|
lookup($lookup: Document): this {
|
|
167
|
-
|
|
168
|
-
this[kPipeline].push({ $lookup });
|
|
169
|
-
return this;
|
|
177
|
+
return this.addStage({ $lookup });
|
|
170
178
|
}
|
|
171
179
|
|
|
172
180
|
/** Add a redact stage to the aggregation pipeline */
|
|
173
181
|
redact($redact: Document): this {
|
|
174
|
-
|
|
175
|
-
this[kPipeline].push({ $redact });
|
|
176
|
-
return this;
|
|
182
|
+
return this.addStage({ $redact });
|
|
177
183
|
}
|
|
178
184
|
|
|
179
185
|
/** Add a skip stage to the aggregation pipeline */
|
|
180
186
|
skip($skip: number): this {
|
|
181
|
-
|
|
182
|
-
this[kPipeline].push({ $skip });
|
|
183
|
-
return this;
|
|
187
|
+
return this.addStage({ $skip });
|
|
184
188
|
}
|
|
185
189
|
|
|
186
190
|
/** Add a sort stage to the aggregation pipeline */
|
|
187
191
|
sort($sort: Sort): this {
|
|
188
|
-
|
|
189
|
-
this[kPipeline].push({ $sort });
|
|
190
|
-
return this;
|
|
192
|
+
return this.addStage({ $sort });
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
/** Add a unwind stage to the aggregation pipeline */
|
|
194
196
|
unwind($unwind: Document | string): this {
|
|
195
|
-
|
|
196
|
-
this[kPipeline].push({ $unwind });
|
|
197
|
-
return this;
|
|
197
|
+
return this.addStage({ $unwind });
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
/** Add a geoNear stage to the aggregation pipeline */
|
|
201
201
|
geoNear($geoNear: Document): this {
|
|
202
|
-
|
|
203
|
-
this[kPipeline].push({ $geoNear });
|
|
204
|
-
return this;
|
|
202
|
+
return this.addStage({ $geoNear });
|
|
205
203
|
}
|
|
206
204
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type Document
|
|
1
|
+
import { type Document } from '../bson';
|
|
2
|
+
import { CursorResponse } from '../cmap/wire_protocol/responses';
|
|
2
3
|
import { MongoInvalidArgumentError, MongoTailableCursorError } from '../error';
|
|
3
4
|
import { type ExplainVerbosityLike } from '../explain';
|
|
4
5
|
import type { MongoClient } from '../mongo_client';
|
|
@@ -9,7 +10,7 @@ import { FindOperation, type FindOptions } from '../operations/find';
|
|
|
9
10
|
import type { Hint } from '../operations/operation';
|
|
10
11
|
import type { ClientSession } from '../sessions';
|
|
11
12
|
import { formatSort, type Sort, type SortDirection } from '../sort';
|
|
12
|
-
import { emitWarningOnce, mergeOptions, type MongoDBNamespace } from '../utils';
|
|
13
|
+
import { emitWarningOnce, mergeOptions, type MongoDBNamespace, squashError } from '../utils';
|
|
13
14
|
import { AbstractCursor, assertUninitialized } from './abstract_cursor';
|
|
14
15
|
|
|
15
16
|
/** @internal */
|
|
@@ -34,7 +35,7 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
|
|
|
34
35
|
/** @internal */
|
|
35
36
|
[kFilter]: Document;
|
|
36
37
|
/** @internal */
|
|
37
|
-
[kNumReturned]
|
|
38
|
+
[kNumReturned] = 0;
|
|
38
39
|
/** @internal */
|
|
39
40
|
[kBuiltOptions]: FindOptions;
|
|
40
41
|
|
|
@@ -69,7 +70,7 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
|
|
|
69
70
|
|
|
70
71
|
/** @internal */
|
|
71
72
|
async _initialize(session: ClientSession): Promise<ExecutionResult> {
|
|
72
|
-
const findOperation = new FindOperation(
|
|
73
|
+
const findOperation = new FindOperation(this.namespace, this[kFilter], {
|
|
73
74
|
...this[kBuiltOptions], // NOTE: order matters here, we may need to refine this
|
|
74
75
|
...this.cursorOptions,
|
|
75
76
|
session
|
|
@@ -78,7 +79,12 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
|
|
|
78
79
|
const response = await executeOperation(this.client, findOperation);
|
|
79
80
|
|
|
80
81
|
// the response is not a cursor when `explain` is enabled
|
|
81
|
-
|
|
82
|
+
if (CursorResponse.is(response)) {
|
|
83
|
+
this[kNumReturned] = response.batchSize;
|
|
84
|
+
} else {
|
|
85
|
+
// Can be an explain response, hence the ?. on everything
|
|
86
|
+
this[kNumReturned] = this[kNumReturned] + (response?.cursor?.firstBatch?.length ?? 0);
|
|
87
|
+
}
|
|
82
88
|
|
|
83
89
|
// TODO: NODE-2882
|
|
84
90
|
return { server: findOperation.server, session, response };
|
|
@@ -94,23 +100,29 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
|
|
|
94
100
|
limit && limit > 0 && numReturned + batchSize > limit ? limit - numReturned : batchSize;
|
|
95
101
|
|
|
96
102
|
if (batchSize <= 0) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
103
|
+
try {
|
|
104
|
+
await this.close();
|
|
105
|
+
} catch (error) {
|
|
106
|
+
squashError(error);
|
|
107
|
+
// this is an optimization for the special case of a limit for a find command to avoid an
|
|
108
|
+
// extra getMore when the limit has been reached and the limit is a multiple of the batchSize.
|
|
109
|
+
// This is a consequence of the new query engine in 5.0 having no knowledge of the limit as it
|
|
110
|
+
// produces results for the find command. Once a batch is filled up, it is returned and only
|
|
111
|
+
// on the subsequent getMore will the query framework consider the limit, determine the cursor
|
|
112
|
+
// is exhausted and return a cursorId of zero.
|
|
113
|
+
// instead, if we determine there are no more documents to request from the server, we preemptively
|
|
114
|
+
// close the cursor
|
|
115
|
+
}
|
|
116
|
+
return CursorResponse.emptyGetMore;
|
|
107
117
|
}
|
|
108
118
|
}
|
|
109
119
|
|
|
110
|
-
const response = await super.getMore(batchSize);
|
|
120
|
+
const response = await super.getMore(batchSize, false);
|
|
111
121
|
// TODO: wrap this in some logic to prevent it from happening if we don't need this support
|
|
112
|
-
if (response) {
|
|
113
|
-
this[kNumReturned] = this[kNumReturned] + response.
|
|
122
|
+
if (CursorResponse.is(response)) {
|
|
123
|
+
this[kNumReturned] = this[kNumReturned] + response.batchSize;
|
|
124
|
+
} else {
|
|
125
|
+
this[kNumReturned] = this[kNumReturned] + (response?.cursor?.nextBatch?.length ?? 0);
|
|
114
126
|
}
|
|
115
127
|
|
|
116
128
|
return response;
|
|
@@ -127,7 +139,7 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
|
|
|
127
139
|
if (typeof options === 'boolean') {
|
|
128
140
|
throw new MongoInvalidArgumentError('Invalid first parameter to count');
|
|
129
141
|
}
|
|
130
|
-
return executeOperation(
|
|
142
|
+
return await executeOperation(
|
|
131
143
|
this.client,
|
|
132
144
|
new CountOperation(this.namespace, this[kFilter], {
|
|
133
145
|
...this[kBuiltOptions], // NOTE: order matters here, we may need to refine this
|
|
@@ -139,9 +151,9 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
|
|
|
139
151
|
|
|
140
152
|
/** Execute the explain for the cursor */
|
|
141
153
|
async explain(verbosity?: ExplainVerbosityLike): Promise<Document> {
|
|
142
|
-
return executeOperation(
|
|
154
|
+
return await executeOperation(
|
|
143
155
|
this.client,
|
|
144
|
-
new FindOperation(
|
|
156
|
+
new FindOperation(this.namespace, this[kFilter], {
|
|
145
157
|
...this[kBuiltOptions], // NOTE: order matters here, we may need to refine this
|
|
146
158
|
...this.cursorOptions,
|
|
147
159
|
explain: verbosity ?? true
|
|
@@ -3,7 +3,7 @@ import type { AggregateOptions } from '../operations/aggregate';
|
|
|
3
3
|
import { AggregationCursor } from './aggregation_cursor';
|
|
4
4
|
|
|
5
5
|
/** @public */
|
|
6
|
-
export type ListSearchIndexesOptions = AggregateOptions
|
|
6
|
+
export type ListSearchIndexesOptions = Omit<AggregateOptions, 'readConcern' | 'writeConcern'>;
|
|
7
7
|
|
|
8
8
|
/** @public */
|
|
9
9
|
export class ListSearchIndexesCursor extends AggregationCursor<{ name: string }> {
|
|
@@ -125,9 +125,10 @@ export class RunCommandCursor extends AbstractCursor {
|
|
|
125
125
|
const getMoreOperation = new GetMoreOperation(this.namespace, this.id!, this.server!, {
|
|
126
126
|
...this.cursorOptions,
|
|
127
127
|
session: this.session,
|
|
128
|
-
...this.getMoreOptions
|
|
128
|
+
...this.getMoreOptions,
|
|
129
|
+
useCursorResponse: false
|
|
129
130
|
});
|
|
130
131
|
|
|
131
|
-
return executeOperation(this.client, getMoreOperation);
|
|
132
|
+
return await executeOperation(this.client, getMoreOperation);
|
|
132
133
|
}
|
|
133
134
|
}
|