Created
September 12, 2011 19:36
-
-
Save kirbysayshi/1212171 to your computer and use it in GitHub Desktop.
example showing how to wrap node-mongodb-native driver in promises. uses jquery deferreds from https://github.com/kirbysayshi/jquery-jqd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var mongo = require('mongodb') | |
,jqd = require('../jquery-jqd').jqd | |
,host = process.env['MONGO_NODE_DRIVER_HOST'] != null | |
? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost' | |
,port = process.env['MONGO_NODE_DRIVER_PORT'] != null | |
? process.env['MONGO_NODE_DRIVER_PORT'] : mongo.Connection.DEFAULT_PORT | |
,db = null | |
,gConnection = null; | |
/* | |
args can be: | |
1) string: 'database name', [mongo.Server] // name of db, optional server, defaults to default port, localhost, autoreconnect | |
2) deferred: con // a deferred obj with a 'this' of the db connection | |
3) none: // assumed that a connection already exists | |
*/ | |
exports.mdb = function mdb(args){ | |
switch(arguments.length){ | |
case 1: | |
if(typeof arguments[0] === 'string'){ | |
// check for connection, create default server otherwise | |
if(db === null){ | |
db = new mongo.Db(arguments[0], | |
new mongo.Server(host, port, { | |
auto_reconnect: true | |
}), { native_parser: true }); | |
gConnection = exports.mdb.connect(); | |
} | |
} else if (typeof arguments[0].promise !== 'undefined'){ | |
// we have a promise, assume a connection | |
gConnection = arguments[0]; | |
} | |
break; | |
case 2: | |
// assume first param is string, second is mongo.Server instance | |
db = new mongo.Db(arguments[0], arguments[1]); | |
gConnection = exports.mdb.connect(); | |
break; | |
default: | |
// zero params, assume we have a deferred connection somewhere | |
if(!gConnection) throw new Error('There is no MongoDb connection to use.'); | |
break; | |
} | |
var con = gConnection; | |
return { | |
connection: con | |
,collection: function(name){ | |
var colDfd = jqd.deferred() | |
,p = colDfd.promise(); | |
// make sure we have a connection, which we should regardless | |
con.then(function(){ | |
this.collection(name, function(err, col){ | |
if(err){ | |
colDfd.reject(); | |
} else { | |
colDfd.resolveWith(col, [col]); | |
} | |
}); | |
}); | |
return { | |
collection: p // the collection's promise | |
,get: function(callback){ | |
return p.then(callback); | |
} | |
,find: function(query){ | |
var dfd = jqd.deferred(); | |
p.then(function(){ | |
this.find(query, function(err, result){ | |
if(err){ | |
dfd.reject(); | |
} else { | |
result.toArray(function(err, docs){ | |
if(err) dfd.reject(); | |
else dfd.resolveWith(docs, [docs]); | |
}); | |
} | |
}); | |
}); | |
return dfd.promise(); | |
} | |
,findOne: function(query){ | |
var dfd = jqd.deferred(); | |
p.then(function(){ | |
this.findOne(query, function(err, doc){ | |
if(err){ | |
dfd.reject(); | |
} else { | |
dfd.resolveWith(doc, [doc]); | |
} | |
}); | |
}); | |
return dfd.promise(); | |
} | |
,findOneOrDie: function(query){ | |
var dfd = jqd.deferred(); | |
p.then(function(){ | |
this.findOne(query, function(err, doc){ | |
if(err || !doc){ | |
dfd.reject(); | |
} else { | |
dfd.resolveWith(doc, [doc]); | |
} | |
}); | |
}); | |
return dfd.promise(); | |
} | |
,insert: function(docs){ | |
var dfd = jqd.deferred(); | |
p.then(function(){ | |
this.insert(docs, function(err, docs){ | |
if(err){ | |
dfd.reject(err); | |
} else { | |
dfd.resolveWith(docs, [err, docs]); | |
} | |
}); | |
}); | |
return dfd.promise(); | |
} | |
,findAndModify: function(options){ | |
var dfd = jqd.deferred(); | |
p.then(function(){ | |
this.findAndModify( | |
options.query | |
,options.sort || [] | |
,options.update | |
,options.options | |
,function(err, result){ | |
if(err) { | |
dfd.rejectWith(err, [err, result]); | |
} else { | |
dfd.resolveWith(result, [err, result]); | |
} | |
}); | |
}); | |
return dfd.promise(); | |
} | |
} | |
} | |
} | |
} | |
exports.mdb.connect = function connect(){ | |
return jqd.deferred(function(dfd){ | |
db.open(function(err, client){ | |
if(err){ | |
dfd.reject(err); | |
} else { | |
dfd.resolveWith(client, [client]); | |
} | |
}); | |
}).promise(); | |
} | |
// attach mongo lib to expo | |
exports.mdb.mongo = mongo; | |
exports.express = function express(args){ | |
// start the connection | |
var m = exports.mdb(args); | |
exports.mdb.BSON = db.options.native_parser ? mongo.BSONNative : mongo.BSONPure; | |
return function(req, res, next){ | |
if(!req.mdb) req.mdb = exports.mdb; | |
next(); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var mdb = require('./mdb').mdb | |
,assert = require('assert'); | |
module.exports = { | |
'connect': function(){ | |
//debugger; | |
mdb('mdbtest').connection.done(function(){ | |
assert.isNotNull(this); | |
assert.equal(this.state, 'connected', 'is connected?'); | |
}); | |
mdb().connection.done(function(){ | |
assert.length(this.connections, 1, 'only one connection is created'); | |
}); | |
} | |
,'insert': function(){ | |
mdb() | |
.collection('testcollection') | |
.insert([{ name: 'i am the law', value: 'like a boss' }]) | |
.done(function(){ | |
// 'this' is the document(s) inserted | |
assert.length(this, 1, 'one document inserted'); | |
assert.isDefined(this[0]._id, 'document has an _id'); | |
}); | |
mdb() | |
.collection('testcollection') | |
.insert([ | |
{ name: 'i am the law', value: 'like a boss' } | |
,{ name: 'i am the law', value: 'like a boss' } | |
]) | |
.done(function(){ | |
// 'this' is the document(s) inserted | |
assert.length(this, 2, 'two documents inserted'); | |
this.forEach(function(e, i){ | |
assert.isDefined(e._id, 'new document ' + i + ' has an _id'); | |
}); | |
}); | |
} | |
,'find': function(){ | |
mdb() | |
.collection('testcollection') | |
.find({}) | |
.done(function(){ | |
// this is already toArray(ed) | |
console.log('find', this); | |
assert.length(this, 3, 'total of three documents found'); | |
}); | |
} | |
,'findInsertChained': function(){ | |
// TODO: this test doesn't actually test anything | |
var p_col = mdb().collection('testcollection') | |
p_col.find({}).done(function(){ | |
assert.notEqual(this.length, 0, 'more than one doc returned'); | |
//console.log('1) found something', this[0]._id); | |
}); | |
//console.log("OBJECT ID", mdb.mongo.BSONNative.ObjectID); | |
p_col.insert([{ | |
_id: new mdb.mongo.BSONNative.ObjectID() | |
,name: 'The Doctor' | |
,value: 'who?' | |
}]).done(function(){ | |
//console.log('2) insert something', this[0]._id); | |
assert.length(this, 1, 'one document returned from insert') | |
}); | |
p_col.find({}).done(function(){ | |
//console.log('3) found something', this[0]._id); | |
assert.notEqual(this.length, 0, 'more than one doc returned'); | |
}); | |
} | |
,'findAndModify': function(){ | |
var p_collection = mdb().collection('testseqcollection'); | |
p_collection.insert({ _id: 'testseq', seq: 0 }).done(function(){ | |
p_collection | |
.findAndModify({ | |
//upsert: true | |
query: { _id: 'testseq' } | |
,update: { $inc: { seq: 1 } } | |
,options: { | |
'new': true | |
} | |
}) | |
.done(function(){ | |
console.log('increment 1 result: ', this); | |
assert.equal(this.seq, 1, 'new sequence should be one'); | |
}); | |
p_collection | |
.findAndModify({ | |
//upsert: true | |
query: { _id: 'testseq' } | |
,update: { $inc: { seq: 1 } } | |
,options: { | |
'new': true | |
} | |
}) | |
.done(function(){ | |
console.log('increment 2 result: ', this); | |
// should return the value on success | |
assert.equal(this.seq, 2, 'new sequence should be two'); | |
}); | |
}); | |
} | |
,'findAndModifyUpsert': function(){ | |
mdb() | |
.collection('sequences') | |
.findAndModify({ | |
update: { $inc: { seq: 1 } } | |
,query: { _id: 'testseq' } | |
,sort: [] | |
,options: { | |
upsert: true | |
,"new": true | |
} | |
}) | |
.done(function(){ | |
console.log('sequence increment', this, arguments); | |
assert.equal(this.seq, 1, 'initial sequence should be one') | |
}); | |
} | |
,'reset': function(){ | |
mdb().connection.done(function(){ | |
this.dropDatabase(function(err, result){ | |
assert.equal(err, null, 'no errors on dropping database'); | |
assert.equal(result.documents[0].ok, 1, 'drop succeeded?'); | |
}); | |
}); | |
mdb().connection.done(function(){ | |
assert.length(this.connections, 1, 'only one connection is created'); | |
}); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice! Why not make it into a module?