mongodb 6.12.0 → 6.13.0-dev.20250201.sha.35c703e3
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/lib/beta.d.ts +176 -108
- package/lib/bulk/common.js +5 -7
- package/lib/bulk/common.js.map +1 -1
- package/lib/change_stream.js +16 -26
- package/lib/change_stream.js.map +1 -1
- package/lib/client-side-encryption/auto_encrypter.js +4 -2
- package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
- package/lib/client-side-encryption/client_encryption.js +4 -4
- package/lib/client-side-encryption/client_encryption.js.map +1 -1
- package/lib/client-side-encryption/state_machine.js +56 -30
- package/lib/client-side-encryption/state_machine.js.map +1 -1
- package/lib/cmap/auth/mongodb_aws.js +1 -1
- package/lib/cmap/auth/mongodb_aws.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc.js +1 -1
- package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +9 -50
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/connection.js +28 -22
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +88 -117
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/wire_protocol/on_data.js +6 -1
- package/lib/cmap/wire_protocol/on_data.js.map +1 -1
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +68 -86
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +47 -18
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +2 -1
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +2 -1
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/cursor/list_collections_cursor.js +2 -1
- package/lib/cursor/list_collections_cursor.js.map +1 -1
- package/lib/db.js +2 -1
- package/lib/db.js.map +1 -1
- package/lib/encrypter.js +5 -9
- package/lib/encrypter.js.map +1 -1
- package/lib/error.js +10 -18
- package/lib/error.js.map +1 -1
- package/lib/index.js +5 -2
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +46 -26
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_logger.js +102 -3
- package/lib/mongo_logger.js.map +1 -1
- package/lib/operations/execute_operation.js +9 -5
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/operation.js +4 -5
- package/lib/operations/operation.js.map +1 -1
- package/lib/sdam/monitor.js +25 -31
- package/lib/sdam/monitor.js.map +1 -1
- package/lib/sdam/server.js +27 -17
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/topology.js +20 -19
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sessions.js +24 -48
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +64 -44
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +176 -108
- package/package.json +2 -2
- package/src/bulk/common.ts +6 -9
- package/src/change_stream.ts +21 -33
- package/src/client-side-encryption/auto_encrypter.ts +12 -8
- package/src/client-side-encryption/client_encryption.ts +6 -4
- package/src/client-side-encryption/state_machine.ts +80 -36
- package/src/cmap/auth/mongodb_aws.ts +1 -1
- package/src/cmap/auth/mongodb_oidc.ts +1 -1
- package/src/cmap/command_monitoring_events.ts +10 -55
- package/src/cmap/connection.ts +37 -29
- package/src/cmap/connection_pool.ts +121 -145
- package/src/cmap/wire_protocol/on_data.ts +9 -2
- package/src/collection.ts +15 -8
- package/src/connection_string.ts +74 -99
- package/src/cursor/abstract_cursor.ts +71 -23
- package/src/cursor/aggregation_cursor.ts +5 -3
- package/src/cursor/find_cursor.ts +5 -3
- package/src/cursor/list_collections_cursor.ts +5 -3
- package/src/db.ts +11 -7
- package/src/encrypter.ts +6 -11
- package/src/error.ts +11 -23
- package/src/index.ts +3 -3
- package/src/mongo_client.ts +78 -47
- package/src/mongo_logger.ts +158 -11
- package/src/mongo_types.ts +38 -0
- package/src/operations/execute_operation.ts +11 -6
- package/src/operations/list_collections.ts +4 -1
- package/src/operations/operation.ts +8 -9
- package/src/sdam/monitor.ts +30 -38
- package/src/sdam/server.ts +33 -20
- package/src/sdam/topology.ts +29 -26
- package/src/sessions.ts +37 -58
- package/src/utils.ts +79 -43
package/src/collection.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { Db } from './db';
|
|
|
14
14
|
import { MongoInvalidArgumentError, MongoOperationTimeoutError } from './error';
|
|
15
15
|
import type { MongoClient, PkFactory } from './mongo_client';
|
|
16
16
|
import type {
|
|
17
|
+
Abortable,
|
|
17
18
|
Filter,
|
|
18
19
|
Flatten,
|
|
19
20
|
OptionalUnlessRequiredId,
|
|
@@ -505,7 +506,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
505
506
|
async findOne(filter: Filter<TSchema>): Promise<WithId<TSchema> | null>;
|
|
506
507
|
async findOne(
|
|
507
508
|
filter: Filter<TSchema>,
|
|
508
|
-
options: Omit<FindOptions, 'timeoutMode'>
|
|
509
|
+
options: Omit<FindOptions, 'timeoutMode'> & Abortable
|
|
509
510
|
): Promise<WithId<TSchema> | null>;
|
|
510
511
|
|
|
511
512
|
// allow an override of the schema.
|
|
@@ -513,12 +514,12 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
513
514
|
async findOne<T = TSchema>(filter: Filter<TSchema>): Promise<T | null>;
|
|
514
515
|
async findOne<T = TSchema>(
|
|
515
516
|
filter: Filter<TSchema>,
|
|
516
|
-
options?: Omit<FindOptions, 'timeoutMode'>
|
|
517
|
+
options?: Omit<FindOptions, 'timeoutMode'> & Abortable
|
|
517
518
|
): Promise<T | null>;
|
|
518
519
|
|
|
519
520
|
async findOne(
|
|
520
521
|
filter: Filter<TSchema> = {},
|
|
521
|
-
options: FindOptions = {}
|
|
522
|
+
options: FindOptions & Abortable = {}
|
|
522
523
|
): Promise<WithId<TSchema> | null> {
|
|
523
524
|
const cursor = this.find(filter, options).limit(-1).batchSize(1);
|
|
524
525
|
const res = await cursor.next();
|
|
@@ -532,9 +533,15 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
532
533
|
* @param filter - The filter predicate. If unspecified, then all documents in the collection will match the predicate
|
|
533
534
|
*/
|
|
534
535
|
find(): FindCursor<WithId<TSchema>>;
|
|
535
|
-
find(filter: Filter<TSchema>, options?: FindOptions): FindCursor<WithId<TSchema>>;
|
|
536
|
-
find<T extends Document>(
|
|
537
|
-
|
|
536
|
+
find(filter: Filter<TSchema>, options?: FindOptions & Abortable): FindCursor<WithId<TSchema>>;
|
|
537
|
+
find<T extends Document>(
|
|
538
|
+
filter: Filter<TSchema>,
|
|
539
|
+
options?: FindOptions & Abortable
|
|
540
|
+
): FindCursor<T>;
|
|
541
|
+
find(
|
|
542
|
+
filter: Filter<TSchema> = {},
|
|
543
|
+
options: FindOptions & Abortable = {}
|
|
544
|
+
): FindCursor<WithId<TSchema>> {
|
|
538
545
|
return new FindCursor<WithId<TSchema>>(
|
|
539
546
|
this.client,
|
|
540
547
|
this.s.namespace,
|
|
@@ -792,7 +799,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
792
799
|
*/
|
|
793
800
|
async countDocuments(
|
|
794
801
|
filter: Filter<TSchema> = {},
|
|
795
|
-
options: CountDocumentsOptions = {}
|
|
802
|
+
options: CountDocumentsOptions & Abortable = {}
|
|
796
803
|
): Promise<number> {
|
|
797
804
|
const pipeline = [];
|
|
798
805
|
pipeline.push({ $match: filter });
|
|
@@ -1006,7 +1013,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
1006
1013
|
*/
|
|
1007
1014
|
aggregate<T extends Document = Document>(
|
|
1008
1015
|
pipeline: Document[] = [],
|
|
1009
|
-
options?: AggregateOptions
|
|
1016
|
+
options?: AggregateOptions & Abortable
|
|
1010
1017
|
): AggregationCursor<T> {
|
|
1011
1018
|
if (!Array.isArray(pipeline)) {
|
|
1012
1019
|
throw new MongoInvalidArgumentError(
|
package/src/connection_string.ts
CHANGED
|
@@ -22,13 +22,7 @@ import {
|
|
|
22
22
|
type ServerApi,
|
|
23
23
|
ServerApiVersion
|
|
24
24
|
} from './mongo_client';
|
|
25
|
-
import {
|
|
26
|
-
MongoLoggableComponent,
|
|
27
|
-
MongoLogger,
|
|
28
|
-
type MongoLoggerEnvOptions,
|
|
29
|
-
type MongoLoggerMongoClientOptions,
|
|
30
|
-
SeverityLevel
|
|
31
|
-
} from './mongo_logger';
|
|
25
|
+
import { MongoLoggableComponent, MongoLogger, SeverityLevel } from './mongo_logger';
|
|
32
26
|
import { ReadConcern, type ReadConcernLevel } from './read_concern';
|
|
33
27
|
import { ReadPreference, type ReadPreferenceMode } from './read_preference';
|
|
34
28
|
import { ServerMonitoringMode } from './sdam/monitor';
|
|
@@ -52,6 +46,27 @@ const LB_REPLICA_SET_ERROR = 'loadBalanced option not supported with a replicaSe
|
|
|
52
46
|
const LB_DIRECT_CONNECTION_ERROR =
|
|
53
47
|
'loadBalanced option not supported when directConnection is provided';
|
|
54
48
|
|
|
49
|
+
function retryDNSTimeoutFor(api: 'resolveSrv'): (a: string) => Promise<dns.SrvRecord[]>;
|
|
50
|
+
function retryDNSTimeoutFor(api: 'resolveTxt'): (a: string) => Promise<string[][]>;
|
|
51
|
+
function retryDNSTimeoutFor(
|
|
52
|
+
api: 'resolveSrv' | 'resolveTxt'
|
|
53
|
+
): (a: string) => Promise<dns.SrvRecord[] | string[][]> {
|
|
54
|
+
return async function dnsReqRetryTimeout(lookupAddress: string) {
|
|
55
|
+
try {
|
|
56
|
+
return await dns.promises[api](lookupAddress);
|
|
57
|
+
} catch (firstDNSError) {
|
|
58
|
+
if (firstDNSError.code === dns.TIMEOUT) {
|
|
59
|
+
return await dns.promises[api](lookupAddress);
|
|
60
|
+
} else {
|
|
61
|
+
throw firstDNSError;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const resolveSrv = retryDNSTimeoutFor('resolveSrv');
|
|
68
|
+
const resolveTxt = retryDNSTimeoutFor('resolveTxt');
|
|
69
|
+
|
|
55
70
|
/**
|
|
56
71
|
* Lookup a `mongodb+srv` connection string, combine the parts and reparse it as a normal
|
|
57
72
|
* connection string.
|
|
@@ -67,14 +82,13 @@ export async function resolveSRVRecord(options: MongoOptions): Promise<HostAddre
|
|
|
67
82
|
// Asynchronously start TXT resolution so that we do not have to wait until
|
|
68
83
|
// the SRV record is resolved before starting a second DNS query.
|
|
69
84
|
const lookupAddress = options.srvHost;
|
|
70
|
-
const txtResolutionPromise =
|
|
85
|
+
const txtResolutionPromise = resolveTxt(lookupAddress);
|
|
71
86
|
|
|
72
87
|
txtResolutionPromise.then(undefined, squashError); // rejections will be handled later
|
|
73
88
|
|
|
89
|
+
const hostname = `_${options.srvServiceName}._tcp.${lookupAddress}`;
|
|
74
90
|
// Resolve the SRV record and use the result as the list of hosts to connect to.
|
|
75
|
-
const addresses = await
|
|
76
|
-
`_${options.srvServiceName}._tcp.${lookupAddress}`
|
|
77
|
-
);
|
|
91
|
+
const addresses = await resolveSrv(hostname);
|
|
78
92
|
|
|
79
93
|
if (addresses.length === 0) {
|
|
80
94
|
throw new MongoAPIError('No addresses found at host');
|
|
@@ -249,13 +263,6 @@ export function parseOptions(
|
|
|
249
263
|
|
|
250
264
|
const mongoOptions = Object.create(null);
|
|
251
265
|
|
|
252
|
-
// Feature flags
|
|
253
|
-
for (const flag of Object.getOwnPropertySymbols(options)) {
|
|
254
|
-
if (FEATURE_FLAGS.has(flag)) {
|
|
255
|
-
mongoOptions[flag] = options[flag];
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
266
|
mongoOptions.hosts = isSRV ? [] : hosts.map(HostAddress.fromString);
|
|
260
267
|
|
|
261
268
|
const urlOptions = new CaseInsensitiveMap<unknown[]>();
|
|
@@ -515,13 +522,8 @@ export function parseOptions(
|
|
|
515
522
|
);
|
|
516
523
|
}
|
|
517
524
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
let loggerEnvOptions: MongoLoggerEnvOptions = {};
|
|
522
|
-
let loggerClientOptions: MongoLoggerMongoClientOptions = {};
|
|
523
|
-
if (mongoOptions[loggerFeatureFlag]) {
|
|
524
|
-
loggerEnvOptions = {
|
|
525
|
+
mongoOptions.mongoLoggerOptions = MongoLogger.resolveOptions(
|
|
526
|
+
{
|
|
525
527
|
MONGODB_LOG_COMMAND: process.env.MONGODB_LOG_COMMAND,
|
|
526
528
|
MONGODB_LOG_TOPOLOGY: process.env.MONGODB_LOG_TOPOLOGY,
|
|
527
529
|
MONGODB_LOG_SERVER_SELECTION: process.env.MONGODB_LOG_SERVER_SELECTION,
|
|
@@ -529,18 +531,13 @@ export function parseOptions(
|
|
|
529
531
|
MONGODB_LOG_CLIENT: process.env.MONGODB_LOG_CLIENT,
|
|
530
532
|
MONGODB_LOG_ALL: process.env.MONGODB_LOG_ALL,
|
|
531
533
|
MONGODB_LOG_MAX_DOCUMENT_LENGTH: process.env.MONGODB_LOG_MAX_DOCUMENT_LENGTH,
|
|
532
|
-
MONGODB_LOG_PATH: process.env.MONGODB_LOG_PATH
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
loggerClientOptions = {
|
|
534
|
+
MONGODB_LOG_PATH: process.env.MONGODB_LOG_PATH
|
|
535
|
+
},
|
|
536
|
+
{
|
|
536
537
|
mongodbLogPath: mongoOptions.mongodbLogPath,
|
|
537
538
|
mongodbLogComponentSeverities: mongoOptions.mongodbLogComponentSeverities,
|
|
538
539
|
mongodbLogMaxDocumentLength: mongoOptions.mongodbLogMaxDocumentLength
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
mongoOptions.mongoLoggerOptions = MongoLogger.resolveOptions(
|
|
542
|
-
loggerEnvOptions,
|
|
543
|
-
loggerClientOptions
|
|
540
|
+
}
|
|
544
541
|
);
|
|
545
542
|
|
|
546
543
|
mongoOptions.metadata = makeClientMetadata(mongoOptions);
|
|
@@ -1220,52 +1217,6 @@ export const OPTIONS = {
|
|
|
1220
1217
|
default: 0,
|
|
1221
1218
|
type: 'int'
|
|
1222
1219
|
},
|
|
1223
|
-
// Custom types for modifying core behavior
|
|
1224
|
-
connectionType: { type: 'any' },
|
|
1225
|
-
srvPoller: { type: 'any' },
|
|
1226
|
-
// Accepted Node.js Options
|
|
1227
|
-
allowPartialTrustChain: { type: 'any' },
|
|
1228
|
-
minDHSize: { type: 'any' },
|
|
1229
|
-
pskCallback: { type: 'any' },
|
|
1230
|
-
secureContext: { type: 'any' },
|
|
1231
|
-
enableTrace: { type: 'any' },
|
|
1232
|
-
requestCert: { type: 'any' },
|
|
1233
|
-
rejectUnauthorized: { type: 'any' },
|
|
1234
|
-
checkServerIdentity: { type: 'any' },
|
|
1235
|
-
ALPNProtocols: { type: 'any' },
|
|
1236
|
-
SNICallback: { type: 'any' },
|
|
1237
|
-
session: { type: 'any' },
|
|
1238
|
-
requestOCSP: { type: 'any' },
|
|
1239
|
-
localAddress: { type: 'any' },
|
|
1240
|
-
localPort: { type: 'any' },
|
|
1241
|
-
hints: { type: 'any' },
|
|
1242
|
-
lookup: { type: 'any' },
|
|
1243
|
-
ca: { type: 'any' },
|
|
1244
|
-
cert: { type: 'any' },
|
|
1245
|
-
ciphers: { type: 'any' },
|
|
1246
|
-
crl: { type: 'any' },
|
|
1247
|
-
ecdhCurve: { type: 'any' },
|
|
1248
|
-
key: { type: 'any' },
|
|
1249
|
-
passphrase: { type: 'any' },
|
|
1250
|
-
pfx: { type: 'any' },
|
|
1251
|
-
secureProtocol: { type: 'any' },
|
|
1252
|
-
index: { type: 'any' },
|
|
1253
|
-
// Legacy options from v3 era
|
|
1254
|
-
useNewUrlParser: {
|
|
1255
|
-
type: 'boolean',
|
|
1256
|
-
deprecated:
|
|
1257
|
-
'useNewUrlParser has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version'
|
|
1258
|
-
} as OptionDescriptor,
|
|
1259
|
-
useUnifiedTopology: {
|
|
1260
|
-
type: 'boolean',
|
|
1261
|
-
deprecated:
|
|
1262
|
-
'useUnifiedTopology has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version'
|
|
1263
|
-
} as OptionDescriptor,
|
|
1264
|
-
// MongoLogger
|
|
1265
|
-
/**
|
|
1266
|
-
* @internal
|
|
1267
|
-
* TODO: NODE-5671 - remove internal flag
|
|
1268
|
-
*/
|
|
1269
1220
|
mongodbLogPath: {
|
|
1270
1221
|
transform({ values: [value] }) {
|
|
1271
1222
|
if (
|
|
@@ -1284,10 +1235,6 @@ export const OPTIONS = {
|
|
|
1284
1235
|
return value;
|
|
1285
1236
|
}
|
|
1286
1237
|
},
|
|
1287
|
-
/**
|
|
1288
|
-
* @internal
|
|
1289
|
-
* TODO: NODE-5671 - remove internal flag
|
|
1290
|
-
*/
|
|
1291
1238
|
mongodbLogComponentSeverities: {
|
|
1292
1239
|
transform({ values: [value] }) {
|
|
1293
1240
|
if (typeof value !== 'object' || !value) {
|
|
@@ -1313,11 +1260,49 @@ export const OPTIONS = {
|
|
|
1313
1260
|
return value;
|
|
1314
1261
|
}
|
|
1315
1262
|
},
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1263
|
+
mongodbLogMaxDocumentLength: { type: 'uint' },
|
|
1264
|
+
// Custom types for modifying core behavior
|
|
1265
|
+
connectionType: { type: 'any' },
|
|
1266
|
+
srvPoller: { type: 'any' },
|
|
1267
|
+
// Accepted Node.js Options
|
|
1268
|
+
allowPartialTrustChain: { type: 'any' },
|
|
1269
|
+
minDHSize: { type: 'any' },
|
|
1270
|
+
pskCallback: { type: 'any' },
|
|
1271
|
+
secureContext: { type: 'any' },
|
|
1272
|
+
enableTrace: { type: 'any' },
|
|
1273
|
+
requestCert: { type: 'any' },
|
|
1274
|
+
rejectUnauthorized: { type: 'any' },
|
|
1275
|
+
checkServerIdentity: { type: 'any' },
|
|
1276
|
+
ALPNProtocols: { type: 'any' },
|
|
1277
|
+
SNICallback: { type: 'any' },
|
|
1278
|
+
session: { type: 'any' },
|
|
1279
|
+
requestOCSP: { type: 'any' },
|
|
1280
|
+
localAddress: { type: 'any' },
|
|
1281
|
+
localPort: { type: 'any' },
|
|
1282
|
+
hints: { type: 'any' },
|
|
1283
|
+
lookup: { type: 'any' },
|
|
1284
|
+
ca: { type: 'any' },
|
|
1285
|
+
cert: { type: 'any' },
|
|
1286
|
+
ciphers: { type: 'any' },
|
|
1287
|
+
crl: { type: 'any' },
|
|
1288
|
+
ecdhCurve: { type: 'any' },
|
|
1289
|
+
key: { type: 'any' },
|
|
1290
|
+
passphrase: { type: 'any' },
|
|
1291
|
+
pfx: { type: 'any' },
|
|
1292
|
+
secureProtocol: { type: 'any' },
|
|
1293
|
+
index: { type: 'any' },
|
|
1294
|
+
// Legacy options from v3 era
|
|
1295
|
+
useNewUrlParser: {
|
|
1296
|
+
type: 'boolean',
|
|
1297
|
+
deprecated:
|
|
1298
|
+
'useNewUrlParser has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version'
|
|
1299
|
+
} as OptionDescriptor,
|
|
1300
|
+
useUnifiedTopology: {
|
|
1301
|
+
type: 'boolean',
|
|
1302
|
+
deprecated:
|
|
1303
|
+
'useUnifiedTopology has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version'
|
|
1304
|
+
} as OptionDescriptor,
|
|
1305
|
+
__skipPingOnConnect: { type: 'boolean' }
|
|
1321
1306
|
} as Record<keyof MongoClientOptions, OptionDescriptor>;
|
|
1322
1307
|
|
|
1323
1308
|
export const DEFAULT_OPTIONS = new CaseInsensitiveMap(
|
|
@@ -1325,13 +1310,3 @@ export const DEFAULT_OPTIONS = new CaseInsensitiveMap(
|
|
|
1325
1310
|
.filter(([, descriptor]) => descriptor.default != null)
|
|
1326
1311
|
.map(([k, d]) => [k, d.default])
|
|
1327
1312
|
);
|
|
1328
|
-
|
|
1329
|
-
/**
|
|
1330
|
-
* Set of permitted feature flags
|
|
1331
|
-
* @internal
|
|
1332
|
-
*/
|
|
1333
|
-
export const FEATURE_FLAGS = new Set([
|
|
1334
|
-
Symbol.for('@@mdb.skipPingOnConnect'),
|
|
1335
|
-
Symbol.for('@@mdb.enableMongoLogger'),
|
|
1336
|
-
Symbol.for('@@mdb.internalLoggerConfig')
|
|
1337
|
-
]);
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
MongoTailableCursorError
|
|
13
13
|
} from '../error';
|
|
14
14
|
import type { MongoClient } from '../mongo_client';
|
|
15
|
-
import { TypedEventEmitter } from '../mongo_types';
|
|
15
|
+
import { type Abortable, TypedEventEmitter } from '../mongo_types';
|
|
16
16
|
import { executeOperation } from '../operations/execute_operation';
|
|
17
17
|
import { GetMoreOperation } from '../operations/get_more';
|
|
18
18
|
import { KillCursorsOperation } from '../operations/kill_cursors';
|
|
@@ -22,7 +22,13 @@ import { type AsyncDisposable, configureResourceManagement } from '../resource_m
|
|
|
22
22
|
import type { Server } from '../sdam/server';
|
|
23
23
|
import { ClientSession, maybeClearPinnedConnection } from '../sessions';
|
|
24
24
|
import { type CSOTTimeoutContext, type Timeout, TimeoutContext } from '../timeout';
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
addAbortListener,
|
|
27
|
+
type Disposable,
|
|
28
|
+
kDispose,
|
|
29
|
+
type MongoDBNamespace,
|
|
30
|
+
squashError
|
|
31
|
+
} from '../utils';
|
|
26
32
|
|
|
27
33
|
/**
|
|
28
34
|
* @internal
|
|
@@ -61,6 +67,10 @@ export interface CursorStreamOptions {
|
|
|
61
67
|
/** @public */
|
|
62
68
|
export type CursorFlag = (typeof CURSOR_FLAGS)[number];
|
|
63
69
|
|
|
70
|
+
function removeActiveCursor(this: AbstractCursor) {
|
|
71
|
+
this.client.s.activeCursors.delete(this);
|
|
72
|
+
}
|
|
73
|
+
|
|
64
74
|
/**
|
|
65
75
|
* @public
|
|
66
76
|
* @experimental
|
|
@@ -247,12 +257,14 @@ export abstract class AbstractCursor<
|
|
|
247
257
|
|
|
248
258
|
/** @internal */
|
|
249
259
|
protected deserializationOptions: OnDemandDocumentDeserializeOptions;
|
|
260
|
+
protected signal: AbortSignal | undefined;
|
|
261
|
+
private abortListener: Disposable | undefined;
|
|
250
262
|
|
|
251
263
|
/** @internal */
|
|
252
264
|
protected constructor(
|
|
253
265
|
client: MongoClient,
|
|
254
266
|
namespace: MongoDBNamespace,
|
|
255
|
-
options: AbstractCursorOptions = {}
|
|
267
|
+
options: AbstractCursorOptions & Abortable = {}
|
|
256
268
|
) {
|
|
257
269
|
super();
|
|
258
270
|
|
|
@@ -352,6 +364,12 @@ export abstract class AbstractCursor<
|
|
|
352
364
|
};
|
|
353
365
|
|
|
354
366
|
this.timeoutContext = options.timeoutContext;
|
|
367
|
+
this.signal = options.signal;
|
|
368
|
+
this.abortListener = addAbortListener(
|
|
369
|
+
this.signal,
|
|
370
|
+
() => void this.close().then(undefined, squashError)
|
|
371
|
+
);
|
|
372
|
+
this.trackCursor();
|
|
355
373
|
}
|
|
356
374
|
|
|
357
375
|
/**
|
|
@@ -431,6 +449,14 @@ export abstract class AbstractCursor<
|
|
|
431
449
|
await this.close();
|
|
432
450
|
}
|
|
433
451
|
|
|
452
|
+
/** Adds cursor to client's tracking so it will be closed by MongoClient.close() */
|
|
453
|
+
private trackCursor() {
|
|
454
|
+
this.cursorClient.s.activeCursors.add(this);
|
|
455
|
+
if (!this.listeners('close').includes(removeActiveCursor)) {
|
|
456
|
+
this.once('close', removeActiveCursor);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
434
460
|
/** Returns current buffered documents length */
|
|
435
461
|
bufferedCount(): number {
|
|
436
462
|
return this.documents?.length ?? 0;
|
|
@@ -455,6 +481,8 @@ export abstract class AbstractCursor<
|
|
|
455
481
|
}
|
|
456
482
|
|
|
457
483
|
async *[Symbol.asyncIterator](): AsyncGenerator<TSchema, void, void> {
|
|
484
|
+
this.signal?.throwIfAborted();
|
|
485
|
+
|
|
458
486
|
if (this.closed) {
|
|
459
487
|
return;
|
|
460
488
|
}
|
|
@@ -481,6 +509,8 @@ export abstract class AbstractCursor<
|
|
|
481
509
|
}
|
|
482
510
|
|
|
483
511
|
yield document;
|
|
512
|
+
|
|
513
|
+
this.signal?.throwIfAborted();
|
|
484
514
|
}
|
|
485
515
|
} finally {
|
|
486
516
|
// Only close the cursor if it has not already been closed. This finally clause handles
|
|
@@ -496,9 +526,16 @@ export abstract class AbstractCursor<
|
|
|
496
526
|
}
|
|
497
527
|
|
|
498
528
|
stream(options?: CursorStreamOptions): Readable & AsyncIterable<TSchema> {
|
|
529
|
+
const readable = new ReadableCursorStream(this);
|
|
530
|
+
const abortListener = addAbortListener(this.signal, function () {
|
|
531
|
+
readable.destroy(this.reason);
|
|
532
|
+
});
|
|
533
|
+
readable.once('end', () => {
|
|
534
|
+
abortListener?.[kDispose]();
|
|
535
|
+
});
|
|
536
|
+
|
|
499
537
|
if (options?.transform) {
|
|
500
538
|
const transform = options.transform;
|
|
501
|
-
const readable = new ReadableCursorStream(this);
|
|
502
539
|
|
|
503
540
|
const transformedStream = readable.pipe(
|
|
504
541
|
new Transform({
|
|
@@ -522,10 +559,12 @@ export abstract class AbstractCursor<
|
|
|
522
559
|
return transformedStream;
|
|
523
560
|
}
|
|
524
561
|
|
|
525
|
-
return
|
|
562
|
+
return readable;
|
|
526
563
|
}
|
|
527
564
|
|
|
528
565
|
async hasNext(): Promise<boolean> {
|
|
566
|
+
this.signal?.throwIfAborted();
|
|
567
|
+
|
|
529
568
|
if (this.cursorId === Long.ZERO) {
|
|
530
569
|
return false;
|
|
531
570
|
}
|
|
@@ -551,6 +590,8 @@ export abstract class AbstractCursor<
|
|
|
551
590
|
|
|
552
591
|
/** Get the next available document from the cursor, returns null if no more documents are available. */
|
|
553
592
|
async next(): Promise<TSchema | null> {
|
|
593
|
+
this.signal?.throwIfAborted();
|
|
594
|
+
|
|
554
595
|
if (this.cursorId === Long.ZERO) {
|
|
555
596
|
throw new MongoCursorExhaustedError();
|
|
556
597
|
}
|
|
@@ -581,6 +622,8 @@ export abstract class AbstractCursor<
|
|
|
581
622
|
* Try to get the next available document from the cursor or `null` if an empty batch is returned
|
|
582
623
|
*/
|
|
583
624
|
async tryNext(): Promise<TSchema | null> {
|
|
625
|
+
this.signal?.throwIfAborted();
|
|
626
|
+
|
|
584
627
|
if (this.cursorId === Long.ZERO) {
|
|
585
628
|
throw new MongoCursorExhaustedError();
|
|
586
629
|
}
|
|
@@ -620,6 +663,8 @@ export abstract class AbstractCursor<
|
|
|
620
663
|
* @deprecated - Will be removed in a future release. Use for await...of instead.
|
|
621
664
|
*/
|
|
622
665
|
async forEach(iterator: (doc: TSchema) => boolean | void): Promise<void> {
|
|
666
|
+
this.signal?.throwIfAborted();
|
|
667
|
+
|
|
623
668
|
if (typeof iterator !== 'function') {
|
|
624
669
|
throw new MongoInvalidArgumentError('Argument "iterator" must be a function');
|
|
625
670
|
}
|
|
@@ -645,6 +690,8 @@ export abstract class AbstractCursor<
|
|
|
645
690
|
* cursor.rewind() can be used to reset the cursor.
|
|
646
691
|
*/
|
|
647
692
|
async toArray(): Promise<TSchema[]> {
|
|
693
|
+
this.signal?.throwIfAborted();
|
|
694
|
+
|
|
648
695
|
const array: TSchema[] = [];
|
|
649
696
|
// at the end of the loop (since readBufferedDocuments is called) the buffer will be empty
|
|
650
697
|
// then, the 'await of' syntax will run a getMore call
|
|
@@ -824,16 +871,15 @@ export abstract class AbstractCursor<
|
|
|
824
871
|
this.isClosed = false;
|
|
825
872
|
this.isKilled = false;
|
|
826
873
|
this.initialized = false;
|
|
874
|
+
this.hasEmittedClose = false;
|
|
875
|
+
this.trackCursor();
|
|
827
876
|
|
|
828
|
-
|
|
829
|
-
if (
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
if (!session.hasEnded) {
|
|
833
|
-
session.endSession().then(undefined, squashError);
|
|
834
|
-
}
|
|
835
|
-
this.cursorSession = this.cursorClient.startSession({ owner: this, explicit: false });
|
|
877
|
+
// We only want to end this session if we created it, and it hasn't ended yet
|
|
878
|
+
if (this.cursorSession.explicit === false) {
|
|
879
|
+
if (!this.cursorSession.hasEnded) {
|
|
880
|
+
this.cursorSession.endSession().then(undefined, squashError);
|
|
836
881
|
}
|
|
882
|
+
this.cursorSession = this.cursorClient.startSession({ owner: this, explicit: false });
|
|
837
883
|
}
|
|
838
884
|
}
|
|
839
885
|
|
|
@@ -968,8 +1014,8 @@ export abstract class AbstractCursor<
|
|
|
968
1014
|
|
|
969
1015
|
/** @internal */
|
|
970
1016
|
private async cleanup(timeoutMS?: number, error?: Error) {
|
|
1017
|
+
this.abortListener?.[kDispose]();
|
|
971
1018
|
this.isClosed = true;
|
|
972
|
-
const session = this.cursorSession;
|
|
973
1019
|
const timeoutContextForKillCursors = (): CursorTimeoutContext | undefined => {
|
|
974
1020
|
if (timeoutMS != null) {
|
|
975
1021
|
this.timeoutContext?.clear();
|
|
@@ -991,7 +1037,7 @@ export abstract class AbstractCursor<
|
|
|
991
1037
|
!this.cursorId.isZero() &&
|
|
992
1038
|
this.cursorNamespace &&
|
|
993
1039
|
this.selectedServer &&
|
|
994
|
-
!
|
|
1040
|
+
!this.cursorSession.hasEnded
|
|
995
1041
|
) {
|
|
996
1042
|
this.isKilled = true;
|
|
997
1043
|
const cursorId = this.cursorId;
|
|
@@ -1000,7 +1046,7 @@ export abstract class AbstractCursor<
|
|
|
1000
1046
|
await executeOperation(
|
|
1001
1047
|
this.cursorClient,
|
|
1002
1048
|
new KillCursorsOperation(cursorId, this.cursorNamespace, this.selectedServer, {
|
|
1003
|
-
session
|
|
1049
|
+
session: this.cursorSession
|
|
1004
1050
|
}),
|
|
1005
1051
|
timeoutContextForKillCursors()
|
|
1006
1052
|
);
|
|
@@ -1008,14 +1054,16 @@ export abstract class AbstractCursor<
|
|
|
1008
1054
|
} catch (error) {
|
|
1009
1055
|
squashError(error);
|
|
1010
1056
|
} finally {
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1057
|
+
try {
|
|
1058
|
+
if (this.cursorSession?.owner === this) {
|
|
1059
|
+
await this.cursorSession.endSession({ error });
|
|
1060
|
+
}
|
|
1061
|
+
if (!this.cursorSession?.inTransaction()) {
|
|
1062
|
+
maybeClearPinnedConnection(this.cursorSession, { error });
|
|
1063
|
+
}
|
|
1064
|
+
} finally {
|
|
1065
|
+
this.emitClose();
|
|
1016
1066
|
}
|
|
1017
|
-
|
|
1018
|
-
this.emitClose();
|
|
1019
1067
|
}
|
|
1020
1068
|
}
|
|
1021
1069
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
validateExplainTimeoutOptions
|
|
9
9
|
} from '../explain';
|
|
10
10
|
import type { MongoClient } from '../mongo_client';
|
|
11
|
+
import { type Abortable } from '../mongo_types';
|
|
11
12
|
import { AggregateOperation, type AggregateOptions } from '../operations/aggregate';
|
|
12
13
|
import { executeOperation } from '../operations/execute_operation';
|
|
13
14
|
import type { ClientSession } from '../sessions';
|
|
@@ -32,14 +33,14 @@ export interface AggregationCursorOptions extends AbstractCursorOptions, Aggrega
|
|
|
32
33
|
export class AggregationCursor<TSchema = any> extends ExplainableCursor<TSchema> {
|
|
33
34
|
public readonly pipeline: Document[];
|
|
34
35
|
/** @internal */
|
|
35
|
-
private aggregateOptions: AggregateOptions;
|
|
36
|
+
private aggregateOptions: AggregateOptions & Abortable;
|
|
36
37
|
|
|
37
38
|
/** @internal */
|
|
38
39
|
constructor(
|
|
39
40
|
client: MongoClient,
|
|
40
41
|
namespace: MongoDBNamespace,
|
|
41
42
|
pipeline: Document[] = [],
|
|
42
|
-
options: AggregateOptions = {}
|
|
43
|
+
options: AggregateOptions & Abortable = {}
|
|
43
44
|
) {
|
|
44
45
|
super(client, namespace, options);
|
|
45
46
|
|
|
@@ -73,7 +74,8 @@ export class AggregationCursor<TSchema = any> extends ExplainableCursor<TSchema>
|
|
|
73
74
|
const options = {
|
|
74
75
|
...this.aggregateOptions,
|
|
75
76
|
...this.cursorOptions,
|
|
76
|
-
session
|
|
77
|
+
session,
|
|
78
|
+
signal: this.signal
|
|
77
79
|
};
|
|
78
80
|
if (options.explain) {
|
|
79
81
|
try {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
validateExplainTimeoutOptions
|
|
10
10
|
} from '../explain';
|
|
11
11
|
import type { MongoClient } from '../mongo_client';
|
|
12
|
+
import { type Abortable } from '../mongo_types';
|
|
12
13
|
import type { CollationOptions } from '../operations/command';
|
|
13
14
|
import { CountOperation, type CountOptions } from '../operations/count';
|
|
14
15
|
import { executeOperation } from '../operations/execute_operation';
|
|
@@ -36,14 +37,14 @@ export class FindCursor<TSchema = any> extends ExplainableCursor<TSchema> {
|
|
|
36
37
|
/** @internal */
|
|
37
38
|
private numReturned = 0;
|
|
38
39
|
/** @internal */
|
|
39
|
-
private readonly findOptions: FindOptions;
|
|
40
|
+
private readonly findOptions: FindOptions & Abortable;
|
|
40
41
|
|
|
41
42
|
/** @internal */
|
|
42
43
|
constructor(
|
|
43
44
|
client: MongoClient,
|
|
44
45
|
namespace: MongoDBNamespace,
|
|
45
46
|
filter: Document = {},
|
|
46
|
-
options: FindOptions = {}
|
|
47
|
+
options: FindOptions & Abortable = {}
|
|
47
48
|
) {
|
|
48
49
|
super(client, namespace, options);
|
|
49
50
|
|
|
@@ -72,7 +73,8 @@ export class FindCursor<TSchema = any> extends ExplainableCursor<TSchema> {
|
|
|
72
73
|
const options = {
|
|
73
74
|
...this.findOptions, // NOTE: order matters here, we may need to refine this
|
|
74
75
|
...this.cursorOptions,
|
|
75
|
-
session
|
|
76
|
+
session,
|
|
77
|
+
signal: this.signal
|
|
76
78
|
};
|
|
77
79
|
|
|
78
80
|
if (options.explain) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Document } from '../bson';
|
|
2
2
|
import type { Db } from '../db';
|
|
3
|
+
import { type Abortable } from '../mongo_types';
|
|
3
4
|
import { executeOperation } from '../operations/execute_operation';
|
|
4
5
|
import {
|
|
5
6
|
type CollectionInfo,
|
|
@@ -17,9 +18,9 @@ export class ListCollectionsCursor<
|
|
|
17
18
|
> extends AbstractCursor<T> {
|
|
18
19
|
parent: Db;
|
|
19
20
|
filter: Document;
|
|
20
|
-
options?: ListCollectionsOptions;
|
|
21
|
+
options?: ListCollectionsOptions & Abortable;
|
|
21
22
|
|
|
22
|
-
constructor(db: Db, filter: Document, options?: ListCollectionsOptions) {
|
|
23
|
+
constructor(db: Db, filter: Document, options?: ListCollectionsOptions & Abortable) {
|
|
23
24
|
super(db.client, db.s.namespace, options);
|
|
24
25
|
this.parent = db;
|
|
25
26
|
this.filter = filter;
|
|
@@ -38,7 +39,8 @@ export class ListCollectionsCursor<
|
|
|
38
39
|
const operation = new ListCollectionsOperation(this.parent, this.filter, {
|
|
39
40
|
...this.cursorOptions,
|
|
40
41
|
...this.options,
|
|
41
|
-
session
|
|
42
|
+
session,
|
|
43
|
+
signal: this.signal
|
|
42
44
|
});
|
|
43
45
|
|
|
44
46
|
const response = await executeOperation(this.parent.client, operation, this.timeoutContext);
|