From acf1d778cfc155b28bc899e39a142f351ec05a02 Mon Sep 17 00:00:00 2001 From: Christian Howe Date: Sat, 28 Jul 2012 21:07:10 -0400 Subject: [PATCH 01/10] started mongodb engine --- lib/resourceful/engines/mongodb/index.js | 151 +++++++++++++++++++++++ package.json | 1 + 2 files changed, 152 insertions(+) create mode 100644 lib/resourceful/engines/mongodb/index.js diff --git a/lib/resourceful/engines/mongodb/index.js b/lib/resourceful/engines/mongodb/index.js new file mode 100644 index 0000000..b65c6ab --- /dev/null +++ b/lib/resourceful/engines/mongodb/index.js @@ -0,0 +1,151 @@ +var url = require('url'), + async = require('async'), + mongodb = require('mongodb'), + Db = mongodb.Db, + Server = mongodb.Server, + Connection = mongodb.Connection; + +var Mongodb = exports.Mongodb = function Mongodb (config) { + if (config.uri) { + var parsed = url.parsed('couchdb://'+config.uri); + config.uri = parsed.hostname; + config.port = parseInt(parsed.port, 10); + config.database = (parsed.pathname || '').replace(/^\//, ''); + } + + this.user = config.auth.user; + this.pass = config.auth.pass; + + this.db = new Db(config.database, new Server(config.uri, config.port)); + + this.collection = config.collection; +} + +Mongodb.prototype.protocol = 'mongodb'; + +Mongodb.prototype.load = function (data) { + throw new Error('Load not valid for mongodb engine') +} + +Mongodb.prototype.setup = function (callback) { + this.db.open(function (err, p_client) { + if (err) { + return callback(err); + } + this.db.authenticate(this.user, this.pass, function(err, result) { + if (err) { + return callback(err); + } + if (result !== true) { + return callback(new Error('Failed to authenticate')); + } + this.db.collection(this.collection, function (err, collection) { + if (err) { + return callback(err); + } + this.client = collection; + return callback(null); + }); + }); + }); +} + +Mongodb.prototype.request = function (method) { + var self = this, + args = Array.prototype.slice.call(arguments, 1); + finish = function () { + self.client[method].apply(self.client, args) + }; + + if (!this.client) { + this.setup(function (err) { + if (err) { + throw err; // sure why not + } + return finish(); + }); + } + else { + return finish(); + } +} + +Mongodb.prototype.get = function (id, callback) { + if (Array.isArray(id)) { + return async.concat(id, function (cb, i) { + this.get(i, cb); + }, callback); + } + + return this.request('findOne', {_id: id}, function (err, doc) { + if (err) return callback(err); + + doc.id = doc._id; + delete doc._id; + callback(null, doc); + }); +} + +Mongodb.prototype.put = function (id, doc, callback) { + delete doc.id; + doc._id = id; + return this.request('insert', doc, {safe: true}, function (err) { + if (err) return callback(err); + + doc.id = id; + delete doc._id; + callback(null, doc); + }); +}; + +Mongodb.prototype.post = Mongodb.prototype.create = function (doc, callback) { + return this.request('insert', doc, {safe: true}, function (err, res) { + if (err) return callback(err); + + doc.id = res[0]._id; + callback(null, doc); + }); +}; + +// ripped from couchdb engine :P +Mongodb.prototype.save = function (id, doc, callback) { + var args = Array.prototype.slice.call(arguments, 0), + callback = args.pop(), + doc = args.pop(); + + // if there's an ID left in args after popping off the callback and + // the doc, then we need to PUT, otherwise create a new record thru POST + if (args.length) { + return this.put.apply(this, arguments); + } + + // checks for presence of _id in doc, just in case the caller forgot + // to add an id as first argument + if (doc.id) { + return this.put.apply(this, [doc.id, doc, callback]); + } else { + return this.post.call(this, doc, callback); + } +}; + +Mongodb.prototype.update = function (id, doc, callback) { + return this.request('update', {_id: id}, doc, {safe: true}, + function (err, res) { + if (err) return callback(err); + + doc.id = res[0]._id; + callback(null, doc); + }); +}; + +Mongodb.prototype.destroy = function (id, callback) { + return this.request('remove', {_id: id}, {safe: true} function (err, num) { + if (err) return callback(err); + + callback(null, this.cache.get(id) || { id: id }); + }); +} + +Mongodb.prototype.find = function (conditions, callback) { + +} diff --git a/package.json b/package.json index 246d3db..a9d72d9 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "dependencies": { "async": "0.1.x", "cradle": "0.6.x", + "mongodb": "1.1.x", "i": "0.3.x", "revalidator": "0.1.x", "node-uuid": "1.3.x" From 11a8a75054ae2a8b7a023906fb28bcfa8975b088 Mon Sep 17 00:00:00 2001 From: Christian Howe Date: Fri, 3 Aug 2012 09:33:30 -0400 Subject: [PATCH 02/10] Add find function. --- lib/resourceful/engines/mongodb/index.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/resourceful/engines/mongodb/index.js b/lib/resourceful/engines/mongodb/index.js index b65c6ab..76e23dc 100644 --- a/lib/resourceful/engines/mongodb/index.js +++ b/lib/resourceful/engines/mongodb/index.js @@ -139,13 +139,21 @@ Mongodb.prototype.update = function (id, doc, callback) { }; Mongodb.prototype.destroy = function (id, callback) { - return this.request('remove', {_id: id}, {safe: true} function (err, num) { + return this.request('remove', {_id: id}, {safe: true}, function (err, num) { if (err) return callback(err); callback(null, this.cache.get(id) || { id: id }); }); -} +}; Mongodb.prototype.find = function (conditions, callback) { + return this.request('find', conditions).toArray(function (err, res) { + if (err) return callback(err); + + callback(null, res); + }); +}; + +Mongodb.prototype.filter = function (name, data) { } From 56d4eaa579b5f1301110c138544b949b2c2c74c0 Mon Sep 17 00:00:00 2001 From: Christian Howe Date: Tue, 7 Aug 2012 12:24:51 -0400 Subject: [PATCH 03/10] Add filter method --- .../engines/{mongodb/index.js => mongodb.js} | 124 +++++++++++------- 1 file changed, 77 insertions(+), 47 deletions(-) rename lib/resourceful/engines/{mongodb/index.js => mongodb.js} (52%) diff --git a/lib/resourceful/engines/mongodb/index.js b/lib/resourceful/engines/mongodb.js similarity index 52% rename from lib/resourceful/engines/mongodb/index.js rename to lib/resourceful/engines/mongodb.js index 76e23dc..fb9d8aa 100644 --- a/lib/resourceful/engines/mongodb/index.js +++ b/lib/resourceful/engines/mongodb.js @@ -7,15 +7,15 @@ var url = require('url'), var Mongodb = exports.Mongodb = function Mongodb (config) { if (config.uri) { - var parsed = url.parsed('couchdb://'+config.uri); + var parsed = url.parse('mongodb://'+config.uri); config.uri = parsed.hostname; config.port = parseInt(parsed.port, 10); config.database = (parsed.pathname || '').replace(/^\//, ''); } - + this.user = config.auth.user; this.pass = config.auth.pass; - + this.db = new Db(config.database, new Server(config.uri, config.port)); this.collection = config.collection; @@ -28,82 +28,88 @@ Mongodb.prototype.load = function (data) { } Mongodb.prototype.setup = function (callback) { + var self = this; this.db.open(function (err, p_client) { if (err) { return callback(err); } - this.db.authenticate(this.user, this.pass, function(err, result) { + self.db.authenticate(self.user, self.pass, function (err, result) { if (err) { return callback(err); } if (result !== true) { return callback(new Error('Failed to authenticate')); } - this.db.collection(this.collection, function (err, collection) { + self.db.collection(self.collection, function (err, collection) { if (err) { return callback(err); } - this.client = collection; + self.client = collection; return callback(null); }); }); }); } -Mongodb.prototype.request = function (method) { - var self = this, - args = Array.prototype.slice.call(arguments, 1); - finish = function () { - self.client[method].apply(self.client, args) - }; - +Mongodb.prototype.request = function (callback) { if (!this.client) { - this.setup(function (err) { + return this.setup(function (err) { if (err) { throw err; // sure why not } - return finish(); + return callback(); }); } else { - return finish(); + return process.nextTick(function (client) { + return callback(); + }); } } Mongodb.prototype.get = function (id, callback) { + var self = this; if (Array.isArray(id)) { return async.concat(id, function (cb, i) { - this.get(i, cb); + self.get(i, cb); }, callback); } - return this.request('findOne', {_id: id}, function (err, doc) { - if (err) return callback(err); + return this.request(function () { + self.client.findOne({_id: id}, function (err, doc) { + if (err) return callback(err); - doc.id = doc._id; - delete doc._id; - callback(null, doc); + doc.id = doc._id; + delete doc._id; + callback(null, doc); + }); }); } Mongodb.prototype.put = function (id, doc, callback) { - delete doc.id; - doc._id = id; - return this.request('insert', doc, {safe: true}, function (err) { - if (err) return callback(err); - - doc.id = id; - delete doc._id; - callback(null, doc); + var self = this; + return this.request(function () { + delete doc.id; + doc._id = id; + self.client.insert(doc, {safe: true}, function (err) { + if (err) return callback(err); + + doc.id = id; + delete doc._id; + callback(null, doc); + }); }); }; Mongodb.prototype.post = Mongodb.prototype.create = function (doc, callback) { - return this.request('insert', doc, {safe: true}, function (err, res) { - if (err) return callback(err); + var self = this; + return this.request(function () { + self.client.insert(doc, {safe: true}, function (err, res) { + if (err) return callback(err); - doc.id = res[0]._id; - callback(null, doc); + doc.id = res[0]._id; + callback(null, doc); + }); }); }; @@ -129,31 +135,55 @@ Mongodb.prototype.save = function (id, doc, callback) { }; Mongodb.prototype.update = function (id, doc, callback) { - return this.request('update', {_id: id}, doc, {safe: true}, - function (err, res) { - if (err) return callback(err); + var self = this; + return this.request(function() { + self.client.update({_id: id}, doc, {safe: true}, function (err, res) { + if (err) return callback(err); - doc.id = res[0]._id; - callback(null, doc); + doc.id = res[0]._id; + callback(null, doc); + }); }); }; Mongodb.prototype.destroy = function (id, callback) { - return this.request('remove', {_id: id}, {safe: true}, function (err, num) { - if (err) return callback(err); + var self = this; + return this.request(function () { + self.remove({_id: id}, {safe: true}, function (err, num) { + if (err) return callback(err); - callback(null, this.cache.get(id) || { id: id }); + callback(null, self.cache.get(id) || { id: id }); + }); }); }; Mongodb.prototype.find = function (conditions, callback) { - return this.request('find', conditions).toArray(function (err, res) { - if (err) return callback(err); + return this.request(function () { + self.find(conditions).toArray(function (err, res) { + if (err) return callback(err); - callback(null, res); + callback(null, res); + }); + }); +}; + +Mongodb.prototype.filter = function (filter, callback) { + var result = [] + return this.request(function () { + self.client.find().each(function (err, doc) { + if (err) return callback(err); + + if (doc === null) { + return callback(null, result); + } + + if (filter(doc)) { + result.push(doc); + } + }); }); }; -Mongodb.prototype.filter = function (name, data) { - +Mongodb.prototype.sync = function () { + process.nextTick(function () { callback(); }); //do nothing } From cb673caa83921fd59383ee2641b4662d5611e1d1 Mon Sep 17 00:00:00 2001 From: Christian Howe Date: Tue, 7 Aug 2012 12:37:54 -0400 Subject: [PATCH 04/10] Fix request to account for cursor chaining API --- lib/resourceful/engines/mongodb.js | 78 ++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/lib/resourceful/engines/mongodb.js b/lib/resourceful/engines/mongodb.js index fb9d8aa..9372479 100644 --- a/lib/resourceful/engines/mongodb.js +++ b/lib/resourceful/engines/mongodb.js @@ -13,10 +13,12 @@ var Mongodb = exports.Mongodb = function Mongodb (config) { config.database = (parsed.pathname || '').replace(/^\//, ''); } - this.user = config.auth.user; - this.pass = config.auth.pass; + this.user = config.auth ? config.auth.user : null; + this.pass = config.auth ? config.auth.pass : null; - this.db = new Db(config.database, new Server(config.uri, config.port)); + this.db = new Db(config.database || resourceful.env, + new Server(config.host || config.uri || '127.0.0.1', + config.port || 27017)); this.collection = config.collection; } @@ -27,12 +29,19 @@ Mongodb.prototype.load = function (data) { throw new Error('Load not valid for mongodb engine') } -Mongodb.prototype.setup = function (callback) { +Mongodb.prototype.setup = function (cb) { var self = this; - this.db.open(function (err, p_client) { - if (err) { - return callback(err); - } + + var getCollection = function (callback) { + self.db.collection(self.collection, function (err, collection) { + if (err) return callback(err); + + self.client = collection; + return callback(null); + }); + }; + + var authenticate = function (callback) { self.db.authenticate(self.user, self.pass, function (err, result) { if (err) { return callback(err); @@ -40,14 +49,19 @@ Mongodb.prototype.setup = function (callback) { if (result !== true) { return callback(new Error('Failed to authenticate')); } - self.db.collection(self.collection, function (err, collection) { - if (err) { - return callback(err); - } - self.client = collection; - return callback(null); - }); + return getCollection(callback); }); + } + + this.db.open(function (err, p_client) { + if (err) { + return callback(err); + } + if (self.user && self.pass) { + return authenticate(cb); + } + + return getCollection(cb); }); } @@ -55,14 +69,14 @@ Mongodb.prototype.request = function (callback) { if (!this.client) { return this.setup(function (err) { if (err) { - throw err; // sure why not + return callback(err); // sure why not } - return callback(); + return callback(null); }); } else { return process.nextTick(function (client) { - return callback(); + return callback(null); }); } } @@ -75,7 +89,9 @@ Mongodb.prototype.get = function (id, callback) { }, callback); } - return this.request(function () { + return this.request(function (err) { + if (err) return callback(err); + self.client.findOne({_id: id}, function (err, doc) { if (err) return callback(err); @@ -88,7 +104,9 @@ Mongodb.prototype.get = function (id, callback) { Mongodb.prototype.put = function (id, doc, callback) { var self = this; - return this.request(function () { + return this.request(function (err) { + if (err) return callback(err); + delete doc.id; doc._id = id; self.client.insert(doc, {safe: true}, function (err) { @@ -103,7 +121,9 @@ Mongodb.prototype.put = function (id, doc, callback) { Mongodb.prototype.post = Mongodb.prototype.create = function (doc, callback) { var self = this; - return this.request(function () { + return this.request(function (err) { + if (err) return callback(err); + self.client.insert(doc, {safe: true}, function (err, res) { if (err) return callback(err); @@ -136,7 +156,9 @@ Mongodb.prototype.save = function (id, doc, callback) { Mongodb.prototype.update = function (id, doc, callback) { var self = this; - return this.request(function() { + return this.request(function(err) { + if (err) return callback(err); + self.client.update({_id: id}, doc, {safe: true}, function (err, res) { if (err) return callback(err); @@ -148,7 +170,9 @@ Mongodb.prototype.update = function (id, doc, callback) { Mongodb.prototype.destroy = function (id, callback) { var self = this; - return this.request(function () { + return this.request(function (err) { + if (err) return callback(err); + self.remove({_id: id}, {safe: true}, function (err, num) { if (err) return callback(err); @@ -158,7 +182,9 @@ Mongodb.prototype.destroy = function (id, callback) { }; Mongodb.prototype.find = function (conditions, callback) { - return this.request(function () { + return this.request(function (err) { + if (err) return callback(err); + self.find(conditions).toArray(function (err, res) { if (err) return callback(err); @@ -169,7 +195,9 @@ Mongodb.prototype.find = function (conditions, callback) { Mongodb.prototype.filter = function (filter, callback) { var result = [] - return this.request(function () { + return this.request(function (err) { + if (err) return callback(err); + self.client.find().each(function (err, doc) { if (err) return callback(err); From 1e2288eb52a118d28ff5cc5b620048c0da1d9ee0 Mon Sep 17 00:00:00 2001 From: Christian Howe Date: Thu, 23 Aug 2012 08:52:17 -0500 Subject: [PATCH 05/10] Add mongodb test engine. --- test/engines/mongodb.js | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 test/engines/mongodb.js diff --git a/test/engines/mongodb.js b/test/engines/mongodb.js new file mode 100644 index 0000000..1e26964 --- /dev/null +++ b/test/engines/mongodb.js @@ -0,0 +1,44 @@ +var mongodb = require('mongodb'), + Db = mongodb.Db, + Server = mongodb.Server, + Connection = mongodb.Connection; + +var engine = exports; + +engine.name = 'mongodb'; +engine.options = { + host: 'alex.mongohq.com', + port: 10047, + database: 'nodejitsudb15119137141', + user: 'nodejitsu', + pass: '48be573a3772606f1e03dd765ea2a2ee', + collection: 'test' +}; + +engine.load = function (resourceful, data, callback) { + var db = new Db(engine.options.database, + new Server(engine.options.host, engine.options.port)); + + db.open(function (err) { + if (err) return callback(err); + + db.authenticate(engine.options.user, engine.options.pass, function (err, result) { + if (err) return callback(err); + if (result !== true) return callback(new Error('Failed to authenticate.')); + + db.collection(engine.options.collection, function (err, collection) { + if (err) return callback(err); + + collection.remove(function (err) { + if (err) return callback(err); + + collection.insert(data, {safe: true}, function (err) { + if (err) return callback(err); + + return callback(null); + }); + }); + }); + }); + }); +}; From e0c8d37a8f0b967d1f0678cc8841431347157415 Mon Sep 17 00:00:00 2001 From: Christian Howe Date: Thu, 23 Aug 2012 09:09:04 -0500 Subject: [PATCH 06/10] Add Mongodb.prototype.load, remove Mongodb.prototype.sync --- lib/resourceful/engines/mongodb.js | 39 +++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/lib/resourceful/engines/mongodb.js b/lib/resourceful/engines/mongodb.js index 9372479..8440fa0 100644 --- a/lib/resourceful/engines/mongodb.js +++ b/lib/resourceful/engines/mongodb.js @@ -1,6 +1,7 @@ var url = require('url'), async = require('async'), mongodb = require('mongodb'), + common = require('../common'), Db = mongodb.Db, Server = mongodb.Server, Connection = mongodb.Connection; @@ -21,14 +22,10 @@ var Mongodb = exports.Mongodb = function Mongodb (config) { config.port || 27017)); this.collection = config.collection; -} +}; Mongodb.prototype.protocol = 'mongodb'; -Mongodb.prototype.load = function (data) { - throw new Error('Load not valid for mongodb engine') -} - Mongodb.prototype.setup = function (cb) { var self = this; @@ -51,7 +48,7 @@ Mongodb.prototype.setup = function (cb) { } return getCollection(callback); }); - } + }; this.db.open(function (err, p_client) { if (err) { @@ -63,7 +60,7 @@ Mongodb.prototype.setup = function (cb) { return getCollection(cb); }); -} +}; Mongodb.prototype.request = function (callback) { if (!this.client) { @@ -79,7 +76,7 @@ Mongodb.prototype.request = function (callback) { return callback(null); }); } -} +}; Mongodb.prototype.get = function (id, callback) { var self = this; @@ -100,7 +97,25 @@ Mongodb.prototype.get = function (id, callback) { callback(null, doc); }); }); -} +}; + +Mongodb.prototype.load = function (data) { + var array = common.clone(data); + return this.request(function (err) { + if (err) return callback(err); + + for (var i in array) { + array[i]._id = array[i].id; + delete array[i].id; + } + + self.client.insert(array, {safe: true}, function (err) { + if (err) return callback(err); + + callback(null); + }); + }); +}; Mongodb.prototype.put = function (id, doc, callback) { var self = this; @@ -194,7 +209,7 @@ Mongodb.prototype.find = function (conditions, callback) { }; Mongodb.prototype.filter = function (filter, callback) { - var result = [] + var result = []; return this.request(function (err) { if (err) return callback(err); @@ -211,7 +226,3 @@ Mongodb.prototype.filter = function (filter, callback) { }); }); }; - -Mongodb.prototype.sync = function () { - process.nextTick(function () { callback(); }); //do nothing -} From fd3bd6d27495d491fe5a18ef2d709833242d6d9b Mon Sep 17 00:00:00 2001 From: Christian Howe Date: Mon, 27 Aug 2012 23:10:00 -0500 Subject: [PATCH 07/10] Fix resourceful/engines/mongodb tests --- lib/resourceful/engines/mongodb.js | 117 +++++++++++++++++++++-------- test/engines/mongodb.js | 4 +- 2 files changed, 88 insertions(+), 33 deletions(-) diff --git a/lib/resourceful/engines/mongodb.js b/lib/resourceful/engines/mongodb.js index 8440fa0..6d8c5ee 100644 --- a/lib/resourceful/engines/mongodb.js +++ b/lib/resourceful/engines/mongodb.js @@ -2,6 +2,7 @@ var url = require('url'), async = require('async'), mongodb = require('mongodb'), common = require('../common'), + resourceful = require('../../resourceful'), Db = mongodb.Db, Server = mongodb.Server, Connection = mongodb.Connection; @@ -14,14 +15,16 @@ var Mongodb = exports.Mongodb = function Mongodb (config) { config.database = (parsed.pathname || '').replace(/^\//, ''); } - this.user = config.auth ? config.auth.user : null; - this.pass = config.auth ? config.auth.pass : null; + this.user = config.auth ? config.auth.user : config.user || null; + this.pass = config.auth ? config.auth.pass : config.pass || null; - this.db = new Db(config.database || resourceful.env, + this.db = new Db(config.database || resourceful.env || 'default', new Server(config.host || config.uri || '127.0.0.1', config.port || 27017)); - this.collection = config.collection; + this.collection = config.collection || 'resourceful'; + + this.cache = new resourceful.Cache(); }; Mongodb.prototype.protocol = 'mongodb'; @@ -81,9 +84,26 @@ Mongodb.prototype.request = function (callback) { Mongodb.prototype.get = function (id, callback) { var self = this; if (Array.isArray(id)) { - return async.concat(id, function (cb, i) { - self.get(i, cb); - }, callback); + var array = []; + return async.forEachSeries(id, function (i, cb) { + self.get(i, function (err, doc) { + if (err) { + if (err.status === 404) { + doc = null; + } + else { + return cb(err); + } + } + + array.push(doc); + + return cb(null); + }); + }, function (err) { + if (err) return callback(err); + callback(null, array); + }); } return this.request(function (err) { @@ -92,14 +112,23 @@ Mongodb.prototype.get = function (id, callback) { self.client.findOne({_id: id}, function (err, doc) { if (err) return callback(err); - doc.id = doc._id; - delete doc._id; - callback(null, doc); + if (doc !== null) { + doc.id = doc._id; + delete doc._id; + } + else { + var error = new Error('Document '+id+' not found.'); + error.status = 404; + return callback(error); + } + + return callback(null, doc); }); }); }; Mongodb.prototype.load = function (data) { + var self = this; var array = common.clone(data); return this.request(function (err) { if (err) return callback(err); @@ -148,37 +177,55 @@ Mongodb.prototype.post = Mongodb.prototype.create = function (doc, callback) { }); }; -// ripped from couchdb engine :P -Mongodb.prototype.save = function (id, doc, callback) { - var args = Array.prototype.slice.call(arguments, 0), +Mongodb.prototype.save = function (/*id, doc, callback*/) { + var self = this, + args = Array.prototype.slice.call(arguments, 0), callback = args.pop(), - doc = args.pop(); + doc = args.pop(), + id = args.pop(); - // if there's an ID left in args after popping off the callback and - // the doc, then we need to PUT, otherwise create a new record thru POST - if (args.length) { - return this.put.apply(this, arguments); + if (!id && !doc.id) { + //no id available, so we must be inserting a new document. same as `post` :D + return this.post(doc, callback); } - // checks for presence of _id in doc, just in case the caller forgot - // to add an id as first argument - if (doc.id) { - return this.put.apply(this, [doc.id, doc, callback]); - } else { - return this.post.call(this, doc, callback); + if (id) { + save = common.clone(doc); + save._id = doc.id = id; + } + else { + save = common.clone(doc); + save._id = save.id; + delete save.id; } + + return this.request(function (err) { + if (err) return callback(err); + + self.client.save(save, {safe: true}, function (err) { + if (err) return callback(err); + + return callback(null, doc); + }); + }); }; -Mongodb.prototype.update = function (id, doc, callback) { +Mongodb.prototype.update = function (id, update, callback) { var self = this; return this.request(function(err) { if (err) return callback(err); - self.client.update({_id: id}, doc, {safe: true}, function (err, res) { + self.client.update({_id: id}, {$set: update}, {safe: true}, function (err, res) { if (err) return callback(err); - doc.id = res[0]._id; - callback(null, doc); + self.client.findOne({_id: id}, function (err, doc) { + if (err) return callback(err); + + doc.id = doc._id; + delete doc._id; + + callback(null, doc); + }); }); }); }; @@ -188,7 +235,7 @@ Mongodb.prototype.destroy = function (id, callback) { return this.request(function (err) { if (err) return callback(err); - self.remove({_id: id}, {safe: true}, function (err, num) { + self.client.remove({_id: id}, {safe: true}, function (err, num) { if (err) return callback(err); callback(null, self.cache.get(id) || { id: id }); @@ -197,18 +244,26 @@ Mongodb.prototype.destroy = function (id, callback) { }; Mongodb.prototype.find = function (conditions, callback) { + var self = this; return this.request(function (err) { if (err) return callback(err); - self.find(conditions).toArray(function (err, res) { + self.client.find(conditions).toArray(function (err, res) { if (err) return callback(err); - callback(null, res); + var rows = res ? res.map(function (doc) { + doc.id = doc._id.split('/').slice(1).join('/'); + delete doc._id; + return doc; + }) : []; + + callback(null, rows); }); }); }; Mongodb.prototype.filter = function (filter, callback) { + var self = this; var result = []; return this.request(function (err) { if (err) return callback(err); diff --git a/test/engines/mongodb.js b/test/engines/mongodb.js index 1e26964..8952423 100644 --- a/test/engines/mongodb.js +++ b/test/engines/mongodb.js @@ -26,10 +26,10 @@ engine.load = function (resourceful, data, callback) { if (err) return callback(err); if (result !== true) return callback(new Error('Failed to authenticate.')); - db.collection(engine.options.collection, function (err, collection) { + db.dropCollection(engine.options.collection, function (err) { if (err) return callback(err); - collection.remove(function (err) { + db.createCollection(engine.options.collection, function (err, collection) { if (err) return callback(err); collection.insert(data, {safe: true}, function (err) { From b1fe712c4b7deb5a3ebcc8fe47779a8d371589cf Mon Sep 17 00:00:00 2001 From: Christian Howe Date: Wed, 5 Sep 2012 05:47:11 -0500 Subject: [PATCH 08/10] Fixed setup bug with multiple asynchronous calls. --- lib/resourceful/engines/mongodb.js | 48 ++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/lib/resourceful/engines/mongodb.js b/lib/resourceful/engines/mongodb.js index 6d8c5ee..521af59 100644 --- a/lib/resourceful/engines/mongodb.js +++ b/lib/resourceful/engines/mongodb.js @@ -32,37 +32,53 @@ Mongodb.prototype.protocol = 'mongodb'; Mongodb.prototype.setup = function (cb) { var self = this; - var getCollection = function (callback) { + if (this.callbacks === undefined) { + this.callbacks = []; + } + + this.callbacks.push(cb); + + var callbacks = function () { + for (var i in self.callbacks) + { + self.callbacks[i].apply(this, arguments); + } + } + + var getCollection = function () { self.db.collection(self.collection, function (err, collection) { - if (err) return callback(err); + if (err) return callbacks(err); self.client = collection; - return callback(null); + return callbacks(null); }); }; - var authenticate = function (callback) { + var authenticate = function () { self.db.authenticate(self.user, self.pass, function (err, result) { if (err) { - return callback(err); + return callbacks(err); } if (result !== true) { - return callback(new Error('Failed to authenticate')); + return callbacks(new Error('Failed to authenticate')); } - return getCollection(callback); + return getCollection(); }); }; - this.db.open(function (err, p_client) { - if (err) { - return callback(err); - } - if (self.user && self.pass) { - return authenticate(cb); - } + if (!this.db.openCalled) { + this.db.open(function (err, p_client) { + if (err) { + return callbacks(err); + } - return getCollection(cb); - }); + if (self.user && self.pass) { + return authenticate(); + } + + return getCollection(); + }); + } }; Mongodb.prototype.request = function (callback) { From 83b174babdd290edec7c63a0dee3fd0c4f53c595 Mon Sep 17 00:00:00 2001 From: Christian Howe Date: Wed, 5 Sep 2012 06:34:28 -0500 Subject: [PATCH 09/10] [test] changed mongodb tests to use localhost --- lib/resourceful/engines/mongodb.js | 2 +- test/engines/mongodb.js | 24 ++++++++---------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/lib/resourceful/engines/mongodb.js b/lib/resourceful/engines/mongodb.js index 521af59..8381b78 100644 --- a/lib/resourceful/engines/mongodb.js +++ b/lib/resourceful/engines/mongodb.js @@ -18,7 +18,7 @@ var Mongodb = exports.Mongodb = function Mongodb (config) { this.user = config.auth ? config.auth.user : config.user || null; this.pass = config.auth ? config.auth.pass : config.pass || null; - this.db = new Db(config.database || resourceful.env || 'default', + this.db = new Db(config.database || resourceful.env || 'test', new Server(config.host || config.uri || '127.0.0.1', config.port || 27017)); diff --git a/test/engines/mongodb.js b/test/engines/mongodb.js index 8952423..243db0e 100644 --- a/test/engines/mongodb.js +++ b/test/engines/mongodb.js @@ -7,12 +7,10 @@ var engine = exports; engine.name = 'mongodb'; engine.options = { - host: 'alex.mongohq.com', - port: 10047, - database: 'nodejitsudb15119137141', - user: 'nodejitsu', - pass: '48be573a3772606f1e03dd765ea2a2ee', - collection: 'test' + database: 'test', + host: '127.0.0.1', + port: 27017, + collection: 'resourceful' }; engine.load = function (resourceful, data, callback) { @@ -21,22 +19,16 @@ engine.load = function (resourceful, data, callback) { db.open(function (err) { if (err) return callback(err); - - db.authenticate(engine.options.user, engine.options.pass, function (err, result) { + db.dropCollection(engine.options.collection, function (err) { if (err) return callback(err); - if (result !== true) return callback(new Error('Failed to authenticate.')); - db.dropCollection(engine.options.collection, function (err) { + db.createCollection(engine.options.collection, function (err, collection) { if (err) return callback(err); - db.createCollection(engine.options.collection, function (err, collection) { + collection.insert(data, {safe: true}, function (err) { if (err) return callback(err); - collection.insert(data, {safe: true}, function (err) { - if (err) return callback(err); - - return callback(null); - }); + return callback(null); }); }); }); From 1de2af8a98c511884d8e900b911683ffa76a98fc Mon Sep 17 00:00:00 2001 From: Christian Howe Date: Wed, 5 Sep 2012 07:01:22 -0500 Subject: [PATCH 10/10] [minor] fix travis build --- test/engines/mongodb.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/engines/mongodb.js b/test/engines/mongodb.js index 243db0e..13ac79f 100644 --- a/test/engines/mongodb.js +++ b/test/engines/mongodb.js @@ -19,8 +19,9 @@ engine.load = function (resourceful, data, callback) { db.open(function (err) { if (err) return callback(err); + db.dropCollection(engine.options.collection, function (err) { - if (err) return callback(err); + //ignore error, probably failed because it didn't exist which is fine db.createCollection(engine.options.collection, function (err, collection) { if (err) return callback(err);