Created
November 16, 2011 15:03
-
-
Save simenbrekken/1370266 to your computer and use it in GitHub Desktop.
MongoDB Native Wrapper
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 mongodb = require('mongodb'), | |
events = require('events'), | |
util = require('util'); | |
var Deferrer = function(emitter, timeoutDelay) { | |
var self = this; | |
var pending = 0; | |
var total = 0; | |
var timeout; | |
var complete = function() { | |
self.emit('complete'); | |
}; | |
emitter.on('defer', function() { | |
pending++; | |
total++; | |
console.log('Pending:', pending, 'Total:', total); | |
if (timeout) clearTimeout(timeout); | |
}); | |
emitter.on('deferComplete', function() { | |
if (!--pending) { | |
if (timeoutDelay) { | |
timeout = setTimeout(complete, timeoutDelay); | |
} else { | |
complete(); | |
} | |
} | |
}); | |
}; | |
util.inherits(Deferrer, events.EventEmitter); | |
var Database = exports.Database = function(name, host, port, databaseOptions, serverOptions) { | |
var self = this; | |
var server = new mongodb.Server(host || 'localhost', port || 27017, serverOptions); // TODO; Support replicasets etc. | |
this.db = new mongodb.Db(name, server, databaseOptions); | |
var autoCloser = new Deferrer(this); | |
autoCloser.on('complete', function() { | |
self.close(); | |
}); | |
}; | |
util.inherits(Database, events.EventEmitter); | |
Database.prototype.defer = function(callback) { | |
var self = this; | |
var opening = this.listeners('open').length > 0; | |
var opened = function(err, db) { | |
callback(err, db); | |
self.emit('deferComplete'); | |
}; | |
this.emit('defer'); | |
if (this.db.state == 'notConnected') { | |
this.once('open', opened); | |
if (!opening) this.open(); | |
} else { | |
opened(null, this.db); | |
} | |
}; | |
Database.prototype.open = function(callback) { | |
var self = this; | |
this.db.open(function(err, db) { | |
self.emit('open', err, db); | |
}); | |
}; | |
Database.prototype.close = function(callback) { | |
this.db.close(callback); | |
}; | |
Database.prototype.collection = function(name) { | |
var self = this; | |
var collection = this[name]; | |
if (!collection) { | |
var temp = 0; | |
collection = this[name] = new Collection(this, name); | |
collection.on('defer', function() { | |
self.db.emit('defer'); | |
}); | |
collection.on('deferComplete', function() { | |
self.db.emit('deferComplete'); | |
}); | |
} | |
return collection; | |
}; | |
var Collection = exports.Collection = function(db, name) { | |
this.db = db; | |
this.name = name; | |
}; | |
util.inherits(Collection, events.EventEmitter); | |
Collection.prototype.defer = function(callback) { | |
var self = this; | |
this.emit('defer'); | |
this.db.defer(function(err, db) { | |
if (err) return callback(err); | |
db.collection(self.name, function(err, collection) { | |
callback(err, collection); | |
self.emit('deferComplete'); | |
}); | |
}); | |
}; | |
Collection.prototype.find = function(query, fields, options) { | |
var self = this; | |
var cursor = new Cursor(function(callback) { | |
self.defer(function(err, collection) { | |
if (err) return callback(err); | |
collection.find(query || {}, fields || {}, callback); | |
}); | |
}); | |
cursor.on('defer', function() { | |
self.db.emit('defer'); | |
}); | |
cursor.on('deferComplete', function() { | |
self.db.emit('deferComplete'); | |
}); | |
return cursor; | |
}; | |
Collection.prototype.insert = function(docs, options, callback) { | |
if (typeof options == 'function') { | |
callback = options; | |
options = null; | |
} | |
this.defer(function(err, collection) { | |
collection.insert(docs, options, callback); | |
}); | |
}; | |
Collection.prototype.update = function(query, updates, options, callback) { | |
if (typeof options == 'function') { | |
callback = options; | |
options = null; | |
} | |
this.defer(function(err, collection) { | |
collection.update(query, updates, options, callback); | |
}); | |
}; | |
Collection.prototype.drop = function(callback) { | |
this.defer(function(err, collection) { | |
collection.drop(callback); | |
}); | |
}; | |
var Cursor = function(cursor) { | |
this.cursor = cursor; | |
this.options = {}; | |
}; | |
util.inherits(Cursor, events.EventEmitter); | |
// TODO: Consolidate | |
Cursor.prototype.limit = function(limit) { | |
this.options.limit = limit; | |
return this; | |
}; | |
Cursor.prototype.skip = function(skip) { | |
this.options.skip = skip; | |
return this; | |
}; | |
Cursor.prototype.sort = function(order) { | |
this.options.sort = order; | |
return this; | |
}; | |
Cursor.prototype.defer = function(callback) { | |
var self = this; | |
this.emit('defer'); | |
this.cursor(function(err, cursor) { | |
if (err) return callback(err); | |
for (var option in self.options) { | |
cursor[option](self.options[option]); | |
} | |
self.emit('deferComplete'); | |
return callback(null, cursor); | |
}); | |
return this; | |
}; | |
Cursor.prototype.next = function(callback) { | |
var self = this; | |
this.emit('defer'); | |
return this.defer(function(err, cursor) { | |
if (err) return callback(err); | |
self.options.skip = (self.options.skip + 1) || 0; | |
cursor.skip(self.options.skip); | |
return cursor.nextObject(function(err, obj) { | |
callback(err, obj); | |
self.emit('deferComplete'); | |
}); | |
}); | |
}; | |
Cursor.prototype.toArray = function(callback) { | |
var self = this; | |
this.emit('defer'); | |
return this.defer(function(err, cursor) { | |
if (err) return callback(err); | |
return cursor.toArray(function(err, docs) { | |
self.emit('deferComplete'); | |
callback(err, docs); | |
}); | |
}); | |
}; | |
Cursor.prototype.count = function(callback) { | |
return this.defer(function(err, cursor) { | |
if (err) return callback(err); | |
return cursor.count(callback); | |
}); | |
}; | |
Cursor.prototype.explain = function(callback) { | |
return this.defer(function(err, cursor) { | |
if (err) return callback(err); | |
return cursor.explain(callback); | |
}); | |
}; | |
exports.db = function(name, host, port, databaseOptions, serverOptions) { | |
return new Database(name, host, port, databaseOptions, serverOptions); | |
}; | |
var db = exports.db('test'); | |
db.collection('foo'); | |
db.foo.drop(); | |
db.foo.insert({'foo': 'bar'}, function(err, docs) { | |
console.log('find #1', docs); | |
}); | |
db.foo.insert({'foo': 'bar2'}, {safe: true}, function(err, docs) { | |
console.log('find #2:', docs); | |
}); | |
db.foo.update({ foo: 'bar2' }, { foo: 'baz!' }, { safe: true }, function(err, result) { | |
console.log('update #2:', result); | |
db.foo.find({foo: 'baz!'}).count(function(err, count) { | |
console.log('count update #2:', err, count); | |
}); | |
}); | |
db.foo.insert({'foo': 'bar3'}, function(err, docs) { | |
console.log('find #3:', docs); | |
db.foo.insert({'foo': 'bar4'}, function(err, docs) { | |
console.log('find #3.1:', docs); | |
db.foo.find({'foo': 'bar'}).limit(5).skip(2).toArray(function(err, docs) { | |
console.log('toArray', err, docs); | |
}); | |
db.foo.find().limit(5).next(function(err, doc) { | |
console.log('next #1:', err, doc); | |
}).next(function(err, doc) { | |
console.log('next #2:', err, doc); | |
}).next(function(err, doc) { | |
console.log('next #3:', err, doc); | |
}); | |
db.foo.find({'foo': 'bar'}).limit(5).count(function(err, count) { | |
console.log('count:', err, count); | |
}); | |
db.foo.find({'foo': 'bar'}).limit(5).explain(function(err, explenation) { | |
console.log('explain:', err, explenation); | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment