Skip to content

Commit b78bb89

Browse files
mbroadstdaprahamian
authored andcommitted
feat: support operations passed to a Cursor or subclass
This is piecemeal change towards the future we're looking for in the cursor: no longer accepting `ns` and `cmd`, but rather just an operation. This allows us to disambiguate options management for the cursor, as well as reusing `executeOperation` for features such as retryability and sessions management.
1 parent 3f9c0f5 commit b78bb89

File tree

3 files changed

+69
-12
lines changed

3 files changed

+69
-12
lines changed

lib/core/cursor.js

+33-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const f = require('util').format;
99
const collationNotSupported = require('./utils').collationNotSupported;
1010
const ReadPreference = require('./topologies/read_preference');
1111
const isUnifiedTopology = require('./utils').isUnifiedTopology;
12+
const executeOperation = require('../operations/execute_operation');
1213

1314
const BSON = retrieveBSON();
1415
const Long = BSON.Long;
@@ -48,6 +49,13 @@ const Long = BSON.Long;
4849
var Cursor = function(topology, ns, cmd, options) {
4950
options = options || {};
5051

52+
if (typeof ns !== 'string') {
53+
this.operation = ns;
54+
ns = this.operation.ns.toString();
55+
options = this.operation.options;
56+
cmd = {};
57+
}
58+
5159
// Cursor pool
5260
this.pool = null;
5361
// Cursor server
@@ -689,12 +697,36 @@ Cursor.prototype._initializeCursor = function(callback) {
689697
done(null, result);
690698
};
691699

700+
if (cursor.operation) {
701+
executeOperation(cursor.topology, cursor.operation, (err, result, server) => {
702+
if (err) {
703+
done(err);
704+
return;
705+
}
706+
707+
cursor.server = server;
708+
cursor.cursorState.init = true;
709+
710+
// NOTE: this is a special internal method for cloning a cursor, consider removing
711+
if (cursor.cursorState.cursorId != null) {
712+
return done();
713+
}
714+
715+
queryCallback(err, result);
716+
});
717+
718+
return;
719+
}
720+
692721
// Very explicitly choose what is passed to selectServer
693722
const serverSelectOptions = {};
694723
if (cursor.cursorState.session) {
695724
serverSelectOptions.session = cursor.cursorState.session;
696725
}
697-
if (cursor.options.readPreference) {
726+
727+
if (cursor.operation) {
728+
serverSelectOptions.readPreference = cursor.operation.readPreference;
729+
} else if (cursor.options.readPreference) {
698730
serverSelectOptions.readPreference = cursor.options.readPreference;
699731
}
700732

lib/cursor.js

+34-10
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ function Cursor(topology, ns, cmd, options) {
113113
const bson = topology.s.bson;
114114
const topologyOptions = topology.s.options;
115115

116+
if (typeof ns !== 'string') {
117+
this.operation = ns;
118+
ns = this.operation.ns.toString();
119+
options = this.operation.options;
120+
cmd = {};
121+
}
122+
116123
// Tailable cursor options
117124
const numberOfRetries = options.numberOfRetries || 5;
118125
const tailableRetryInterval = options.tailableRetryInterval || 500;
@@ -168,12 +175,14 @@ function Cursor(topology, ns, cmd, options) {
168175
this.sortValue = this.s.cmd.sort;
169176

170177
// Get the batchSize
171-
const batchSize =
172-
cmd.cursor && cmd.cursor.batchSize
173-
? cmd.cursor && cmd.cursor.batchSize
174-
: options.cursor && options.cursor.batchSize
175-
? options.cursor.batchSize
176-
: 1000;
178+
let batchSize = 1000;
179+
if (cmd.cursor && cmd.cursor.batchSize) {
180+
batchSize = cmd.cursor && cmd.cursor.batchSize;
181+
} else if (options.cursor && options.cursor.batchSize) {
182+
batchSize = options.cursor.batchSize;
183+
} else if (typeof options.batchSize === 'number') {
184+
batchSize = options.batchSize;
185+
}
177186

178187
// Set the batchSize
179188
this.setCursorBatchSize(batchSize);
@@ -224,10 +233,19 @@ for (let name in CoreCursor.prototype) {
224233
}
225234

226235
Cursor.prototype._initializeCursor = function(callback) {
227-
// implicitly create a session if one has not been provided
228-
if (!this.s.explicitlyIgnoreSession && !this.s.session && this.s.topology.hasSessionSupport()) {
229-
this.s.session = this.s.topology.startSession({ owner: this });
230-
this.cursorState.session = this.s.session;
236+
if (this.operation && this.operation.session != null) {
237+
this.s.session = this.operation.session;
238+
this.cursorState.session = this.operation.session;
239+
} else {
240+
// implicitly create a session if one has not been provided
241+
if (!this.s.explicitlyIgnoreSession && !this.s.session && this.s.topology.hasSessionSupport()) {
242+
this.s.session = this.s.topology.startSession({ owner: this });
243+
this.cursorState.session = this.s.session;
244+
245+
if (this.operation) {
246+
this.operation.session = this.s.session;
247+
}
248+
}
231249
}
232250

233251
CoreCursor.prototype._initializeCursor.apply(this, [callback]);
@@ -1000,6 +1018,12 @@ Cursor.prototype.transformStream = function(options) {
10001018
* @return {Promise} returns Promise if no callback passed
10011019
*/
10021020
Cursor.prototype.explain = function(callback) {
1021+
if (this.operation) {
1022+
this.operation.explain = true;
1023+
executeOperation(this.s.topology, this.operation, callback);
1024+
return;
1025+
}
1026+
10031027
this.s.cmd.explain = true;
10041028

10051029
// Do we have a readConcern

lib/operations/common_functions.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ function nextObject(cursor, callback) {
224224
MongoError.create({ message: 'Cursor is closed', driver: true })
225225
);
226226
}
227-
if (cursor.s.state === Cursor.INIT && cursor.s.cmd.sort) {
227+
228+
if (cursor.s.state === Cursor.INIT && cursor.s.cmd && cursor.s.cmd.sort) {
228229
try {
229230
cursor.s.cmd.sort = formattedOrderClause(cursor.s.cmd.sort);
230231
} catch (err) {

0 commit comments

Comments
 (0)