Skip to content

Commit b6f89cc

Browse files
committed
Implemented hasNext for simpler iteration when using genertors
1 parent 35dede2 commit b6f89cc

File tree

3 files changed

+148
-29
lines changed

3 files changed

+148
-29
lines changed

lib/cursor.js

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ var Cursor = function(bson, ns, cmd, options, topology, topologyOptions) {
120120
, topologyOptions: topologyOptions
121121
// Promise library
122122
, promiseLibrary: promiseLibrary
123+
// Current doc
124+
, currentDoc: null
123125
}
124126

125127
// Legacy fields
@@ -166,12 +168,71 @@ for(var name in CoreCursor.prototype) {
166168
Cursor.prototype[name] = CoreCursor.prototype[name];
167169
}
168170

171+
/**
172+
* Check if there is any document still available in the cursor
173+
* @method
174+
* @param {Cursor~resultCallback} callback The result callback.
175+
* @throws {MongoError}
176+
* @deprecated
177+
* @return {Promise} returns Promise if no callback passed
178+
*/
179+
Cursor.prototype.hasNext = function(callback) {
180+
var self = this;
181+
182+
// Execute using callback
183+
if(typeof callback == 'function') return nextObject(self, function(err, doc) {
184+
if(!doc) return callback(null, false);
185+
self.s.currentDoc = doc;
186+
callback(null, true);
187+
});
188+
189+
// Return a Promise
190+
return new this.s.promiseLibrary(function(resolve, reject) {
191+
nextObject(self, function(err, doc) {
192+
if(self.s.state == Cursor.CLOSED || self.isDead()) return resolve(false);
193+
if(err) return reject(err);
194+
if(!doc) return resolve(false);
195+
self.s.currentDoc = doc;
196+
resolve(true);
197+
});
198+
});
199+
}
200+
201+
202+
/**
203+
* Get the next available document from the cursor, returns null if no more documents are available.
204+
* @method
205+
* @param {Cursor~resultCallback} callback The result callback.
206+
* @throws {MongoError}
207+
* @deprecated
208+
* @return {Promise} returns Promise if no callback passed
209+
*/
169210
Cursor.prototype.next = function(callback) {
170211
var self = this;
171-
if(typeof callback == 'function') return this._next(callback);
212+
213+
// Execute using callback
214+
if(typeof callback == 'function') {
215+
// Return the currentDoc if someone called hasNext first
216+
if(self.s.currentDoc) {
217+
var doc = self.s.currentDoc;
218+
self.s.currentDoc = null;
219+
return callback(null, doc);
220+
}
221+
222+
// Return the next object
223+
return nextObject(self, callback)
224+
};
225+
172226
// Return a Promise
173227
return new this.s.promiseLibrary(function(resolve, reject) {
174-
self._next(function(err, r) {
228+
// Return the currentDoc if someone called hasNext first
229+
if(self.s.currentDoc) {
230+
var doc = self.s.currentDoc;
231+
self.s.currentDoc = null;
232+
return resolve(doc);
233+
}
234+
235+
nextObject(self, function(err, r) {
175236
if(err) return reject(err);
176237
resolve(r);
177238
});
@@ -360,15 +421,7 @@ Cursor.prototype.skip = function(value) {
360421
* The callback format for results
361422
* @callback Cursor~resultCallback
362423
* @param {MongoError} error An error instance representing the error during the execution.
363-
* @param {(object|null)} result The result object if the command was executed successfully.
364-
*/
365-
366-
/**
367-
* Get the next available document from the cursor, returns null if no more documents are available.
368-
* @function external:CoreCursor#next
369-
* @param {Cursor~resultCallback} callback The result callback.
370-
* @throws {MongoError}
371-
* @return {Promise} returns Promise if no callback passed
424+
* @param {(object|null|boolean)} result The result object if the command was executed successfully.
372425
*/
373426

374427
/**
@@ -433,20 +486,7 @@ Cursor.prototype.skip = function(value) {
433486
* @deprecated
434487
* @return {Promise} returns Promise if no callback passed
435488
*/
436-
Cursor.prototype.nextObject = function(callback) {
437-
var self = this;
438-
439-
// Execute using callback
440-
if(typeof callback == 'function') return nextObject(self, callback);
441-
442-
// Return a Promise
443-
return new this.s.promiseLibrary(function(resolve, reject) {
444-
nextObject(self, function(err, r) {
445-
if(err) return reject(err);
446-
resolve(r);
447-
});
448-
});
449-
}
489+
Cursor.prototype.nextObject = Cursor.prototype.next;
450490

451491
var nextObject = function(self, callback) {
452492
if(self.s.state == Cursor.CLOSED || self.isDead()) return handleCallback(callback, new MongoError("Cursor is closed"));

test/functional/operation_example_tests.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5354,6 +5354,84 @@ exports.shouldCorrectlyPeformNextObjectOnCursor = {
53545354
}
53555355
}
53565356

5357+
/**
5358+
* A simple example showing the use of next.
5359+
*
5360+
* @example-class Cursor
5361+
* @example-method next
5362+
* @ignore
5363+
*/
5364+
exports.shouldCorrectlyPeformNextOnCursorWithCallbacks = {
5365+
// Add a tag that our runner can trigger on
5366+
// in this case we are setting that node needs to be higher than 0.10.X to run
5367+
metadata: { requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] } },
5368+
5369+
// The actual test we wish to run
5370+
test: function(configuration, test) {
5371+
var db = configuration.newDbInstance(configuration.writeConcernMax(), {poolSize:1, auto_reconnect:false});
5372+
5373+
db.open(function(err, db) {
5374+
// LINE var MongoClient = require('mongodb').MongoClient,
5375+
// LINE test = require('assert');
5376+
// LINE MongoClient.connect('mongodb://localhost:27017/test', function(err, db) {
5377+
// REPLACE configuration.writeConcernMax() WITH {w:1}
5378+
// REMOVE-LINE restartAndDone
5379+
// REMOVE-LINE test.done();
5380+
// BEGIN
5381+
5382+
// Create a collection
5383+
var collection = db.collection('simple_next_object_collection_with_next');
5384+
5385+
// Insert some documents we can sort on
5386+
collection.insertMany([{a:1}, {a:2}, {a:3}], configuration.writeConcernMax(), function(err, docs) {
5387+
test.equal(null, err);
5388+
5389+
// Do normal ascending sort
5390+
var cursor = collection.find();
5391+
// Perform hasNext check
5392+
cursor.hasNext(function(err, r) {
5393+
test.equal(null, err);
5394+
test.ok(r);
5395+
5396+
cursor.next(function(err, r) {
5397+
test.equal(null, err);
5398+
test.equal(1, r.a);
5399+
5400+
cursor.hasNext(function(err, r) {
5401+
test.equal(null, err);
5402+
test.ok(r);
5403+
5404+
cursor.next(function(err, r) {
5405+
test.equal(null, err);
5406+
test.equal(2, r.a);
5407+
5408+
cursor.hasNext(function(err, r) {
5409+
test.equal(null, err);
5410+
test.ok(r);
5411+
5412+
cursor.next(function(err, r) {
5413+
test.equal(null, err);
5414+
test.equal(3, r.a);
5415+
5416+
cursor.hasNext(function(err, r) {
5417+
test.equal(null, err);
5418+
test.ok(!r);
5419+
5420+
db.close();
5421+
test.done();
5422+
});
5423+
});
5424+
});
5425+
});
5426+
});
5427+
});
5428+
});
5429+
});
5430+
});
5431+
// END
5432+
}
5433+
}
5434+
53575435
/**
53585436
* A simple example showing the use of the cursor explain function.
53595437
*

test/functional/operation_generators_example_tests.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4348,7 +4348,7 @@ exports.shouldCorrectlyPeformNextObjectOnCursorWithGenerators = {
43484348
* A simple example showing the use of next and co module to iterate over cursor
43494349
*
43504350
* @example-class Cursor
4351-
* @example-method nextObject
4351+
* @example-method next
43524352
* @ignore
43534353
*/
43544354
exports.shouldCorrectlyPeformNextOnCursorWithGenerators = {
@@ -4386,11 +4386,12 @@ exports.shouldCorrectlyPeformNextOnCursorWithGenerators = {
43864386
var doc = null;
43874387
var docs = [];
43884388

4389-
// Iterate over all the cursor items
4390-
while((doc = yield cursor.next()) != null) {
4391-
docs.push(doc);
4389+
// Iterate over the cursor
4390+
while(yield cursor.hasNext()) {
4391+
docs.push(yield cursor.next());
43924392
}
43934393

4394+
// Validate the correct number of elements
43944395
test.equal(3, docs.length);
43954396
db.close();
43964397
test.done();

0 commit comments

Comments
 (0)