Skip to content

Commit 1c59f25

Browse files
committed
fix(cursor): make aggregation cursors handle destroy() and handle destroy() before cursor created
Fix Automattic#14966
1 parent 1a2fd2b commit 1c59f25

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

lib/cursor/aggregationCursor.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,37 @@ AggregationCursor.prototype.close = async function close() {
196196
this.emit('close');
197197
};
198198

199+
/**
200+
* Marks this cursor as destroyed. Will stop streaming and subsequent calls to
201+
* `next()` will error.
202+
*
203+
* @return {this}
204+
* @api private
205+
* @method _destroy
206+
*/
207+
208+
AggregationCursor.prototype._destroy = function _destroy(_err, callback) {
209+
let waitForCursor = null;
210+
if (!this.cursor) {
211+
waitForCursor = new Promise((resolve) => {
212+
this.once('cursor', resolve);
213+
});
214+
} else {
215+
waitForCursor = Promise.resolve();
216+
}
217+
218+
waitForCursor
219+
.then(() => this.cursor.close())
220+
.then(() => {
221+
this._closed = false;
222+
callback();
223+
})
224+
.catch(error => {
225+
callback(error);
226+
});
227+
return this;
228+
};
229+
199230
/**
200231
* Get the next document from this cursor. Will return `null` when there are
201232
* no documents left.

lib/cursor/queryCursor.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,19 @@ QueryCursor.prototype.close = async function close() {
248248
*/
249249

250250
QueryCursor.prototype._destroy = function _destroy(_err, callback) {
251-
this.cursor.close()
251+
let waitForCursor = null;
252+
if (!this.cursor) {
253+
waitForCursor = new Promise((resolve) => {
254+
this.once('cursor', resolve);
255+
});
256+
} else {
257+
waitForCursor = Promise.resolve();
258+
}
259+
260+
waitForCursor
261+
.then(() => {
262+
this.cursor.close();
263+
})
252264
.then(() => {
253265
this._closed = false;
254266
callback();

test/query.cursor.test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,19 @@ describe('QueryCursor', function() {
936936
assert.ok(stream.destroyed);
937937
assert.ok(stream.cursor.closed);
938938
});
939+
940+
it('handles destroy() before cursor is created (gh-14966)', async function() {
941+
db.deleteModel(/Test/);
942+
const TestModel = db.model('Test', mongoose.Schema({ name: String }));
943+
944+
const stream = await TestModel.find().cursor();
945+
assert.ok(!stream.cursor);
946+
stream.destroy();
947+
948+
await once(stream, 'cursor');
949+
assert.ok(stream.destroyed);
950+
assert.ok(stream.cursor.closed);
951+
});
939952
});
940953

941954
async function delay(ms) {

0 commit comments

Comments
 (0)