Skip to content

Instantly share code, notes, and snippets.

@kirbysayshi
Created September 12, 2011 19:36
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save kirbysayshi/1212171 to your computer and use it in GitHub Desktop.
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
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();
}
}
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');
});
}
};
@wmertens
Copy link

Nice! Why not make it into a module?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment