Skip to content

Commit

Permalink
Rewritten to use a url parameter for a conn string
Browse files Browse the repository at this point in the history
URLs are pretty standard practice for most of the
cloud hosting providers out there that offer
mongo hosting, so we should keep parity.

Unfortunately, most of the driver had to be rewritten
to account for the differences in the MongoClient
driver that works with urls.
  • Loading branch information
tedkulp committed Mar 14, 2013
1 parent bf5c860 commit 222ec79
Showing 1 changed file with 145 additions and 126 deletions.
271 changes: 145 additions & 126 deletions MongoAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,173 +5,192 @@

var async = require('async')
, _ = require('underscore')
, _str = require('underscore.string');
, mongodb = require('mongodb')
, mongoClient = mongodb.MongoClient
, objectId = mongodb.ObjectID;

var mongo = require('mongodb')
, Db = mongo.Db
, Server = mongo.Server
, Connection = mongo.Connection
, db = null;
module.exports = (function() {

module.exports = (function(){
// Keep track of all the dbs used by the app
var dbs = {};

var adapter = {

syncable: false,

registerCollection: function(collection, cb) {
//Connect to MongoDB
connect(collection, cb);
var self = this;

// If the configuration in this collection corresponds
// with a known database, reuse it the connection(s) to that db
dbs[collection.identity] = _.find(dbs, function(db) {
return collection.url === db.url;
});

// Otherwise initialize for the first time
if (!dbs[collection.identity]) {
dbs[collection.identity] = marshalConfig(collection);
}

return cb();
},

drop: function(collectionName, cb) {
//Open the connection
db.open(function connectionOpened(err, client){
if (err) return cb(err);
teardown: function(cb) {
cb && cb();
},

// Run query
db.collection(collectionName, function collectionSelected(err, collection){
if (err) return cb(err);
describe: function(collectionName, cb) {
//It's mongo -- there's nothing to describe
return cb(null, {});
},

//Drop the collection
collection.drop(function dropCompleted(err, res){
if (err) return cb(err);
define: function(collectionName, definition, cb) {
spawnConnection(function __DEFINE__(connection, cb) {
connection.createCollection(collectionName, function __DEFINE__(err, result) {
if (err) return cb(err);
cb(null, result);
});
}, dbs[collectionName], cb);
},

//Close the connection
db.close();
cb(err,res);
});
drop: function(collectionName, cb) {
spawnConnection(function __DROP__(connection, cb) {
connection.dropCollection(collectionName, function __DEFINE__(err, result) {
if (err) return cb(err);
cb(null, result);
});
});
}, dbs[collectionName], cb);
},

create: function(collectionName, data, cb) {
//Open the connection
db.open(function connectionOpened(err, client){
if (err) return cb(err);

// Run query
db.collection(collectionName, function collectionSelected(err, collection){
spawnConnection(function(connection, cb) {
var collection = connection.collection(collectionName);
collection.insert(data, function(err, result) {
if (err) return cb(err);

//Count the docs
collection.find({}, function (err, cursor){
if (err) return cb(err);
// Build model to return
var model = _.extend({}, data, {

//Create an array of the result
cursor.toArray(function(err, items){
if (err) return cb(err);

// Set the 'id'
data.id = items.length + 1;
// TODO: look up the autoIncrement attribute and increment that instead of assuming `id`
id: result[0]._id
});

// Run query
collection.insert(data, function insertCompleted(err, res){
if (err) return cb(err);
if (model._id)
delete model._id;

//Close the connection
db.close();
cb(err, data);
});
});
});
cb(err, model);
});
});
}, dbs[collectionName], cb);
},

find: function(collectionName, options, cb) {
//Open the connection
db.open(function connectionOpened(err, client){
if (err) return cb(err);

//Select the collection
db.collection(collectionName, function collectionSelected(err, collection){
if (err) return cb(err);

//Find matching documents
collection.find(options.where, function(err, cursor){
if (err) return cb(err);

//Create an array of the result
cursor.toArray(function (err, res){
if (err) return cb(err);

//Close the connection
db.close();
cb(err,res);
});
});
spawnConnection(function(connection, cb) {
var collection = connection.collection(collectionName);
options = rewriteCriteria(options);
collection.find.apply(collection, parseFindOptions(options)).toArray(function(err, docs) {
cb(err, rewriteIds(docs));
});
});
}, dbs[collectionName], cb);
},

update: function(collectionName, options, values, cb) {
//Open the connection
db.open(function connectionOpened(err, client){
if (err) return cb(err);

//Select the collection
db.collection(collectionName, function collectionSelected(err, collection){
if (err) return cb(err);

//Create query
var query = { '$set': values };

//Update matching documents
collection.update(options.where, query, function(err, res){
if (err) return cb(err);

//Find documents matching the results
collection.find(options.where, function(err, cursor){
if (err) return cb(err);

//Create an array of the result
cursor.toArray(function (err, res){
if (err) return cb(err);

//Close the connection
db.close();
cb(err,res);
});
var that = this;

spawnConnection(function(connection, cb) {
options = rewriteCriteria(options);
var collection = connection.collection(collectionName);
collection.update(options.where, { $set: values }, { multi: true }, function(err, result) {
if (!err) {
that.find(collectionName, options, function(err, docs) {
cb(err, docs);
});
});
} else {
cb(err, result);
}
});
});
}, dbs[collectionName], cb);
},

destroy: function(collectionName, options, cb) {
//Open the connection
db.open(function connectionOpened(err, client){
if (err) return cb(err);

//Select the collection
db.collection(collectionName, function collectionSelected(err, collection){
if (err) return cb(err);

//Remove matching documents
collection.remove(options.where, function(err, res){
if (err) return cb(err);

//Close the connection
db.close();
cb(err,res);
});
spawnConnection(function(connection, cb) {
options = rewriteCriteria(options);
var collection = connection.collection(collectionName);
collection.remove(options.where, function(err, result) {
cb(err, result);
});
});
}, dbs[collectionName], cb);
},

identity: 'sails-mongo'
};

function spawnConnection(logic, config, cb) {
mongoClient.connect(config.url, function(err, db) {
afterwards(err, db);
});

function afterwards(err, db) {
if (err) return cb(err);
logic(db, function(err, result) {
db.close();
cb && cb(err, result);
});
}
};

////////////// //////////////////////////////////////////
////////////// Private Methods //////////////////////////////////////////
////////////// //////////////////////////////////////////
function connect (collection, cb) {
db = new Db(collection.database, new Server(collection.host, collection.port || 27017, {}), {w: 1});
return cb();
// Convert standard adapter config
// into a custom configuration object

function marshalConfig(config) {
return _.extend(config, {
url : config.url
});
}

return adapter;
function parseFindOptions(options) {
return [options.where, _.omit(options, 'where')];
}

})();
function rewriteCriteria(options) {
if (options.where) {
if (options.where.id && !options.where._id) {
options.where._id = options.where.id;
delete options.where.id;
}
if (options.where._id && _.isString(options.where._id)) {
options.where._id = new objectId(options.where._id);
}

options.where = parseTypes(options.where);
}
return options;
}

function parseTypes(obj) {
// Rewrite false and true if they come through. Not sure if there
// is a better way to do this or not.
_.each(obj, function(val, key) {
if (val === "false")
obj[key] = false;
else if (val === "true")
obj[key] = true;
else if (!_.isNaN(Date.parse(val)))
obj[key] = new Date(val);
else if (_.isObject(val))
obj[key] = parseTypes(val); // Nested objects...
});

return obj;
}

function rewriteIds(models) {
return _.map(models, function(model) {
if (model._id) {
model.id = model._id;
delete model._id;
}
return model;
});
}

return adapter;
})();

0 comments on commit 222ec79

Please sign in to comment.