mongodb 4.4.1 → 4.6.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/README.md +3 -2
- package/lib/admin.js +5 -6
- package/lib/admin.js.map +1 -1
- package/lib/bulk/common.js +34 -7
- package/lib/bulk/common.js.map +1 -1
- package/lib/bulk/unordered.js.map +1 -1
- package/lib/change_stream.js +251 -245
- package/lib/change_stream.js.map +1 -1
- package/lib/cmap/auth/gssapi.js.map +1 -1
- package/lib/cmap/auth/mongocr.js.map +1 -1
- package/lib/cmap/auth/mongodb_aws.js +3 -0
- package/lib/cmap/auth/mongodb_aws.js.map +1 -1
- package/lib/cmap/auth/plain.js.map +1 -1
- package/lib/cmap/auth/scram.js +1 -0
- package/lib/cmap/auth/scram.js.map +1 -1
- package/lib/cmap/auth/x509.js.map +1 -1
- package/lib/cmap/commands.js +12 -11
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connect.js +8 -1
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +111 -145
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/errors.js.map +1 -1
- package/lib/cmap/message_stream.js.map +1 -1
- package/lib/cmap/stream_description.js +3 -0
- package/lib/cmap/stream_description.js.map +1 -1
- package/lib/collection.js +60 -29
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +32 -11
- package/lib/connection_string.js.map +1 -1
- package/lib/constants.js +8 -1
- package/lib/constants.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +64 -51
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +2 -2
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +9 -4
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/db.js +20 -13
- package/lib/db.js.map +1 -1
- package/lib/encrypter.js +21 -10
- package/lib/encrypter.js.map +1 -1
- package/lib/error.js +121 -59
- package/lib/error.js.map +1 -1
- package/lib/gridfs/download.js +2 -0
- package/lib/gridfs/download.js.map +1 -1
- package/lib/gridfs/index.js +42 -51
- package/lib/gridfs/index.js.map +1 -1
- package/lib/gridfs/upload.js +1 -1
- package/lib/gridfs/upload.js.map +1 -1
- package/lib/index.js +7 -3
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +21 -27
- package/lib/mongo_client.js.map +1 -1
- package/lib/operations/add_user.js +8 -1
- package/lib/operations/add_user.js.map +1 -1
- package/lib/operations/aggregate.js +5 -0
- package/lib/operations/aggregate.js.map +1 -1
- package/lib/operations/bulk_write.js.map +1 -1
- package/lib/operations/collections.js.map +1 -1
- package/lib/operations/command.js +0 -3
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/common_functions.js +8 -1
- package/lib/operations/common_functions.js.map +1 -1
- package/lib/operations/count.js.map +1 -1
- package/lib/operations/count_documents.js.map +1 -1
- package/lib/operations/create_collection.js +51 -17
- package/lib/operations/create_collection.js.map +1 -1
- package/lib/operations/delete.js +5 -3
- package/lib/operations/delete.js.map +1 -1
- package/lib/operations/distinct.js.map +1 -1
- package/lib/operations/drop.js +67 -7
- package/lib/operations/drop.js.map +1 -1
- package/lib/operations/estimated_document_count.js.map +1 -1
- package/lib/operations/eval.js.map +1 -1
- package/lib/operations/execute_operation.js +71 -79
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js +3 -52
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/find_and_modify.js +5 -0
- package/lib/operations/find_and_modify.js.map +1 -1
- package/lib/operations/get_more.js +5 -0
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js +8 -9
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/insert.js +8 -2
- package/lib/operations/insert.js.map +1 -1
- package/lib/operations/is_capped.js.map +1 -1
- package/lib/operations/list_collections.js +10 -42
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/list_databases.js +5 -0
- package/lib/operations/list_databases.js.map +1 -1
- package/lib/operations/map_reduce.js +1 -2
- package/lib/operations/map_reduce.js.map +1 -1
- package/lib/operations/operation.js +1 -3
- package/lib/operations/operation.js.map +1 -1
- package/lib/operations/options_operation.js.map +1 -1
- package/lib/operations/profiling_level.js.map +1 -1
- package/lib/operations/remove_user.js.map +1 -1
- package/lib/operations/rename.js +1 -1
- package/lib/operations/rename.js.map +1 -1
- package/lib/operations/run_command.js.map +1 -1
- package/lib/operations/set_profiling_level.js.map +1 -1
- package/lib/operations/stats.js.map +1 -1
- package/lib/operations/update.js +5 -0
- package/lib/operations/update.js.map +1 -1
- package/lib/operations/validate_collection.js.map +1 -1
- package/lib/read_concern.js +1 -0
- package/lib/read_concern.js.map +1 -1
- package/lib/sdam/common.js +1 -7
- package/lib/sdam/common.js.map +1 -1
- package/lib/sdam/events.js +1 -1
- package/lib/sdam/events.js.map +1 -1
- package/lib/sdam/monitor.js +1 -2
- package/lib/sdam/monitor.js.map +1 -1
- package/lib/sdam/server.js +108 -78
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/topology.js +38 -55
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sdam/topology_description.js +3 -4
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +93 -68
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +21 -97
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +417 -92
- package/package.json +25 -29
- package/src/admin.ts +6 -10
- package/src/bulk/common.ts +45 -14
- package/src/bulk/unordered.ts +1 -1
- package/src/change_stream.ts +559 -425
- package/src/cmap/auth/gssapi.ts +1 -1
- package/src/cmap/auth/mongocr.ts +1 -1
- package/src/cmap/auth/mongodb_aws.ts +6 -1
- package/src/cmap/auth/plain.ts +1 -1
- package/src/cmap/auth/scram.ts +3 -2
- package/src/cmap/auth/x509.ts +6 -2
- package/src/cmap/commands.ts +26 -22
- package/src/cmap/connect.ts +15 -14
- package/src/cmap/connection.ts +163 -185
- package/src/cmap/errors.ts +2 -2
- package/src/cmap/message_stream.ts +2 -2
- package/src/cmap/stream_description.ts +4 -1
- package/src/collection.ts +66 -35
- package/src/connection_string.ts +46 -18
- package/src/constants.ts +6 -0
- package/src/cursor/abstract_cursor.ts +87 -65
- package/src/cursor/aggregation_cursor.ts +4 -4
- package/src/cursor/find_cursor.ts +16 -8
- package/src/db.ts +27 -24
- package/src/deps.ts +40 -0
- package/src/encrypter.ts +22 -11
- package/src/error.ts +170 -89
- package/src/gridfs/download.ts +3 -1
- package/src/gridfs/index.ts +51 -68
- package/src/gridfs/upload.ts +13 -13
- package/src/index.ts +21 -0
- package/src/mongo_client.ts +36 -50
- package/src/mongo_types.ts +1 -1
- package/src/operations/add_user.ts +14 -3
- package/src/operations/aggregate.ts +15 -5
- package/src/operations/bulk_write.ts +6 -2
- package/src/operations/collections.ts +6 -2
- package/src/operations/command.ts +23 -12
- package/src/operations/common_functions.ts +8 -1
- package/src/operations/count.ts +6 -2
- package/src/operations/count_documents.ts +5 -1
- package/src/operations/create_collection.ts +91 -23
- package/src/operations/delete.ts +19 -13
- package/src/operations/distinct.ts +6 -2
- package/src/operations/drop.ts +100 -10
- package/src/operations/estimated_document_count.ts +11 -3
- package/src/operations/eval.ts +6 -2
- package/src/operations/execute_operation.ts +103 -101
- package/src/operations/find.ts +9 -85
- package/src/operations/find_and_modify.ts +21 -2
- package/src/operations/get_more.ts +20 -6
- package/src/operations/indexes.ts +54 -36
- package/src/operations/insert.ts +28 -7
- package/src/operations/is_capped.ts +6 -2
- package/src/operations/list_collections.ts +24 -59
- package/src/operations/list_databases.ts +13 -3
- package/src/operations/map_reduce.ts +7 -6
- package/src/operations/operation.ts +10 -9
- package/src/operations/options_operation.ts +6 -2
- package/src/operations/profiling_level.ts +6 -2
- package/src/operations/remove_user.ts +6 -2
- package/src/operations/rename.ts +7 -3
- package/src/operations/run_command.ts +6 -2
- package/src/operations/set_profiling_level.ts +6 -2
- package/src/operations/stats.ts +12 -4
- package/src/operations/update.ts +19 -9
- package/src/operations/validate_collection.ts +6 -2
- package/src/read_concern.ts +1 -0
- package/src/sdam/common.ts +0 -6
- package/src/sdam/events.ts +2 -2
- package/src/sdam/monitor.ts +4 -5
- package/src/sdam/server.ts +125 -117
- package/src/sdam/topology.ts +39 -78
- package/src/sdam/topology_description.ts +3 -4
- package/src/sessions.ts +108 -78
- package/src/utils.ts +39 -119
- package/tsconfig.json +40 -0
- package/mongodb.ts34.d.ts +0 -5720
package/lib/change_stream.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ChangeStreamCursor = exports.ChangeStream = void 0;
|
|
4
4
|
const Denque = require("denque");
|
|
5
5
|
const collection_1 = require("./collection");
|
|
6
|
+
const constants_1 = require("./constants");
|
|
6
7
|
const abstract_cursor_1 = require("./cursor/abstract_cursor");
|
|
7
8
|
const db_1 = require("./db");
|
|
8
9
|
const error_1 = require("./error");
|
|
@@ -19,13 +20,27 @@ const kCursorStream = Symbol('cursorStream');
|
|
|
19
20
|
const kClosed = Symbol('closed');
|
|
20
21
|
/** @internal */
|
|
21
22
|
const kMode = Symbol('mode');
|
|
22
|
-
const CHANGE_STREAM_OPTIONS = [
|
|
23
|
-
|
|
23
|
+
const CHANGE_STREAM_OPTIONS = [
|
|
24
|
+
'resumeAfter',
|
|
25
|
+
'startAfter',
|
|
26
|
+
'startAtOperationTime',
|
|
27
|
+
'fullDocument'
|
|
28
|
+
];
|
|
29
|
+
const CURSOR_OPTIONS = [
|
|
30
|
+
'batchSize',
|
|
31
|
+
'maxAwaitTimeMS',
|
|
32
|
+
'collation',
|
|
33
|
+
'readPreference',
|
|
34
|
+
'comment',
|
|
35
|
+
...CHANGE_STREAM_OPTIONS
|
|
36
|
+
];
|
|
24
37
|
const CHANGE_DOMAIN_TYPES = {
|
|
25
38
|
COLLECTION: Symbol('Collection'),
|
|
26
39
|
DATABASE: Symbol('Database'),
|
|
27
40
|
CLUSTER: Symbol('Cluster')
|
|
28
41
|
};
|
|
42
|
+
const SELECTION_TIMEOUT = 30000;
|
|
43
|
+
const CHANGE_STREAM_EVENTS = [constants_1.RESUME_TOKEN_CHANGED, constants_1.END, constants_1.CLOSE];
|
|
29
44
|
const NO_RESUME_TOKEN_ERROR = 'A change stream document has been received that lacks a resume token (_id).';
|
|
30
45
|
const NO_CURSOR_ERROR = 'ChangeStream has no cursor';
|
|
31
46
|
const CHANGESTREAM_CLOSED_ERROR = 'ChangeStream is closed';
|
|
@@ -63,13 +78,13 @@ class ChangeStream extends mongo_types_1.TypedEventEmitter {
|
|
|
63
78
|
}
|
|
64
79
|
this[kResumeQueue] = new Denque();
|
|
65
80
|
// Create contained Change Stream cursor
|
|
66
|
-
this.cursor =
|
|
81
|
+
this.cursor = this._createChangeStreamCursor(options);
|
|
67
82
|
this[kClosed] = false;
|
|
68
83
|
this[kMode] = false;
|
|
69
84
|
// Listen for any `change` listeners being added to ChangeStream
|
|
70
85
|
this.on('newListener', eventName => {
|
|
71
86
|
if (eventName === 'change' && this.cursor && this.listenerCount('change') === 0) {
|
|
72
|
-
|
|
87
|
+
this._streamEvents(this.cursor);
|
|
73
88
|
}
|
|
74
89
|
});
|
|
75
90
|
this.on('removeListener', eventName => {
|
|
@@ -89,9 +104,9 @@ class ChangeStream extends mongo_types_1.TypedEventEmitter {
|
|
|
89
104
|
return (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.resumeToken;
|
|
90
105
|
}
|
|
91
106
|
hasNext(callback) {
|
|
92
|
-
|
|
107
|
+
this._setIsIterator();
|
|
93
108
|
return (0, utils_1.maybePromise)(callback, cb => {
|
|
94
|
-
|
|
109
|
+
this._getCursor((err, cursor) => {
|
|
95
110
|
if (err || !cursor)
|
|
96
111
|
return cb(err); // failed to resume, raise an error
|
|
97
112
|
cursor.hasNext(cb);
|
|
@@ -99,18 +114,18 @@ class ChangeStream extends mongo_types_1.TypedEventEmitter {
|
|
|
99
114
|
});
|
|
100
115
|
}
|
|
101
116
|
next(callback) {
|
|
102
|
-
|
|
117
|
+
this._setIsIterator();
|
|
103
118
|
return (0, utils_1.maybePromise)(callback, cb => {
|
|
104
|
-
|
|
119
|
+
this._getCursor((err, cursor) => {
|
|
105
120
|
if (err || !cursor)
|
|
106
121
|
return cb(err); // failed to resume, raise an error
|
|
107
122
|
cursor.next((error, change) => {
|
|
108
123
|
if (error) {
|
|
109
124
|
this[kResumeQueue].push(() => this.next(cb));
|
|
110
|
-
|
|
125
|
+
this._processError(error, cb);
|
|
111
126
|
return;
|
|
112
127
|
}
|
|
113
|
-
|
|
128
|
+
this._processNewChange(change !== null && change !== void 0 ? change : null, cb);
|
|
114
129
|
});
|
|
115
130
|
});
|
|
116
131
|
});
|
|
@@ -129,7 +144,7 @@ class ChangeStream extends mongo_types_1.TypedEventEmitter {
|
|
|
129
144
|
}
|
|
130
145
|
const cursor = this.cursor;
|
|
131
146
|
return cursor.close(err => {
|
|
132
|
-
|
|
147
|
+
this._endStream();
|
|
133
148
|
this.cursor = undefined;
|
|
134
149
|
return cb(err);
|
|
135
150
|
});
|
|
@@ -146,41 +161,243 @@ class ChangeStream extends mongo_types_1.TypedEventEmitter {
|
|
|
146
161
|
return this.cursor.stream(options);
|
|
147
162
|
}
|
|
148
163
|
tryNext(callback) {
|
|
149
|
-
|
|
164
|
+
this._setIsIterator();
|
|
150
165
|
return (0, utils_1.maybePromise)(callback, cb => {
|
|
151
|
-
|
|
166
|
+
this._getCursor((err, cursor) => {
|
|
152
167
|
if (err || !cursor)
|
|
153
168
|
return cb(err); // failed to resume, raise an error
|
|
154
169
|
return cursor.tryNext(cb);
|
|
155
170
|
});
|
|
156
171
|
});
|
|
157
172
|
}
|
|
173
|
+
/** @internal */
|
|
174
|
+
_setIsEmitter() {
|
|
175
|
+
if (this[kMode] === 'iterator') {
|
|
176
|
+
// TODO(NODE-3485): Replace with MongoChangeStreamModeError
|
|
177
|
+
throw new error_1.MongoAPIError('ChangeStream cannot be used as an EventEmitter after being used as an iterator');
|
|
178
|
+
}
|
|
179
|
+
this[kMode] = 'emitter';
|
|
180
|
+
}
|
|
181
|
+
/** @internal */
|
|
182
|
+
_setIsIterator() {
|
|
183
|
+
if (this[kMode] === 'emitter') {
|
|
184
|
+
// TODO(NODE-3485): Replace with MongoChangeStreamModeError
|
|
185
|
+
throw new error_1.MongoAPIError('ChangeStream cannot be used as an iterator after being used as an EventEmitter');
|
|
186
|
+
}
|
|
187
|
+
this[kMode] = 'iterator';
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Create a new change stream cursor based on self's configuration
|
|
191
|
+
* @internal
|
|
192
|
+
*/
|
|
193
|
+
_createChangeStreamCursor(options) {
|
|
194
|
+
const changeStreamStageOptions = (0, utils_1.filterOptions)(options, CHANGE_STREAM_OPTIONS);
|
|
195
|
+
if (this.type === CHANGE_DOMAIN_TYPES.CLUSTER) {
|
|
196
|
+
changeStreamStageOptions.allChangesForCluster = true;
|
|
197
|
+
}
|
|
198
|
+
const pipeline = [{ $changeStream: changeStreamStageOptions }, ...this.pipeline];
|
|
199
|
+
const cursorOptions = (0, utils_1.filterOptions)(options, CURSOR_OPTIONS);
|
|
200
|
+
const changeStreamCursor = new ChangeStreamCursor((0, utils_1.getTopology)(this.parent), this.namespace, pipeline, cursorOptions);
|
|
201
|
+
for (const event of CHANGE_STREAM_EVENTS) {
|
|
202
|
+
changeStreamCursor.on(event, e => this.emit(event, e));
|
|
203
|
+
}
|
|
204
|
+
if (this.listenerCount(ChangeStream.CHANGE) > 0) {
|
|
205
|
+
this._streamEvents(changeStreamCursor);
|
|
206
|
+
}
|
|
207
|
+
return changeStreamCursor;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* This method performs a basic server selection loop, satisfying the requirements of
|
|
211
|
+
* ChangeStream resumability until the new SDAM layer can be used.
|
|
212
|
+
* @internal
|
|
213
|
+
*/
|
|
214
|
+
_waitForTopologyConnected(topology, options, callback) {
|
|
215
|
+
setTimeout(() => {
|
|
216
|
+
if (options && options.start == null) {
|
|
217
|
+
options.start = (0, utils_1.now)();
|
|
218
|
+
}
|
|
219
|
+
const start = options.start || (0, utils_1.now)();
|
|
220
|
+
const timeout = options.timeout || SELECTION_TIMEOUT;
|
|
221
|
+
if (topology.isConnected()) {
|
|
222
|
+
return callback();
|
|
223
|
+
}
|
|
224
|
+
if ((0, utils_1.calculateDurationInMs)(start) > timeout) {
|
|
225
|
+
// TODO(NODE-3497): Replace with MongoNetworkTimeoutError
|
|
226
|
+
return callback(new error_1.MongoRuntimeError('Timed out waiting for connection'));
|
|
227
|
+
}
|
|
228
|
+
this._waitForTopologyConnected(topology, options, callback);
|
|
229
|
+
}, 500); // this is an arbitrary wait time to allow SDAM to transition
|
|
230
|
+
}
|
|
231
|
+
/** @internal */
|
|
232
|
+
_closeWithError(error, callback) {
|
|
233
|
+
if (!callback) {
|
|
234
|
+
this.emit(ChangeStream.ERROR, error);
|
|
235
|
+
}
|
|
236
|
+
this.close(() => callback && callback(error));
|
|
237
|
+
}
|
|
238
|
+
/** @internal */
|
|
239
|
+
_streamEvents(cursor) {
|
|
240
|
+
var _a;
|
|
241
|
+
this._setIsEmitter();
|
|
242
|
+
const stream = (_a = this[kCursorStream]) !== null && _a !== void 0 ? _a : cursor.stream();
|
|
243
|
+
this[kCursorStream] = stream;
|
|
244
|
+
stream.on('data', change => this._processNewChange(change));
|
|
245
|
+
stream.on('error', error => this._processError(error));
|
|
246
|
+
}
|
|
247
|
+
/** @internal */
|
|
248
|
+
_endStream() {
|
|
249
|
+
const cursorStream = this[kCursorStream];
|
|
250
|
+
if (cursorStream) {
|
|
251
|
+
['data', 'close', 'end', 'error'].forEach(event => cursorStream.removeAllListeners(event));
|
|
252
|
+
cursorStream.destroy();
|
|
253
|
+
}
|
|
254
|
+
this[kCursorStream] = undefined;
|
|
255
|
+
}
|
|
256
|
+
/** @internal */
|
|
257
|
+
_processNewChange(change, callback) {
|
|
258
|
+
var _a;
|
|
259
|
+
if (this[kClosed]) {
|
|
260
|
+
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
|
|
261
|
+
if (callback)
|
|
262
|
+
callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
// a null change means the cursor has been notified, implicitly closing the change stream
|
|
266
|
+
if (change == null) {
|
|
267
|
+
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
|
|
268
|
+
return this._closeWithError(new error_1.MongoRuntimeError(CHANGESTREAM_CLOSED_ERROR), callback);
|
|
269
|
+
}
|
|
270
|
+
if (change && !change._id) {
|
|
271
|
+
return this._closeWithError(new error_1.MongoChangeStreamError(NO_RESUME_TOKEN_ERROR), callback);
|
|
272
|
+
}
|
|
273
|
+
// cache the resume token
|
|
274
|
+
(_a = this.cursor) === null || _a === void 0 ? void 0 : _a.cacheResumeToken(change._id);
|
|
275
|
+
// wipe the startAtOperationTime if there was one so that there won't be a conflict
|
|
276
|
+
// between resumeToken and startAtOperationTime if we need to reconnect the cursor
|
|
277
|
+
this.options.startAtOperationTime = undefined;
|
|
278
|
+
// Return the change
|
|
279
|
+
if (!callback)
|
|
280
|
+
return this.emit(ChangeStream.CHANGE, change);
|
|
281
|
+
return callback(undefined, change);
|
|
282
|
+
}
|
|
283
|
+
/** @internal */
|
|
284
|
+
_processError(error, callback) {
|
|
285
|
+
const cursor = this.cursor;
|
|
286
|
+
// If the change stream has been closed explicitly, do not process error.
|
|
287
|
+
if (this[kClosed]) {
|
|
288
|
+
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
|
|
289
|
+
if (callback)
|
|
290
|
+
callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// if the resume succeeds, continue with the new cursor
|
|
294
|
+
const resumeWithCursor = (newCursor) => {
|
|
295
|
+
this.cursor = newCursor;
|
|
296
|
+
this._processResumeQueue();
|
|
297
|
+
};
|
|
298
|
+
// otherwise, raise an error and close the change stream
|
|
299
|
+
const unresumableError = (err) => {
|
|
300
|
+
if (!callback) {
|
|
301
|
+
this.emit(ChangeStream.ERROR, err);
|
|
302
|
+
}
|
|
303
|
+
this.close(() => this._processResumeQueue(err));
|
|
304
|
+
};
|
|
305
|
+
if (cursor && (0, error_1.isResumableError)(error, (0, utils_1.maxWireVersion)(cursor.server))) {
|
|
306
|
+
this.cursor = undefined;
|
|
307
|
+
// stop listening to all events from old cursor
|
|
308
|
+
this._endStream();
|
|
309
|
+
// close internal cursor, ignore errors
|
|
310
|
+
cursor.close();
|
|
311
|
+
const topology = (0, utils_1.getTopology)(this.parent);
|
|
312
|
+
this._waitForTopologyConnected(topology, { readPreference: cursor.readPreference }, err => {
|
|
313
|
+
// if the topology can't reconnect, close the stream
|
|
314
|
+
if (err)
|
|
315
|
+
return unresumableError(err);
|
|
316
|
+
// create a new cursor, preserving the old cursor's options
|
|
317
|
+
const newCursor = this._createChangeStreamCursor(cursor.resumeOptions);
|
|
318
|
+
// attempt to continue in emitter mode
|
|
319
|
+
if (!callback)
|
|
320
|
+
return resumeWithCursor(newCursor);
|
|
321
|
+
// attempt to continue in iterator mode
|
|
322
|
+
newCursor.hasNext(err => {
|
|
323
|
+
// if there's an error immediately after resuming, close the stream
|
|
324
|
+
if (err)
|
|
325
|
+
return unresumableError(err);
|
|
326
|
+
resumeWithCursor(newCursor);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
// if initial error wasn't resumable, raise an error and close the change stream
|
|
332
|
+
return this._closeWithError(error, callback);
|
|
333
|
+
}
|
|
334
|
+
/** @internal */
|
|
335
|
+
_getCursor(callback) {
|
|
336
|
+
if (this[kClosed]) {
|
|
337
|
+
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
|
|
338
|
+
callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
// if a cursor exists and it is open, return it
|
|
342
|
+
if (this.cursor) {
|
|
343
|
+
callback(undefined, this.cursor);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
// no cursor, queue callback until topology reconnects
|
|
347
|
+
this[kResumeQueue].push(callback);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Drain the resume queue when a new has become available
|
|
351
|
+
* @internal
|
|
352
|
+
*
|
|
353
|
+
* @param err - error getting a new cursor
|
|
354
|
+
*/
|
|
355
|
+
_processResumeQueue(error) {
|
|
356
|
+
var _a;
|
|
357
|
+
while (this[kResumeQueue].length) {
|
|
358
|
+
const request = this[kResumeQueue].pop();
|
|
359
|
+
if (!request)
|
|
360
|
+
break; // Should never occur but TS can't use the length check in the while condition
|
|
361
|
+
if (!error) {
|
|
362
|
+
if (this[kClosed]) {
|
|
363
|
+
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
|
|
364
|
+
request(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (!this.cursor) {
|
|
368
|
+
request(new error_1.MongoChangeStreamError(NO_CURSOR_ERROR));
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
request(error, (_a = this.cursor) !== null && _a !== void 0 ? _a : undefined);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
158
375
|
}
|
|
159
376
|
exports.ChangeStream = ChangeStream;
|
|
160
377
|
/** @event */
|
|
161
|
-
ChangeStream.RESPONSE =
|
|
378
|
+
ChangeStream.RESPONSE = constants_1.RESPONSE;
|
|
162
379
|
/** @event */
|
|
163
|
-
ChangeStream.MORE =
|
|
380
|
+
ChangeStream.MORE = constants_1.MORE;
|
|
164
381
|
/** @event */
|
|
165
|
-
ChangeStream.INIT =
|
|
382
|
+
ChangeStream.INIT = constants_1.INIT;
|
|
166
383
|
/** @event */
|
|
167
|
-
ChangeStream.CLOSE =
|
|
384
|
+
ChangeStream.CLOSE = constants_1.CLOSE;
|
|
168
385
|
/**
|
|
169
386
|
* Fired for each new matching change in the specified namespace. Attaching a `change`
|
|
170
387
|
* event listener to a Change Stream will switch the stream into flowing mode. Data will
|
|
171
388
|
* then be passed as soon as it is available.
|
|
172
389
|
* @event
|
|
173
390
|
*/
|
|
174
|
-
ChangeStream.CHANGE =
|
|
391
|
+
ChangeStream.CHANGE = constants_1.CHANGE;
|
|
175
392
|
/** @event */
|
|
176
|
-
ChangeStream.END =
|
|
393
|
+
ChangeStream.END = constants_1.END;
|
|
177
394
|
/** @event */
|
|
178
|
-
ChangeStream.ERROR =
|
|
395
|
+
ChangeStream.ERROR = constants_1.ERROR;
|
|
179
396
|
/**
|
|
180
397
|
* Emitted each time the change stream stores a new resume token.
|
|
181
398
|
* @event
|
|
182
399
|
*/
|
|
183
|
-
ChangeStream.RESUME_TOKEN_CHANGED =
|
|
400
|
+
ChangeStream.RESUME_TOKEN_CHANGED = constants_1.RESUME_TOKEN_CHANGED;
|
|
184
401
|
/** @internal */
|
|
185
402
|
class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
|
|
186
403
|
constructor(topology, namespace, pipeline = [], options = {}) {
|
|
@@ -204,17 +421,14 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
|
|
|
204
421
|
return this._resumeToken;
|
|
205
422
|
}
|
|
206
423
|
get resumeOptions() {
|
|
207
|
-
const result =
|
|
208
|
-
for (const optionName of CURSOR_OPTIONS) {
|
|
209
|
-
if (Reflect.has(this.options, optionName)) {
|
|
210
|
-
Reflect.set(result, optionName, Reflect.get(this.options, optionName));
|
|
211
|
-
}
|
|
212
|
-
}
|
|
424
|
+
const result = (0, utils_1.filterOptions)(this.options, CURSOR_OPTIONS);
|
|
213
425
|
if (this.resumeToken || this.startAtOperationTime) {
|
|
214
|
-
['resumeAfter', 'startAfter', 'startAtOperationTime']
|
|
426
|
+
for (const key of ['resumeAfter', 'startAfter', 'startAtOperationTime']) {
|
|
427
|
+
Reflect.deleteProperty(result, key);
|
|
428
|
+
}
|
|
215
429
|
if (this.resumeToken) {
|
|
216
430
|
const resumeKey = this.options.startAfter && !this.hasReceived ? 'startAfter' : 'resumeAfter';
|
|
217
|
-
|
|
431
|
+
result[resumeKey] = this.resumeToken;
|
|
218
432
|
}
|
|
219
433
|
else if (this.startAtOperationTime && (0, utils_1.maxWireVersion)(this.server) >= 7) {
|
|
220
434
|
result.startAtOperationTime = this.startAtOperationTime;
|
|
@@ -231,11 +445,12 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
|
|
|
231
445
|
}
|
|
232
446
|
this.hasReceived = true;
|
|
233
447
|
}
|
|
234
|
-
_processBatch(
|
|
235
|
-
const cursor =
|
|
448
|
+
_processBatch(response) {
|
|
449
|
+
const cursor = response.cursor;
|
|
236
450
|
if (cursor.postBatchResumeToken) {
|
|
237
|
-
this.postBatchResumeToken = cursor.postBatchResumeToken;
|
|
238
|
-
|
|
451
|
+
this.postBatchResumeToken = response.cursor.postBatchResumeToken;
|
|
452
|
+
const batch = 'firstBatch' in response.cursor ? response.cursor.firstBatch : response.cursor.nextBatch;
|
|
453
|
+
if (batch.length === 0) {
|
|
239
454
|
this.resumeToken = cursor.postBatchResumeToken;
|
|
240
455
|
}
|
|
241
456
|
}
|
|
@@ -251,7 +466,7 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
|
|
|
251
466
|
...this.options,
|
|
252
467
|
session
|
|
253
468
|
});
|
|
254
|
-
(0, execute_operation_1.executeOperation)(
|
|
469
|
+
(0, execute_operation_1.executeOperation)(session, aggregateOperation, (err, response) => {
|
|
255
470
|
if (err || response == null) {
|
|
256
471
|
return callback(err);
|
|
257
472
|
}
|
|
@@ -262,7 +477,7 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
|
|
|
262
477
|
(0, utils_1.maxWireVersion)(server) >= 7) {
|
|
263
478
|
this.startAtOperationTime = response.operationTime;
|
|
264
479
|
}
|
|
265
|
-
this._processBatch(
|
|
480
|
+
this._processBatch(response);
|
|
266
481
|
this.emit(ChangeStream.INIT, response);
|
|
267
482
|
this.emit(ChangeStream.RESPONSE);
|
|
268
483
|
// TODO: NODE-2882
|
|
@@ -274,7 +489,7 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
|
|
|
274
489
|
if (err) {
|
|
275
490
|
return callback(err);
|
|
276
491
|
}
|
|
277
|
-
this._processBatch(
|
|
492
|
+
this._processBatch(response);
|
|
278
493
|
this.emit(ChangeStream.MORE, response);
|
|
279
494
|
this.emit(ChangeStream.RESPONSE);
|
|
280
495
|
callback(err, response);
|
|
@@ -282,213 +497,4 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
|
|
|
282
497
|
}
|
|
283
498
|
}
|
|
284
499
|
exports.ChangeStreamCursor = ChangeStreamCursor;
|
|
285
|
-
const CHANGE_STREAM_EVENTS = [
|
|
286
|
-
ChangeStream.RESUME_TOKEN_CHANGED,
|
|
287
|
-
ChangeStream.END,
|
|
288
|
-
ChangeStream.CLOSE
|
|
289
|
-
];
|
|
290
|
-
function setIsEmitter(changeStream) {
|
|
291
|
-
if (changeStream[kMode] === 'iterator') {
|
|
292
|
-
// TODO(NODE-3485): Replace with MongoChangeStreamModeError
|
|
293
|
-
throw new error_1.MongoAPIError('ChangeStream cannot be used as an EventEmitter after being used as an iterator');
|
|
294
|
-
}
|
|
295
|
-
changeStream[kMode] = 'emitter';
|
|
296
|
-
}
|
|
297
|
-
function setIsIterator(changeStream) {
|
|
298
|
-
if (changeStream[kMode] === 'emitter') {
|
|
299
|
-
// TODO(NODE-3485): Replace with MongoChangeStreamModeError
|
|
300
|
-
throw new error_1.MongoAPIError('ChangeStream cannot be used as an iterator after being used as an EventEmitter');
|
|
301
|
-
}
|
|
302
|
-
changeStream[kMode] = 'iterator';
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Create a new change stream cursor based on self's configuration
|
|
306
|
-
* @internal
|
|
307
|
-
*/
|
|
308
|
-
function createChangeStreamCursor(changeStream, options) {
|
|
309
|
-
const changeStreamStageOptions = { fullDocument: options.fullDocument || 'default' };
|
|
310
|
-
applyKnownOptions(changeStreamStageOptions, options, CHANGE_STREAM_OPTIONS);
|
|
311
|
-
if (changeStream.type === CHANGE_DOMAIN_TYPES.CLUSTER) {
|
|
312
|
-
changeStreamStageOptions.allChangesForCluster = true;
|
|
313
|
-
}
|
|
314
|
-
const pipeline = [{ $changeStream: changeStreamStageOptions }].concat(changeStream.pipeline);
|
|
315
|
-
const cursorOptions = applyKnownOptions({}, options, CURSOR_OPTIONS);
|
|
316
|
-
const changeStreamCursor = new ChangeStreamCursor((0, utils_1.getTopology)(changeStream.parent), changeStream.namespace, pipeline, cursorOptions);
|
|
317
|
-
for (const event of CHANGE_STREAM_EVENTS) {
|
|
318
|
-
changeStreamCursor.on(event, e => changeStream.emit(event, e));
|
|
319
|
-
}
|
|
320
|
-
if (changeStream.listenerCount(ChangeStream.CHANGE) > 0) {
|
|
321
|
-
streamEvents(changeStream, changeStreamCursor);
|
|
322
|
-
}
|
|
323
|
-
return changeStreamCursor;
|
|
324
|
-
}
|
|
325
|
-
function applyKnownOptions(target, source, optionNames) {
|
|
326
|
-
optionNames.forEach(name => {
|
|
327
|
-
if (source[name]) {
|
|
328
|
-
target[name] = source[name];
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
return target;
|
|
332
|
-
}
|
|
333
|
-
// This method performs a basic server selection loop, satisfying the requirements of
|
|
334
|
-
// ChangeStream resumability until the new SDAM layer can be used.
|
|
335
|
-
const SELECTION_TIMEOUT = 30000;
|
|
336
|
-
function waitForTopologyConnected(topology, options, callback) {
|
|
337
|
-
setTimeout(() => {
|
|
338
|
-
if (options && options.start == null) {
|
|
339
|
-
options.start = (0, utils_1.now)();
|
|
340
|
-
}
|
|
341
|
-
const start = options.start || (0, utils_1.now)();
|
|
342
|
-
const timeout = options.timeout || SELECTION_TIMEOUT;
|
|
343
|
-
if (topology.isConnected()) {
|
|
344
|
-
return callback();
|
|
345
|
-
}
|
|
346
|
-
if ((0, utils_1.calculateDurationInMs)(start) > timeout) {
|
|
347
|
-
// TODO(NODE-3497): Replace with MongoNetworkTimeoutError
|
|
348
|
-
return callback(new error_1.MongoRuntimeError('Timed out waiting for connection'));
|
|
349
|
-
}
|
|
350
|
-
waitForTopologyConnected(topology, options, callback);
|
|
351
|
-
}, 500); // this is an arbitrary wait time to allow SDAM to transition
|
|
352
|
-
}
|
|
353
|
-
function closeWithError(changeStream, error, callback) {
|
|
354
|
-
if (!callback) {
|
|
355
|
-
changeStream.emit(ChangeStream.ERROR, error);
|
|
356
|
-
}
|
|
357
|
-
changeStream.close(() => callback && callback(error));
|
|
358
|
-
}
|
|
359
|
-
function streamEvents(changeStream, cursor) {
|
|
360
|
-
setIsEmitter(changeStream);
|
|
361
|
-
const stream = changeStream[kCursorStream] || cursor.stream();
|
|
362
|
-
changeStream[kCursorStream] = stream;
|
|
363
|
-
stream.on('data', change => processNewChange(changeStream, change));
|
|
364
|
-
stream.on('error', error => processError(changeStream, error));
|
|
365
|
-
}
|
|
366
|
-
function endStream(changeStream) {
|
|
367
|
-
const cursorStream = changeStream[kCursorStream];
|
|
368
|
-
if (cursorStream) {
|
|
369
|
-
['data', 'close', 'end', 'error'].forEach(event => cursorStream.removeAllListeners(event));
|
|
370
|
-
cursorStream.destroy();
|
|
371
|
-
}
|
|
372
|
-
changeStream[kCursorStream] = undefined;
|
|
373
|
-
}
|
|
374
|
-
function processNewChange(changeStream, change, callback) {
|
|
375
|
-
var _a;
|
|
376
|
-
if (changeStream[kClosed]) {
|
|
377
|
-
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
|
|
378
|
-
if (callback)
|
|
379
|
-
callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
// a null change means the cursor has been notified, implicitly closing the change stream
|
|
383
|
-
if (change == null) {
|
|
384
|
-
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
|
|
385
|
-
return closeWithError(changeStream, new error_1.MongoRuntimeError(CHANGESTREAM_CLOSED_ERROR), callback);
|
|
386
|
-
}
|
|
387
|
-
if (change && !change._id) {
|
|
388
|
-
return closeWithError(changeStream, new error_1.MongoChangeStreamError(NO_RESUME_TOKEN_ERROR), callback);
|
|
389
|
-
}
|
|
390
|
-
// cache the resume token
|
|
391
|
-
(_a = changeStream.cursor) === null || _a === void 0 ? void 0 : _a.cacheResumeToken(change._id);
|
|
392
|
-
// wipe the startAtOperationTime if there was one so that there won't be a conflict
|
|
393
|
-
// between resumeToken and startAtOperationTime if we need to reconnect the cursor
|
|
394
|
-
changeStream.options.startAtOperationTime = undefined;
|
|
395
|
-
// Return the change
|
|
396
|
-
if (!callback)
|
|
397
|
-
return changeStream.emit(ChangeStream.CHANGE, change);
|
|
398
|
-
return callback(undefined, change);
|
|
399
|
-
}
|
|
400
|
-
function processError(changeStream, error, callback) {
|
|
401
|
-
const cursor = changeStream.cursor;
|
|
402
|
-
// If the change stream has been closed explicitly, do not process error.
|
|
403
|
-
if (changeStream[kClosed]) {
|
|
404
|
-
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
|
|
405
|
-
if (callback)
|
|
406
|
-
callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
// if the resume succeeds, continue with the new cursor
|
|
410
|
-
function resumeWithCursor(newCursor) {
|
|
411
|
-
changeStream.cursor = newCursor;
|
|
412
|
-
processResumeQueue(changeStream);
|
|
413
|
-
}
|
|
414
|
-
// otherwise, raise an error and close the change stream
|
|
415
|
-
function unresumableError(err) {
|
|
416
|
-
if (!callback) {
|
|
417
|
-
changeStream.emit(ChangeStream.ERROR, err);
|
|
418
|
-
}
|
|
419
|
-
changeStream.close(() => processResumeQueue(changeStream, err));
|
|
420
|
-
}
|
|
421
|
-
if (cursor && (0, error_1.isResumableError)(error, (0, utils_1.maxWireVersion)(cursor.server))) {
|
|
422
|
-
changeStream.cursor = undefined;
|
|
423
|
-
// stop listening to all events from old cursor
|
|
424
|
-
endStream(changeStream);
|
|
425
|
-
// close internal cursor, ignore errors
|
|
426
|
-
cursor.close();
|
|
427
|
-
const topology = (0, utils_1.getTopology)(changeStream.parent);
|
|
428
|
-
waitForTopologyConnected(topology, { readPreference: cursor.readPreference }, err => {
|
|
429
|
-
// if the topology can't reconnect, close the stream
|
|
430
|
-
if (err)
|
|
431
|
-
return unresumableError(err);
|
|
432
|
-
// create a new cursor, preserving the old cursor's options
|
|
433
|
-
const newCursor = createChangeStreamCursor(changeStream, cursor.resumeOptions);
|
|
434
|
-
// attempt to continue in emitter mode
|
|
435
|
-
if (!callback)
|
|
436
|
-
return resumeWithCursor(newCursor);
|
|
437
|
-
// attempt to continue in iterator mode
|
|
438
|
-
newCursor.hasNext(err => {
|
|
439
|
-
// if there's an error immediately after resuming, close the stream
|
|
440
|
-
if (err)
|
|
441
|
-
return unresumableError(err);
|
|
442
|
-
resumeWithCursor(newCursor);
|
|
443
|
-
});
|
|
444
|
-
});
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
// if initial error wasn't resumable, raise an error and close the change stream
|
|
448
|
-
return closeWithError(changeStream, error, callback);
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Safely provides a cursor across resume attempts
|
|
452
|
-
*
|
|
453
|
-
* @param changeStream - the parent ChangeStream
|
|
454
|
-
*/
|
|
455
|
-
function getCursor(changeStream, callback) {
|
|
456
|
-
if (changeStream[kClosed]) {
|
|
457
|
-
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
|
|
458
|
-
callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
// if a cursor exists and it is open, return it
|
|
462
|
-
if (changeStream.cursor) {
|
|
463
|
-
callback(undefined, changeStream.cursor);
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
// no cursor, queue callback until topology reconnects
|
|
467
|
-
changeStream[kResumeQueue].push(callback);
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Drain the resume queue when a new has become available
|
|
471
|
-
*
|
|
472
|
-
* @param changeStream - the parent ChangeStream
|
|
473
|
-
* @param err - error getting a new cursor
|
|
474
|
-
*/
|
|
475
|
-
function processResumeQueue(changeStream, err) {
|
|
476
|
-
while (changeStream[kResumeQueue].length) {
|
|
477
|
-
const request = changeStream[kResumeQueue].pop();
|
|
478
|
-
if (!request)
|
|
479
|
-
break; // Should never occur but TS can't use the length check in the while condition
|
|
480
|
-
if (!err) {
|
|
481
|
-
if (changeStream[kClosed]) {
|
|
482
|
-
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
|
|
483
|
-
request(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
|
|
484
|
-
return;
|
|
485
|
-
}
|
|
486
|
-
if (!changeStream.cursor) {
|
|
487
|
-
request(new error_1.MongoChangeStreamError(NO_CURSOR_ERROR));
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
request(err, changeStream.cursor);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
500
|
//# sourceMappingURL=change_stream.js.map
|