mongodb 4.7.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/bson.js +4 -2
- package/lib/bson.js.map +1 -1
- package/lib/bulk/common.js +1 -0
- package/lib/bulk/common.js.map +1 -1
- package/lib/change_stream.js +136 -271
- package/lib/change_stream.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +2 -32
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/commands.js +1 -153
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connect.js +3 -6
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +21 -84
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +196 -170
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/message_stream.js.map +1 -1
- package/lib/cmap/wire_protocol/compression.js +2 -6
- package/lib/cmap/wire_protocol/compression.js.map +1 -1
- package/lib/cmap/wire_protocol/constants.js +1 -3
- package/lib/cmap/wire_protocol/constants.js.map +1 -1
- package/lib/collection.js +24 -9
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +62 -75
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/change_stream_cursor.js +115 -0
- package/lib/cursor/change_stream_cursor.js.map +1 -0
- package/lib/cursor/list_collections_cursor.js +37 -0
- package/lib/cursor/list_collections_cursor.js.map +1 -0
- package/lib/cursor/list_indexes_cursor.js +36 -0
- package/lib/cursor/list_indexes_cursor.js.map +1 -0
- package/lib/db.js +2 -2
- package/lib/db.js.map +1 -1
- package/lib/deps.js.map +1 -1
- package/lib/encrypter.js +3 -13
- package/lib/encrypter.js.map +1 -1
- package/lib/index.js +28 -21
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +62 -21
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_types.js.map +1 -1
- package/lib/operations/common_functions.js.map +1 -1
- package/lib/operations/create_collection.js.map +1 -1
- package/lib/operations/distinct.js +5 -5
- package/lib/operations/distinct.js.map +1 -1
- package/lib/operations/estimated_document_count.js +5 -0
- package/lib/operations/estimated_document_count.js.map +1 -1
- package/lib/operations/execute_operation.js +17 -8
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js +3 -0
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/get_more.js +32 -7
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js +39 -65
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/kill_cursors.js +32 -0
- package/lib/operations/kill_cursors.js.map +1 -0
- package/lib/operations/list_collections.js +1 -33
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/operation.js +4 -1
- package/lib/operations/operation.js.map +1 -1
- package/lib/read_preference.js.map +1 -1
- package/lib/sdam/common.js +2 -1
- package/lib/sdam/common.js.map +1 -1
- package/lib/sdam/monitor.js +2 -1
- package/lib/sdam/monitor.js.map +1 -1
- package/lib/sdam/server.js +1 -52
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +51 -58
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/srv_polling.js +2 -2
- package/lib/sdam/srv_polling.js.map +1 -1
- package/lib/sdam/topology.js +28 -67
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sdam/topology_description.js +24 -42
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +29 -31
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +65 -70
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +136 -73
- package/package.json +23 -22
- package/src/bson.ts +4 -0
- package/src/bulk/common.ts +1 -0
- package/src/change_stream.ts +147 -373
- package/src/cmap/command_monitoring_events.ts +3 -37
- package/src/cmap/commands.ts +2 -190
- package/src/cmap/connect.ts +20 -25
- package/src/cmap/connection.ts +27 -139
- package/src/cmap/connection_pool.ts +208 -169
- package/src/cmap/message_stream.ts +2 -3
- package/src/cmap/wire_protocol/compression.ts +8 -6
- package/src/cmap/wire_protocol/constants.ts +0 -2
- package/src/collection.ts +27 -13
- package/src/connection_string.ts +1 -1
- package/src/cursor/abstract_cursor.ts +98 -87
- package/src/cursor/change_stream_cursor.ts +194 -0
- package/src/cursor/list_collections_cursor.ts +52 -0
- package/src/cursor/list_indexes_cursor.ts +41 -0
- package/src/db.ts +2 -5
- package/src/deps.ts +13 -22
- package/src/encrypter.ts +4 -14
- package/src/index.ts +13 -9
- package/src/mongo_client.ts +102 -33
- package/src/mongo_types.ts +81 -57
- package/src/operations/common_functions.ts +1 -1
- package/src/operations/create_collection.ts +1 -2
- package/src/operations/distinct.ts +7 -9
- package/src/operations/estimated_document_count.ts +6 -0
- package/src/operations/execute_operation.ts +17 -8
- package/src/operations/find.ts +9 -0
- package/src/operations/get_more.ts +56 -13
- package/src/operations/indexes.ts +52 -89
- package/src/operations/kill_cursors.ts +53 -0
- package/src/operations/list_collections.ts +0 -43
- package/src/operations/operation.ts +5 -1
- package/src/read_preference.ts +5 -9
- package/src/sdam/common.ts +2 -0
- package/src/sdam/monitor.ts +2 -1
- package/src/sdam/server.ts +4 -89
- package/src/sdam/server_description.ts +70 -80
- package/src/sdam/srv_polling.ts +1 -1
- package/src/sdam/topology.ts +37 -103
- package/src/sdam/topology_description.ts +44 -68
- package/src/sessions.ts +32 -39
- package/src/utils.ts +78 -75
package/src/collection.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { UnorderedBulkOperation } from './bulk/unordered';
|
|
|
5
5
|
import { ChangeStream, ChangeStreamDocument, ChangeStreamOptions } from './change_stream';
|
|
6
6
|
import { AggregationCursor } from './cursor/aggregation_cursor';
|
|
7
7
|
import { FindCursor } from './cursor/find_cursor';
|
|
8
|
+
import { ListIndexesCursor } from './cursor/list_indexes_cursor';
|
|
8
9
|
import type { Db } from './db';
|
|
9
10
|
import { MongoInvalidArgumentError } from './error';
|
|
10
11
|
import type { Logger, LoggerOptions } from './logger';
|
|
@@ -57,7 +58,6 @@ import {
|
|
|
57
58
|
IndexExistsOperation,
|
|
58
59
|
IndexInformationOperation,
|
|
59
60
|
IndexSpecification,
|
|
60
|
-
ListIndexesCursor,
|
|
61
61
|
ListIndexesOptions
|
|
62
62
|
} from './operations/indexes';
|
|
63
63
|
import {
|
|
@@ -725,7 +725,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
725
725
|
}
|
|
726
726
|
|
|
727
727
|
if (typeof filter === 'function') {
|
|
728
|
-
callback = filter
|
|
728
|
+
callback = filter;
|
|
729
729
|
filter = {};
|
|
730
730
|
options = {};
|
|
731
731
|
}
|
|
@@ -1128,7 +1128,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
1128
1128
|
this.s.db.s.client,
|
|
1129
1129
|
new CountDocumentsOperation(
|
|
1130
1130
|
this as TODO_NODE_3286,
|
|
1131
|
-
filter
|
|
1131
|
+
filter,
|
|
1132
1132
|
resolveOptions(this, options as CountDocumentsOptions)
|
|
1133
1133
|
),
|
|
1134
1134
|
callback
|
|
@@ -1191,7 +1191,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
1191
1191
|
callback?: Callback<any[]>
|
|
1192
1192
|
): Promise<any[]> | void {
|
|
1193
1193
|
if (typeof filter === 'function') {
|
|
1194
|
-
(callback = filter
|
|
1194
|
+
(callback = filter), (filter = {}), (options = {});
|
|
1195
1195
|
} else {
|
|
1196
1196
|
if (arguments.length === 3 && typeof options === 'function') {
|
|
1197
1197
|
(callback = options), (options = {});
|
|
@@ -1544,12 +1544,26 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
1544
1544
|
);
|
|
1545
1545
|
}
|
|
1546
1546
|
|
|
1547
|
-
/**
|
|
1547
|
+
/**
|
|
1548
|
+
* Initiate an Out of order batch write operation. All operations will be buffered into insert/update/remove commands executed out of order.
|
|
1549
|
+
*
|
|
1550
|
+
* @throws MongoNotConnectedError
|
|
1551
|
+
* @remarks
|
|
1552
|
+
* **NOTE:** MongoClient must be connected prior to calling this method due to a known limitation in this legacy implemenation.
|
|
1553
|
+
* However, `collection.bulkWrite()` provides an equivalent API that does not require prior connecting.
|
|
1554
|
+
*/
|
|
1548
1555
|
initializeUnorderedBulkOp(options?: BulkWriteOptions): UnorderedBulkOperation {
|
|
1549
1556
|
return new UnorderedBulkOperation(this as TODO_NODE_3286, resolveOptions(this, options));
|
|
1550
1557
|
}
|
|
1551
1558
|
|
|
1552
|
-
/**
|
|
1559
|
+
/**
|
|
1560
|
+
* Initiate an In order bulk write operation. Operations will be serially executed in the order they are added, creating a new operation for each switch in types.
|
|
1561
|
+
*
|
|
1562
|
+
* @throws MongoNotConnectedError
|
|
1563
|
+
* @remarks
|
|
1564
|
+
* **NOTE:** MongoClient must be connected prior to calling this method due to a known limitation in this legacy implemenation.
|
|
1565
|
+
* However, `collection.bulkWrite()` provides an equivalent API that does not require prior connecting.
|
|
1566
|
+
*/
|
|
1553
1567
|
initializeOrderedBulkOp(options?: BulkWriteOptions): OrderedBulkOperation {
|
|
1554
1568
|
return new OrderedBulkOperation(this as TODO_NODE_3286, resolveOptions(this, options));
|
|
1555
1569
|
}
|
|
@@ -1596,13 +1610,13 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
1596
1610
|
* Updates documents.
|
|
1597
1611
|
*
|
|
1598
1612
|
* @deprecated use updateOne, updateMany or bulkWrite
|
|
1599
|
-
* @param
|
|
1613
|
+
* @param filter - The filter for the update operation.
|
|
1600
1614
|
* @param update - The update operations to be applied to the documents
|
|
1601
1615
|
* @param options - Optional settings for the command
|
|
1602
1616
|
* @param callback - An optional callback, a Promise will be returned if none is provided
|
|
1603
1617
|
*/
|
|
1604
1618
|
update(
|
|
1605
|
-
|
|
1619
|
+
filter: Filter<TSchema>,
|
|
1606
1620
|
update: UpdateFilter<TSchema>,
|
|
1607
1621
|
options: UpdateOptions,
|
|
1608
1622
|
callback: Callback<Document>
|
|
@@ -1613,19 +1627,19 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
1613
1627
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
1614
1628
|
options = options ?? {};
|
|
1615
1629
|
|
|
1616
|
-
return this.updateMany(
|
|
1630
|
+
return this.updateMany(filter, update, options, callback);
|
|
1617
1631
|
}
|
|
1618
1632
|
|
|
1619
1633
|
/**
|
|
1620
1634
|
* Remove documents.
|
|
1621
1635
|
*
|
|
1622
1636
|
* @deprecated use deleteOne, deleteMany or bulkWrite
|
|
1623
|
-
* @param
|
|
1637
|
+
* @param filter - The filter for the remove operation.
|
|
1624
1638
|
* @param options - Optional settings for the command
|
|
1625
1639
|
* @param callback - An optional callback, a Promise will be returned if none is provided
|
|
1626
1640
|
*/
|
|
1627
1641
|
remove(
|
|
1628
|
-
|
|
1642
|
+
filter: Filter<TSchema>,
|
|
1629
1643
|
options: DeleteOptions,
|
|
1630
1644
|
callback: Callback
|
|
1631
1645
|
): Promise<DeleteResult> | void {
|
|
@@ -1635,7 +1649,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
1635
1649
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
1636
1650
|
options = options ?? {};
|
|
1637
1651
|
|
|
1638
|
-
return this.deleteMany(
|
|
1652
|
+
return this.deleteMany(filter, options, callback);
|
|
1639
1653
|
}
|
|
1640
1654
|
|
|
1641
1655
|
/**
|
|
@@ -1667,7 +1681,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
1667
1681
|
callback?: Callback<number>
|
|
1668
1682
|
): Promise<number> | void {
|
|
1669
1683
|
if (typeof filter === 'function') {
|
|
1670
|
-
(callback = filter
|
|
1684
|
+
(callback = filter), (filter = {}), (options = {});
|
|
1671
1685
|
} else {
|
|
1672
1686
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
1673
1687
|
}
|
package/src/connection_string.ts
CHANGED
|
@@ -1188,7 +1188,7 @@ export const OPTIONS = {
|
|
|
1188
1188
|
|
|
1189
1189
|
throw new MongoParseError(`Invalid WriteConcern cannot parse: ${JSON.stringify(value)}`);
|
|
1190
1190
|
}
|
|
1191
|
-
}
|
|
1191
|
+
},
|
|
1192
1192
|
wtimeout: {
|
|
1193
1193
|
deprecated: 'Please use wtimeoutMS instead',
|
|
1194
1194
|
target: 'writeConcern',
|
|
@@ -14,6 +14,7 @@ import type { MongoClient } from '../mongo_client';
|
|
|
14
14
|
import { TODO_NODE_3286, TypedEventEmitter } from '../mongo_types';
|
|
15
15
|
import { executeOperation, ExecutionResult } from '../operations/execute_operation';
|
|
16
16
|
import { GetMoreOperation } from '../operations/get_more';
|
|
17
|
+
import { KillCursorsOperation } from '../operations/kill_cursors';
|
|
17
18
|
import { ReadConcern, ReadConcernLike } from '../read_concern';
|
|
18
19
|
import { ReadPreference, ReadPreferenceLike } from '../read_preference';
|
|
19
20
|
import type { Server } from '../sdam/server';
|
|
@@ -66,7 +67,7 @@ export interface CursorCloseOptions {
|
|
|
66
67
|
/** @public */
|
|
67
68
|
export interface CursorStreamOptions {
|
|
68
69
|
/** A transformation method applied to each document emitted by the stream */
|
|
69
|
-
transform?(doc: Document): Document;
|
|
70
|
+
transform?(this: void, doc: Document): Document;
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
/** @public */
|
|
@@ -77,8 +78,20 @@ export interface AbstractCursorOptions extends BSONSerializeOptions {
|
|
|
77
78
|
session?: ClientSession;
|
|
78
79
|
readPreference?: ReadPreferenceLike;
|
|
79
80
|
readConcern?: ReadConcernLike;
|
|
81
|
+
/**
|
|
82
|
+
* Specifies the number of documents to return in each response from MongoDB
|
|
83
|
+
*/
|
|
80
84
|
batchSize?: number;
|
|
85
|
+
/**
|
|
86
|
+
* When applicable `maxTimeMS` controls the amount of time the initial command
|
|
87
|
+
* that constructs a cursor should take. (ex. find, aggregate, listCollections)
|
|
88
|
+
*/
|
|
81
89
|
maxTimeMS?: number;
|
|
90
|
+
/**
|
|
91
|
+
* When applicable `maxAwaitTimeMS` controls the amount of time subsequent getMores
|
|
92
|
+
* that a cursor uses to fetch more data should take. (ex. cursor.next())
|
|
93
|
+
*/
|
|
94
|
+
maxAwaitTimeMS?: number;
|
|
82
95
|
/**
|
|
83
96
|
* Comment to apply to the operation.
|
|
84
97
|
*
|
|
@@ -88,7 +101,19 @@ export interface AbstractCursorOptions extends BSONSerializeOptions {
|
|
|
88
101
|
* In server versions 4.4 and above, 'comment' can be any valid BSON type.
|
|
89
102
|
*/
|
|
90
103
|
comment?: unknown;
|
|
104
|
+
/**
|
|
105
|
+
* By default, MongoDB will automatically close a cursor when the
|
|
106
|
+
* client has exhausted all results in the cursor. However, for [capped collections](https://www.mongodb.com/docs/manual/core/capped-collections)
|
|
107
|
+
* you may use a Tailable Cursor that remains open after the client exhausts
|
|
108
|
+
* the results in the initial cursor.
|
|
109
|
+
*/
|
|
91
110
|
tailable?: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* If awaitData is set to true, when the cursor reaches the end of the capped collection,
|
|
113
|
+
* MongoDB blocks the query thread for a period of time waiting for new data to arrive.
|
|
114
|
+
* When new data is inserted into the capped collection, the blocked thread is signaled
|
|
115
|
+
* to wake up and return the next batch to the client.
|
|
116
|
+
*/
|
|
92
117
|
awaitData?: boolean;
|
|
93
118
|
noCursorTimeout?: boolean;
|
|
94
119
|
}
|
|
@@ -118,7 +143,7 @@ export abstract class AbstractCursor<
|
|
|
118
143
|
/** @internal */
|
|
119
144
|
[kId]?: Long;
|
|
120
145
|
/** @internal */
|
|
121
|
-
[kSession]
|
|
146
|
+
[kSession]: ClientSession;
|
|
122
147
|
/** @internal */
|
|
123
148
|
[kServer]?: Server;
|
|
124
149
|
/** @internal */
|
|
@@ -154,7 +179,7 @@ export abstract class AbstractCursor<
|
|
|
154
179
|
}
|
|
155
180
|
this[kClient] = client;
|
|
156
181
|
this[kNamespace] = namespace;
|
|
157
|
-
this[kDocuments] = [];
|
|
182
|
+
this[kDocuments] = [];
|
|
158
183
|
this[kInitialized] = false;
|
|
159
184
|
this[kClosed] = false;
|
|
160
185
|
this[kKilled] = false;
|
|
@@ -185,8 +210,14 @@ export abstract class AbstractCursor<
|
|
|
185
210
|
this[kOptions].maxTimeMS = options.maxTimeMS;
|
|
186
211
|
}
|
|
187
212
|
|
|
213
|
+
if (typeof options.maxAwaitTimeMS === 'number') {
|
|
214
|
+
this[kOptions].maxAwaitTimeMS = options.maxAwaitTimeMS;
|
|
215
|
+
}
|
|
216
|
+
|
|
188
217
|
if (options.session instanceof ClientSession) {
|
|
189
218
|
this[kSession] = options.session;
|
|
219
|
+
} else {
|
|
220
|
+
this[kSession] = this[kClient].startSession({ owner: this, explicit: false });
|
|
190
221
|
}
|
|
191
222
|
}
|
|
192
223
|
|
|
@@ -217,11 +248,11 @@ export abstract class AbstractCursor<
|
|
|
217
248
|
}
|
|
218
249
|
|
|
219
250
|
/** @internal */
|
|
220
|
-
get session(): ClientSession
|
|
251
|
+
get session(): ClientSession {
|
|
221
252
|
return this[kSession];
|
|
222
253
|
}
|
|
223
254
|
|
|
224
|
-
set session(clientSession: ClientSession
|
|
255
|
+
set session(clientSession: ClientSession) {
|
|
225
256
|
this[kSession] = clientSession;
|
|
226
257
|
}
|
|
227
258
|
|
|
@@ -264,7 +295,7 @@ export abstract class AbstractCursor<
|
|
|
264
295
|
stream(options?: CursorStreamOptions): Readable & AsyncIterable<TSchema> {
|
|
265
296
|
if (options?.transform) {
|
|
266
297
|
const transform = options.transform;
|
|
267
|
-
const readable =
|
|
298
|
+
const readable = new ReadableCursorStream(this);
|
|
268
299
|
|
|
269
300
|
return readable.pipe(
|
|
270
301
|
new Transform({
|
|
@@ -282,7 +313,7 @@ export abstract class AbstractCursor<
|
|
|
282
313
|
);
|
|
283
314
|
}
|
|
284
315
|
|
|
285
|
-
return
|
|
316
|
+
return new ReadableCursorStream(this);
|
|
286
317
|
}
|
|
287
318
|
|
|
288
319
|
hasNext(): Promise<boolean>;
|
|
@@ -592,11 +623,12 @@ export abstract class AbstractCursor<
|
|
|
592
623
|
const session = this[kSession];
|
|
593
624
|
if (session) {
|
|
594
625
|
// We only want to end this session if we created it, and it hasn't ended yet
|
|
595
|
-
if (session.explicit === false
|
|
596
|
-
session.
|
|
626
|
+
if (session.explicit === false) {
|
|
627
|
+
if (!session.hasEnded) {
|
|
628
|
+
session.endSession().catch(() => null);
|
|
629
|
+
}
|
|
630
|
+
this[kSession] = this.client.startSession({ owner: this, explicit: false });
|
|
597
631
|
}
|
|
598
|
-
|
|
599
|
-
this[kSession] = undefined;
|
|
600
632
|
}
|
|
601
633
|
}
|
|
602
634
|
|
|
@@ -613,21 +645,8 @@ export abstract class AbstractCursor<
|
|
|
613
645
|
|
|
614
646
|
/** @internal */
|
|
615
647
|
_getMore(batchSize: number, callback: Callback<Document>): void {
|
|
616
|
-
|
|
617
|
-
const
|
|
618
|
-
const server = this[kServer];
|
|
619
|
-
|
|
620
|
-
if (cursorId == null) {
|
|
621
|
-
callback(new MongoRuntimeError('Unable to iterate cursor with no id'));
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
if (server == null) {
|
|
626
|
-
callback(new MongoRuntimeError('Unable to iterate cursor without selected server'));
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
const getMoreOperation = new GetMoreOperation(cursorNs, cursorId, server, {
|
|
648
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
649
|
+
const getMoreOperation = new GetMoreOperation(this[kNamespace], this[kId]!, this[kServer]!, {
|
|
631
650
|
...this[kOptions],
|
|
632
651
|
session: this[kSession],
|
|
633
652
|
batchSize
|
|
@@ -644,24 +663,13 @@ export abstract class AbstractCursor<
|
|
|
644
663
|
* a significant refactor.
|
|
645
664
|
*/
|
|
646
665
|
[kInit](callback: Callback<TSchema | null>): void {
|
|
647
|
-
if (this[kSession] == null) {
|
|
648
|
-
if (this[kClient].topology?.shouldCheckForSessionSupport()) {
|
|
649
|
-
return this[kClient].topology?.selectServer(ReadPreference.primaryPreferred, {}, err => {
|
|
650
|
-
if (err) return callback(err);
|
|
651
|
-
return this[kInit](callback);
|
|
652
|
-
});
|
|
653
|
-
} else if (this[kClient].topology?.hasSessionSupport()) {
|
|
654
|
-
this[kSession] = this[kClient].topology?.startSession({ owner: this, explicit: false });
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
|
|
658
666
|
this._initialize(this[kSession], (err, state) => {
|
|
659
667
|
if (state) {
|
|
660
668
|
const response = state.response;
|
|
661
669
|
this[kServer] = state.server;
|
|
662
|
-
this[kSession] = state.session;
|
|
663
670
|
|
|
664
671
|
if (response.cursor) {
|
|
672
|
+
// TODO(NODE-2674): Preserve int64 sent from MongoDB
|
|
665
673
|
this[kId] =
|
|
666
674
|
typeof response.cursor.id === 'number'
|
|
667
675
|
? Long.fromNumber(response.cursor.id)
|
|
@@ -714,7 +722,21 @@ function nextDocument<T>(cursor: AbstractCursor): T | null {
|
|
|
714
722
|
return null;
|
|
715
723
|
}
|
|
716
724
|
|
|
717
|
-
|
|
725
|
+
/**
|
|
726
|
+
* @param cursor - the cursor on which to call `next`
|
|
727
|
+
* @param blocking - a boolean indicating whether or not the cursor should `block` until data
|
|
728
|
+
* is available. Generally, this flag is set to `false` because if the getMore returns no documents,
|
|
729
|
+
* the cursor has been exhausted. In certain scenarios (ChangeStreams, tailable await cursors and
|
|
730
|
+
* `tryNext`, for example) blocking is necessary because a getMore returning no documents does
|
|
731
|
+
* not indicate the end of the cursor.
|
|
732
|
+
* @param callback - callback to return the result to the caller
|
|
733
|
+
* @returns
|
|
734
|
+
*/
|
|
735
|
+
export function next<T>(
|
|
736
|
+
cursor: AbstractCursor<T>,
|
|
737
|
+
blocking: boolean,
|
|
738
|
+
callback: Callback<T | null>
|
|
739
|
+
): void {
|
|
718
740
|
const cursorId = cursor[kId];
|
|
719
741
|
if (cursor.closed) {
|
|
720
742
|
return callback(undefined, null);
|
|
@@ -829,11 +851,11 @@ function cleanupCursor(
|
|
|
829
851
|
}
|
|
830
852
|
|
|
831
853
|
cursor[kKilled] = true;
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
[
|
|
835
|
-
|
|
836
|
-
|
|
854
|
+
|
|
855
|
+
return executeOperation(
|
|
856
|
+
cursor[kClient],
|
|
857
|
+
new KillCursorsOperation(cursorId, cursorNs, server, { session }),
|
|
858
|
+
completeCleanup
|
|
837
859
|
);
|
|
838
860
|
}
|
|
839
861
|
|
|
@@ -844,50 +866,41 @@ export function assertUninitialized(cursor: AbstractCursor): void {
|
|
|
844
866
|
}
|
|
845
867
|
}
|
|
846
868
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
autoDestroy: false,
|
|
851
|
-
highWaterMark: 1
|
|
852
|
-
});
|
|
853
|
-
|
|
854
|
-
let initialized = false;
|
|
855
|
-
let reading = false;
|
|
856
|
-
let needToClose = true; // NOTE: we must close the cursor if we never read from it, use `_construct` in future node versions
|
|
857
|
-
|
|
858
|
-
readable._read = function () {
|
|
859
|
-
if (initialized === false) {
|
|
860
|
-
needToClose = false;
|
|
861
|
-
initialized = true;
|
|
862
|
-
}
|
|
869
|
+
class ReadableCursorStream extends Readable {
|
|
870
|
+
private _cursor: AbstractCursor;
|
|
871
|
+
private _readInProgress = false;
|
|
863
872
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
873
|
+
constructor(cursor: AbstractCursor) {
|
|
874
|
+
super({
|
|
875
|
+
objectMode: true,
|
|
876
|
+
autoDestroy: false,
|
|
877
|
+
highWaterMark: 1
|
|
878
|
+
});
|
|
879
|
+
this._cursor = cursor;
|
|
880
|
+
}
|
|
869
881
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
882
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
883
|
+
override _read(size: number): void {
|
|
884
|
+
if (!this._readInProgress) {
|
|
885
|
+
this._readInProgress = true;
|
|
886
|
+
this._readNext();
|
|
875
887
|
}
|
|
876
|
-
}
|
|
888
|
+
}
|
|
877
889
|
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
needToClose = err ? !cursor.closed : result != null;
|
|
890
|
+
override _destroy(error: Error | null, callback: (error?: Error | null) => void): void {
|
|
891
|
+
this._cursor.close(err => process.nextTick(callback, err || error));
|
|
892
|
+
}
|
|
882
893
|
|
|
894
|
+
private _readNext() {
|
|
895
|
+
next(this._cursor, true, (err, result) => {
|
|
883
896
|
if (err) {
|
|
884
897
|
// NOTE: This is questionable, but we have a test backing the behavior. It seems the
|
|
885
898
|
// desired behavior is that a stream ends cleanly when a user explicitly closes
|
|
886
899
|
// a client during iteration. Alternatively, we could do the "right" thing and
|
|
887
900
|
// propagate the error message by removing this special case.
|
|
888
901
|
if (err.message.match(/server is closed/)) {
|
|
889
|
-
|
|
890
|
-
return
|
|
902
|
+
this._cursor.close().catch(() => null);
|
|
903
|
+
return this.push(null);
|
|
891
904
|
}
|
|
892
905
|
|
|
893
906
|
// NOTE: This is also perhaps questionable. The rationale here is that these errors tend
|
|
@@ -896,25 +909,23 @@ function makeCursorStream(cursor: AbstractCursor) {
|
|
|
896
909
|
// that changed to happen in cleanup legitimate errors would not destroy the
|
|
897
910
|
// stream. There are change streams test specifically test these cases.
|
|
898
911
|
if (err.message.match(/interrupted/)) {
|
|
899
|
-
return
|
|
912
|
+
return this.push(null);
|
|
900
913
|
}
|
|
901
914
|
|
|
902
|
-
return
|
|
915
|
+
return this.destroy(err);
|
|
903
916
|
}
|
|
904
917
|
|
|
905
918
|
if (result == null) {
|
|
906
|
-
|
|
907
|
-
} else if (
|
|
908
|
-
|
|
919
|
+
this.push(null);
|
|
920
|
+
} else if (this.destroyed) {
|
|
921
|
+
this._cursor.close().catch(() => null);
|
|
909
922
|
} else {
|
|
910
|
-
if (
|
|
911
|
-
return
|
|
923
|
+
if (this.push(result)) {
|
|
924
|
+
return this._readNext();
|
|
912
925
|
}
|
|
913
926
|
|
|
914
|
-
|
|
927
|
+
this._readInProgress = false;
|
|
915
928
|
}
|
|
916
929
|
});
|
|
917
930
|
}
|
|
918
|
-
|
|
919
|
-
return readable;
|
|
920
931
|
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import type { Document, Long, Timestamp } from '../bson';
|
|
2
|
+
import {
|
|
3
|
+
type ChangeStreamDocument,
|
|
4
|
+
type ChangeStreamEvents,
|
|
5
|
+
type OperationTime,
|
|
6
|
+
type ResumeToken,
|
|
7
|
+
ChangeStream
|
|
8
|
+
} from '../change_stream';
|
|
9
|
+
import { INIT, RESPONSE } from '../constants';
|
|
10
|
+
import type { MongoClient } from '../mongo_client';
|
|
11
|
+
import type { TODO_NODE_3286 } from '../mongo_types';
|
|
12
|
+
import { AggregateOperation } from '../operations/aggregate';
|
|
13
|
+
import type { CollationOptions } from '../operations/command';
|
|
14
|
+
import { type ExecutionResult, executeOperation } from '../operations/execute_operation';
|
|
15
|
+
import type { ClientSession } from '../sessions';
|
|
16
|
+
import { type Callback, type MongoDBNamespace, maxWireVersion } from '../utils';
|
|
17
|
+
import { type AbstractCursorOptions, AbstractCursor } from './abstract_cursor';
|
|
18
|
+
|
|
19
|
+
/** @internal */
|
|
20
|
+
export interface ChangeStreamCursorOptions extends AbstractCursorOptions {
|
|
21
|
+
startAtOperationTime?: OperationTime;
|
|
22
|
+
resumeAfter?: ResumeToken;
|
|
23
|
+
startAfter?: ResumeToken;
|
|
24
|
+
maxAwaitTimeMS?: number;
|
|
25
|
+
collation?: CollationOptions;
|
|
26
|
+
fullDocument?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
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
|
+
/** @internal */
|
|
42
|
+
export class ChangeStreamCursor<
|
|
43
|
+
TSchema extends Document = Document,
|
|
44
|
+
TChange extends Document = ChangeStreamDocument<TSchema>
|
|
45
|
+
> extends AbstractCursor<TChange, ChangeStreamEvents> {
|
|
46
|
+
_resumeToken: ResumeToken;
|
|
47
|
+
startAtOperationTime?: OperationTime;
|
|
48
|
+
hasReceived?: boolean;
|
|
49
|
+
resumeAfter: ResumeToken;
|
|
50
|
+
startAfter: ResumeToken;
|
|
51
|
+
options: ChangeStreamCursorOptions;
|
|
52
|
+
|
|
53
|
+
postBatchResumeToken?: ResumeToken;
|
|
54
|
+
pipeline: Document[];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @internal
|
|
58
|
+
*
|
|
59
|
+
* used to determine change stream resumability
|
|
60
|
+
*/
|
|
61
|
+
maxWireVersion: number | undefined;
|
|
62
|
+
|
|
63
|
+
constructor(
|
|
64
|
+
client: MongoClient,
|
|
65
|
+
namespace: MongoDBNamespace,
|
|
66
|
+
pipeline: Document[] = [],
|
|
67
|
+
options: ChangeStreamCursorOptions = {}
|
|
68
|
+
) {
|
|
69
|
+
super(client, namespace, options);
|
|
70
|
+
|
|
71
|
+
this.pipeline = pipeline;
|
|
72
|
+
this.options = options;
|
|
73
|
+
this._resumeToken = null;
|
|
74
|
+
this.startAtOperationTime = options.startAtOperationTime;
|
|
75
|
+
|
|
76
|
+
if (options.startAfter) {
|
|
77
|
+
this.resumeToken = options.startAfter;
|
|
78
|
+
} else if (options.resumeAfter) {
|
|
79
|
+
this.resumeToken = options.resumeAfter;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
set resumeToken(token: ResumeToken) {
|
|
84
|
+
this._resumeToken = token;
|
|
85
|
+
this.emit(ChangeStream.RESUME_TOKEN_CHANGED, token);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
get resumeToken(): ResumeToken {
|
|
89
|
+
return this._resumeToken;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get resumeOptions(): ChangeStreamCursorOptions {
|
|
93
|
+
const options: ChangeStreamCursorOptions = {
|
|
94
|
+
...this.options
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
for (const key of ['resumeAfter', 'startAfter', 'startAtOperationTime'] as const) {
|
|
98
|
+
delete options[key];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (this.resumeToken != null) {
|
|
102
|
+
if (this.options.startAfter && !this.hasReceived) {
|
|
103
|
+
options.startAfter = this.resumeToken;
|
|
104
|
+
} else {
|
|
105
|
+
options.resumeAfter = this.resumeToken;
|
|
106
|
+
}
|
|
107
|
+
} else if (this.startAtOperationTime != null && maxWireVersion(this.server) >= 7) {
|
|
108
|
+
options.startAtOperationTime = this.startAtOperationTime;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return options;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
cacheResumeToken(resumeToken: ResumeToken): void {
|
|
115
|
+
if (this.bufferedCount() === 0 && this.postBatchResumeToken) {
|
|
116
|
+
this.resumeToken = this.postBatchResumeToken;
|
|
117
|
+
} else {
|
|
118
|
+
this.resumeToken = resumeToken;
|
|
119
|
+
}
|
|
120
|
+
this.hasReceived = true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
_processBatch(response: ChangeStreamAggregateRawResult<TChange>): void {
|
|
124
|
+
const cursor = response.cursor;
|
|
125
|
+
if (cursor.postBatchResumeToken) {
|
|
126
|
+
this.postBatchResumeToken = response.cursor.postBatchResumeToken;
|
|
127
|
+
|
|
128
|
+
const batch =
|
|
129
|
+
'firstBatch' in response.cursor ? response.cursor.firstBatch : response.cursor.nextBatch;
|
|
130
|
+
if (batch.length === 0) {
|
|
131
|
+
this.resumeToken = cursor.postBatchResumeToken;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
clone(): AbstractCursor<TChange> {
|
|
137
|
+
return new ChangeStreamCursor(this.client, this.namespace, this.pipeline, {
|
|
138
|
+
...this.cursorOptions
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_initialize(session: ClientSession, callback: Callback<ExecutionResult>): void {
|
|
143
|
+
const aggregateOperation = new AggregateOperation(this.namespace, this.pipeline, {
|
|
144
|
+
...this.cursorOptions,
|
|
145
|
+
...this.options,
|
|
146
|
+
session
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
executeOperation<TODO_NODE_3286, ChangeStreamAggregateRawResult<TChange>>(
|
|
150
|
+
session.client,
|
|
151
|
+
aggregateOperation,
|
|
152
|
+
(err, response) => {
|
|
153
|
+
if (err || response == null) {
|
|
154
|
+
return callback(err);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const server = aggregateOperation.server;
|
|
158
|
+
this.maxWireVersion = maxWireVersion(server);
|
|
159
|
+
|
|
160
|
+
if (
|
|
161
|
+
this.startAtOperationTime == null &&
|
|
162
|
+
this.resumeAfter == null &&
|
|
163
|
+
this.startAfter == null &&
|
|
164
|
+
this.maxWireVersion >= 7
|
|
165
|
+
) {
|
|
166
|
+
this.startAtOperationTime = response.operationTime;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this._processBatch(response);
|
|
170
|
+
|
|
171
|
+
this.emit(INIT, response);
|
|
172
|
+
this.emit(RESPONSE);
|
|
173
|
+
|
|
174
|
+
// TODO: NODE-2882
|
|
175
|
+
callback(undefined, { server, session, response });
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
override _getMore(batchSize: number, callback: Callback): void {
|
|
181
|
+
super._getMore(batchSize, (err, response) => {
|
|
182
|
+
if (err) {
|
|
183
|
+
return callback(err);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this.maxWireVersion = maxWireVersion(this.server);
|
|
187
|
+
this._processBatch(response as TODO_NODE_3286 as ChangeStreamAggregateRawResult<TChange>);
|
|
188
|
+
|
|
189
|
+
this.emit(ChangeStream.MORE, response);
|
|
190
|
+
this.emit(ChangeStream.RESPONSE);
|
|
191
|
+
callback(err, response);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|