Skip to content

Instantly share code, notes, and snippets.

@simenbrekken
Created November 16, 2011 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simenbrekken/1370266 to your computer and use it in GitHub Desktop.
Save simenbrekken/1370266 to your computer and use it in GitHub Desktop.
MongoDB Native Wrapper
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