From ea3eb8f989e96bdab8d13b5ef76955b765324d99 Mon Sep 17 00:00:00 2001 From: Benjamin Pannell Date: Tue, 17 Nov 2015 08:52:22 +0200 Subject: [PATCH] feat: Add ability to use cursor to retrieve a single document --- dist/lib/Cursor.js | 27 +++++++++++++++++++++++++++ dist/lib/Cursor.js.map | 2 +- test/Model.ts | 27 +++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/dist/lib/Cursor.js b/dist/lib/Cursor.js index c1dff17..8f75a64 100644 --- a/dist/lib/Cursor.js +++ b/dist/lib/Cursor.js @@ -111,6 +111,33 @@ var Cursor = (function () { return _this.model.handlers.documentReceived(_this.conditions, document, function (document, isNew, isPartial) { return _this.model.helpers.wrapDocument(document, isNew, isPartial); }); }).nodeify(callback); }; + /** + * Retrieves the next item in the result list and then closes the cursor + * @param {function(Error, TInstance)} callback A callback which is triggered when the next item becomes available + * @return {Promise} A promise which is resolved once the item becomes available and the cursor has been closed. + */ + Cursor.prototype.one = function (callback) { + var _this = this; + return new Bluebird(function (resolve, reject) { + _this.cursor.next(function (err, result) { + if (err) + return reject(err); + return resolve(result); + }); + }).then(function (document) { + return new Bluebird(function (resolve, reject) { + _this.cursor.close(function (err) { + if (err) + return reject(err); + return resolve(document); + }); + }); + }).then(function (document) { + if (!document) + return Bluebird.resolve(null); + return _this.model.handlers.documentReceived(_this.conditions, document, function (document, isNew, isPartial) { return _this.model.helpers.wrapDocument(document, isNew, isPartial); }); + }).nodeify(callback); + }; /** * Returns a new cursor which behaves the same as this one did before any results were retrieved * @return {Cursor} The new cursor which starts at the beginning of the results diff --git a/dist/lib/Cursor.js.map b/dist/lib/Cursor.js.map index 51eb0b9..4373ef0 100644 --- a/dist/lib/Cursor.js.map +++ b/dist/lib/Cursor.js.map @@ -1 +1 @@ -{"version":3,"sources":["lib/Cursor.ts"],"names":["Cursor","Cursor.constructor","Cursor.count","Cursor.forEach","Cursor.map","Cursor.toArray","Cursor.next","Cursor.rewind","Cursor.sort","Cursor.limit","Cursor.skip"],"mappings":"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","file":"lib/Cursor.js","sourcesContent":["import {Model} from './Model';\r\nimport General = require('./General');\r\nimport MongoDB = require('mongodb');\r\nimport Bluebird = require('bluebird');\r\nimport * as Index from './Index';\r\n\r\n/**\r\n * An Iridium collection cursor which allows the itteration through documents\r\n * in the collection, automatically wrapping them in the correct instance type.\r\n *\r\n * @param TDocument The interface representing the collection's documents\r\n * @param TInstance The interface or class used to represent the wrapped documents.\r\n */\r\nexport class Cursor {\r\n /**\r\n * Creates a new Iridium cursor which wraps a MongoDB cursor object\r\n * @param {Model} model The Iridium model that this cursor belongs to\r\n * @param {Object} conditions The conditions that resulte in this cursor being created\r\n * @param {MongoDB.Cursor} cursor The MongoDB native cursor object to be wrapped\r\n * @constructor\r\n */\r\n constructor(private model: Model, private conditions: any, public cursor: MongoDB.Cursor) {\r\n\r\n }\r\n\r\n /**\r\n * Counts the number of documents which are matched by this cursor\r\n * @param {function(Error, Number)} callback A callback which is triggered when the result is available\r\n * @return {Promise} A promise which will resolve with the number of documents matched by this cursor\r\n */\r\n count(callback?: General.Callback): Bluebird {\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.count(true,(err, count) => {\r\n if (err) return reject(err);\r\n return resolve(count);\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Runs the specified handler over each instance in the query results\r\n * @param {function(Instance)} handler The handler which is triggered for each element in the query\r\n * @param {function(Error)} callback A callback which is triggered when all operations have been dispatched\r\n * @return {Promise} A promise which is resolved when all operations have been dispatched\r\n */\r\n forEach(handler: (instance: TInstance) => void, callback?: General.Callback): Bluebird {\r\n var helpers = this.model.helpers;\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.forEach((item: TDocument) => {\r\n this.model.handlers.documentReceived(this.conditions, item, function () { return helpers.wrapDocument.apply(helpers, arguments); }).then(handler);\r\n },(err) => {\r\n if (err) return reject(err);\r\n return resolve(null);\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Runs the specified transform over each instance in the query results and returns the resulting transformed objects\r\n * @param {function(Instance): TResult} transform A handler which is used to transform the result objects\r\n * @param {function(Error, TResult[])} callback A callback which is triggered when the transformations are completed\r\n * @return {Promise} A promise which is fulfilled with the results of the transformations\r\n */\r\n map(transform: (instance: TInstance) => TResult | Bluebird, callback?: General.Callback): Bluebird {\r\n var helpers = this.model.helpers;\r\n return new Bluebird((resolve, reject) => {\r\n var promises: Bluebird[] = [];\r\n this.cursor.forEach((item: TDocument) => {\r\n promises.push(this.model.handlers.documentReceived(this.conditions, item, function () { return helpers.wrapDocument.apply(helpers, arguments); })\r\n .then(<(instance) => TResult>transform));\r\n },(err) => {\r\n if (err) return reject(err);\r\n return resolve(Bluebird.all(promises));\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Retrieves all matching instances and returns them in an array\r\n * @param {function(Error, TInstance[])} callback A callback which is triggered with the resulting instances\r\n * @return {Promise} A promise which resolves with the instances returned by the query\r\n */\r\n toArray(callback?: General.Callback): Bluebird {\r\n var helpers = this.model.helpers;\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.toArray((err, results: any[]) => {\r\n if (err) return reject(err);\r\n return resolve(results);\r\n });\r\n }).map((document) => {\r\n return this.model.handlers.documentReceived(this.conditions, document, function () { return helpers.wrapDocument.apply(helpers, arguments); });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Retrieves the next item in the results list\r\n * @param {function(Error, TInstance)} callback A callback which is triggered when the next item becomes available\r\n * @return {Promise} A promise which is resolved with the next item\r\n */\r\n next(callback?: General.Callback): Bluebird {\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.next((err, result: any) => {\r\n if (err) return reject(err);\r\n return resolve(result);\r\n });\r\n }).then((document) => {\r\n if (!document) return Bluebird.resolve(null);\r\n return this.model.handlers.documentReceived(this.conditions, document,(document, isNew?, isPartial?) => this.model.helpers.wrapDocument(document, isNew, isPartial));\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Returns a new cursor which behaves the same as this one did before any results were retrieved\r\n * @return {Cursor} The new cursor which starts at the beginning of the results\r\n */\r\n rewind(): Cursor {\r\n this.cursor.rewind();\r\n return this;\r\n }\r\n\r\n /**\r\n * Returns a new cursor which sorts its results by the given index expression\r\n * @param {model.IndexSpecification} sortExpression The index expression dictating the sort order and direction to use\r\n * @return {Cursor} The new cursor which sorts its results by the sortExpression\r\n */\r\n sort(sortExpression: Index.IndexSpecification): Cursor {\r\n return new Cursor(this.model, this.conditions, this.cursor.sort(sortExpression));\r\n }\r\n\r\n /**\r\n * Returns a new cursor which limits the number of returned results\r\n * @param {Number} limit The maximum number of results to return\r\n * @return {Cursor} The new cursor which will return a maximum number of results\r\n */\r\n limit(limit: number): Cursor {\r\n return new Cursor(this.model, this.conditions, this.cursor.limit(limit));\r\n }\r\n\r\n /**\r\n * Returns a new cursor which skips a number of results before it begins\r\n * returning any.\r\n * @param {Number} skip The number of results to skip before the cursor beings returning\r\n * @return {Cursor} The new cursor which skips a number of results\r\n */\r\n skip(skip: number): Cursor {\r\n return new Cursor(this.model, this.conditions, this.cursor.skip(skip));\r\n }\r\n}"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["lib/Cursor.ts"],"names":["Cursor","Cursor.constructor","Cursor.count","Cursor.forEach","Cursor.map","Cursor.toArray","Cursor.next","Cursor.one","Cursor.rewind","Cursor.sort","Cursor.limit","Cursor.skip","Cursor.readFrom"],"mappings":"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","file":"lib/Cursor.js","sourcesContent":["import {Model} from './Model';\r\nimport General = require('./General');\r\nimport MongoDB = require('mongodb');\r\nimport Bluebird = require('bluebird');\r\nimport * as Index from './Index';\r\n\r\n/**\r\n * An Iridium collection cursor which allows the itteration through documents\r\n * in the collection, automatically wrapping them in the correct instance type.\r\n *\r\n * @param TDocument The interface representing the collection's documents\r\n * @param TInstance The interface or class used to represent the wrapped documents.\r\n */\r\nexport class Cursor {\r\n /**\r\n * Creates a new Iridium cursor which wraps a MongoDB cursor object\r\n * @param {Model} model The Iridium model that this cursor belongs to\r\n * @param {Object} conditions The conditions that resulte in this cursor being created\r\n * @param {MongoDB.Cursor} cursor The MongoDB native cursor object to be wrapped\r\n * @constructor\r\n */\r\n constructor(private model: Model, private conditions: any, public cursor: MongoDB.Cursor) {\r\n\r\n }\r\n\r\n /**\r\n * Counts the number of documents which are matched by this cursor\r\n * @param {function(Error, Number)} callback A callback which is triggered when the result is available\r\n * @return {Promise} A promise which will resolve with the number of documents matched by this cursor\r\n */\r\n count(callback?: General.Callback): Bluebird {\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.count(true,(err, count) => {\r\n if (err) return reject(err);\r\n return resolve(count);\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Runs the specified handler over each instance in the query results\r\n * @param {function(Instance)} handler The handler which is triggered for each element in the query\r\n * @param {function(Error)} callback A callback which is triggered when all operations have been dispatched\r\n * @return {Promise} A promise which is resolved when all operations have been dispatched\r\n */\r\n forEach(handler: (instance: TInstance) => void, callback?: General.Callback): Bluebird {\r\n var helpers = this.model.helpers;\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.forEach((item: TDocument) => {\r\n this.model.handlers.documentReceived(this.conditions, item, function () { return helpers.wrapDocument.apply(helpers, arguments); }).then(handler);\r\n },(err) => {\r\n if (err) return reject(err);\r\n return resolve(null);\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Runs the specified transform over each instance in the query results and returns the resulting transformed objects\r\n * @param {function(Instance): TResult} transform A handler which is used to transform the result objects\r\n * @param {function(Error, TResult[])} callback A callback which is triggered when the transformations are completed\r\n * @return {Promise} A promise which is fulfilled with the results of the transformations\r\n */\r\n map(transform: (instance: TInstance) => TResult | Bluebird, callback?: General.Callback): Bluebird {\r\n var helpers = this.model.helpers;\r\n return new Bluebird((resolve, reject) => {\r\n var promises: Bluebird[] = [];\r\n this.cursor.forEach((item: TDocument) => {\r\n promises.push(this.model.handlers.documentReceived(this.conditions, item, function () { return helpers.wrapDocument.apply(helpers, arguments); })\r\n .then(<(instance) => TResult>transform));\r\n },(err) => {\r\n if (err) return reject(err);\r\n return resolve(Bluebird.all(promises));\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Retrieves all matching instances and returns them in an array\r\n * @param {function(Error, TInstance[])} callback A callback which is triggered with the resulting instances\r\n * @return {Promise} A promise which resolves with the instances returned by the query\r\n */\r\n toArray(callback?: General.Callback): Bluebird {\r\n var helpers = this.model.helpers;\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.toArray((err, results: any[]) => {\r\n if (err) return reject(err);\r\n return resolve(results);\r\n });\r\n }).map((document) => {\r\n return this.model.handlers.documentReceived(this.conditions, document, function () { return helpers.wrapDocument.apply(helpers, arguments); });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Retrieves the next item in the results list\r\n * @param {function(Error, TInstance)} callback A callback which is triggered when the next item becomes available\r\n * @return {Promise} A promise which is resolved with the next item\r\n */\r\n next(callback?: General.Callback): Bluebird {\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.next((err, result: any) => {\r\n if (err) return reject(err);\r\n return resolve(result);\r\n });\r\n }).then((document) => {\r\n if (!document) return Bluebird.resolve(null);\r\n return this.model.handlers.documentReceived(this.conditions, document,(document, isNew?, isPartial?) => this.model.helpers.wrapDocument(document, isNew, isPartial));\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Retrieves the next item in the result list and then closes the cursor\r\n * @param {function(Error, TInstance)} callback A callback which is triggered when the next item becomes available\r\n * @return {Promise} A promise which is resolved once the item becomes available and the cursor has been closed.\r\n */\r\n one(callback?: General.Callback): Bluebird {\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.next((err, result: any) => {\r\n if (err) return reject(err);\r\n return resolve(result);\r\n });\r\n }).then((document) => {\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.close((err) => {\r\n if (err) return reject(err);\r\n return resolve(document);\r\n });\r\n });\r\n }).then((document) => {\r\n if (!document) return Bluebird.resolve(null);\r\n return this.model.handlers.documentReceived(this.conditions, document,(document, isNew?, isPartial?) => this.model.helpers.wrapDocument(document, isNew, isPartial));\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Returns a new cursor which behaves the same as this one did before any results were retrieved\r\n * @return {Cursor} The new cursor which starts at the beginning of the results\r\n */\r\n rewind(): Cursor {\r\n this.cursor.rewind();\r\n return this;\r\n }\r\n\r\n /**\r\n * Returns a new cursor which sorts its results by the given index expression\r\n * @param {model.IndexSpecification} sortExpression The index expression dictating the sort order and direction to use\r\n * @return {Cursor} The new cursor which sorts its results by the sortExpression\r\n */\r\n sort(sortExpression: Index.IndexSpecification): Cursor {\r\n return new Cursor(this.model, this.conditions, this.cursor.sort(sortExpression));\r\n }\r\n\r\n /**\r\n * Returns a new cursor which limits the number of returned results\r\n * @param {Number} limit The maximum number of results to return\r\n * @return {Cursor} The new cursor which will return a maximum number of results\r\n */\r\n limit(limit: number): Cursor {\r\n return new Cursor(this.model, this.conditions, this.cursor.limit(limit));\r\n }\r\n\r\n /**\r\n * Returns a new cursor which skips a number of results before it begins\r\n * returning any.\r\n * @param {Number} skip The number of results to skip before the cursor beings returning\r\n * @return {Cursor} The new cursor which skips a number of results\r\n */\r\n skip(skip: number): Cursor {\r\n return new Cursor(this.model, this.conditions, this.cursor.skip(skip));\r\n }\r\n\r\n /**\r\n * Returns a new cursor which will read from the specified node type.\r\n * @param {String} type The type of node to read from - see https://docs.mongodb.org/manual/core/read-preference/\r\n * @return {Cursor} The new cursor which reads from the specified node type\r\n */\r\n readFrom(type: string): Cursor {\r\n return new Cursor(this.model, this.conditions, this.cursor.setReadPreference(type));\r\n }\r\n}"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/test/Model.ts b/test/Model.ts index 6af1995..57bb6e9 100644 --- a/test/Model.ts +++ b/test/Model.ts @@ -599,6 +599,33 @@ describe("Model",() => { }); }); + describe("one()", () => { + it("should return a promise",() => { + chai.expect(model.find().one()).to.be.an.instanceof(Promise); + }); + + it("which should resolve to the next instance in the query",() => { + return chai.expect(model.find().one()).to.eventually.be.an.instanceof(model.Instance); + }); + + it("should be capable of functioning correctly with empty result sets",() => { + return chai.expect(model.find({ nothing: true }).one()).to.eventually.not.exist; + }); + + it("should support using callbacks instead of promises",(done) => { + model.find().one((err, instance) => { + if (err) return done(err); + chai.expect(instance).to.be.an.instanceof(model.Instance); + return done(); + }); + }); + + it("should not allow you to call it more than once", () => { + let cursor = model.find(); + return chai.expect(cursor.one().then(() => cursor.one())).to.eventually.be.rejected; + }); + }); + describe("rewind()",() => { it("should return a new cursor",() => { chai.expect(model.find().rewind()).to.be.an.instanceof(Cursor);