Skip to content

Commit

Permalink
feat: implement rewind support for AbstractCursor subclasses
Browse files Browse the repository at this point in the history
This reintroduces support for rewinding a cursor to its
uninitialized state.

NODE-2811
  • Loading branch information
mbroadst committed Dec 1, 2020
1 parent 98ae02c commit 8f24e65
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 3 deletions.
29 changes: 28 additions & 1 deletion src/cursor/abstract_cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,33 @@ export abstract class AbstractCursor extends EventEmitter {
return this;
}

/**
* Rewind this cursor to its uninitialized state. Any options that are present on the cursor will
* remain in effect. Iterating this cursor will cause new queries to be sent to the server, even
* if the resultant data has already been retrieved by this cursor.
*/
rewind(): void {
if (!this[kInitialized]) {
return;
}

this[kId] = undefined;
this[kDocuments] = [];
this[kClosed] = false;
this[kKilled] = false;
this[kInitialized] = false;

const session = this[kSession];
if (session) {
// We only want to end this session if we created it, and it hasn't ended yet
if (session.explicit === false && !session.hasEnded) {
session.endSession();
}

this[kSession] = undefined;
}
}

/* @internal */
abstract _initialize(
session: ClientSession | undefined,
Expand Down Expand Up @@ -552,7 +579,7 @@ function next(
if (cursorId == null) {
// All cursors must operate within a session, one must be made implicitly if not explicitly provided
if (cursor[kSession] == null && cursor[kTopology].hasSessionSupport()) {
cursor[kSession] = cursor[kTopology].startSession({ owner: cursor, explicit: true });
cursor[kSession] = cursor[kTopology].startSession({ owner: cursor, explicit: false });
}

cursor._initialize(cursor[kSession], (err, state) => {
Expand Down
79 changes: 79 additions & 0 deletions test/functional/abstract_cursor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,83 @@ describe('AbstractCursor', function () {
})
);
});

context('#rewind', function () {
beforeEach(
withClientV2(function (client, done) {
const coll = client.db().collection('rewind');
coll.drop(() => {
coll.insertMany([{}, {}], err => {
expect(err).to.not.exist;
done();
});
});
})
);

it(
'should rewind a cursor',
withClientV2(function (client, done) {
const coll = client.db().collection('rewind');
const cursor = coll.find({});
this.defer(() => cursor.close());

cursor.toArray((err, docs) => {
expect(err).to.not.exist;
expect(docs).to.have.length(2);

cursor.rewind();
cursor.toArray((err, docs) => {
expect(err).to.not.exist;
expect(docs).to.have.length(2);

done();
});
});
})
);

it(
'should end an implicit session on rewind',
withClientV2(function (client, done) {
const coll = client.db().collection('rewind');
const cursor = coll.find({}, { batchSize: 1 });
this.defer(() => cursor.close());

cursor.next((err, doc) => {
expect(err).to.not.exist;
expect(doc).to.exist;

const session = cursor.session;
expect(session).property('hasEnded').to.be.false;
cursor.rewind();
expect(session).property('hasEnded').to.be.true;
done();
});
})
);

it(
'should not end an explicit session on rewind',
withClientV2(function (client, done) {
const coll = client.db().collection('rewind');
const session = client.startSession();

const cursor = coll.find({}, { batchSize: 1, session });
this.defer(() => cursor.close());

cursor.next((err, doc) => {
expect(err).to.not.exist;
expect(doc).to.exist;

const session = cursor.session;
expect(session).property('hasEnded').to.be.false;
cursor.rewind();
expect(session).property('hasEnded').to.be.false;

session.endSession(done);
});
})
);
});
});
3 changes: 1 addition & 2 deletions test/functional/operation_example.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4908,8 +4908,7 @@ describe('Operation Examples', function () {
* @example-class Cursor
* @example-method rewind
*/
// NOTE: unclear whether we should continue to support `rewind`
it.skip('Should correctly rewind and restart cursor', {
it('Should correctly rewind and restart cursor', {
// Add a tag that our runner can trigger on
// in this case we are setting that node needs to be higher than 0.10.X to run
metadata: {
Expand Down

0 comments on commit 8f24e65

Please sign in to comment.