loopback-datasource-juggler/lib/adapters/mongodb.js

243 lines
7.0 KiB
JavaScript

var safeRequire = require('../utils').safeRequire;
/**
* Module dependencies
*/
var mongodb = safeRequire('mongodb');
var ObjectID = mongodb.ObjectID;
exports.initialize = function initializeSchema(schema, callback) {
if (!mongodb) return;
var s = schema.settings;
if (schema.settings.rs) {
s.rs = schema.settings.rs;
if (schema.settings.url) {
var uris = schema.settings.url.split(',');
s.hosts = []
s.ports = []
uris.forEach(function(uri) {
var url = require('url').parse(uri);
s.hosts.push(url.hostname || 'localhost');
s.ports.push(parseInt(url.port || '27017', 10));
if (!s.database) s.database = url.pathname.replace(/^\//, '');
if (!s.username) s.username = url.auth && url.auth.split(':')[0];
if (!s.password) s.password = url.auth && url.auth.split(':')[1];
});
}
s.database = s.database || 'test';
} else {
if (schema.settings.url) {
var url = require('url').parse(schema.settings.url);
s.host = url.hostname;
s.port = url.port;
s.database = url.pathname.replace(/^\//, '');
s.username = url.auth && url.auth.split(':')[0];
s.password = url.auth && url.auth.split(':')[1];
}
s.host = s.host || 'localhost';
s.port = parseInt(s.port || '27017', 10);
s.database = s.database || 'test';
}
s.safe = s.safe || false;
schema.adapter = new MongoDB(s, schema, callback);
};
function MongoDB(s, schema, callback) {
var i, n;
this._models = {};
this.collections = {};
var server;
if (s.rs) {
set = [];
for (i = 0, n = s.hosts.length; i < n; i++) {
set.push(new mongodb.Server(s.hosts[i], s.ports[i], {auto_reconnect: true}));
}
server = new mongodb.ReplSetServers(set, {rs_name: s.rs});
} else {
server = new mongodb.Server(s.host, s.port, {});
}
new mongodb.Db(s.database, server, { safe: s.safe }).open(function (err, client) {
if (err) throw err;
if (s.username && s.password) {
t = this;
client.authenticate(s.username, s.password, function (err, result) {
t.client = client;
schema.client = client;
callback();
});
} else {
this.client = client;
schema.client = client;
callback();
}
}.bind(this));
}
MongoDB.prototype.define = function (descr) {
if (!descr.settings) descr.settings = {};
this._models[descr.model.modelName] = descr;
};
MongoDB.prototype.defineProperty = function (model, prop, params) {
this._models[model].properties[prop] = params;
};
MongoDB.prototype.collection = function (name) {
if (!this.collections[name]) {
this.collections[name] = new mongodb.Collection(this.client, name);
}
return this.collections[name];
};
MongoDB.prototype.create = function (model, data, callback) {
if (data.id === null) {
delete data.id;
}
this.collection(model).insert(data, {}, function (err, m) {
callback(err, err ? null : m[0]._id.toString());
});
};
MongoDB.prototype.save = function (model, data, callback) {
this.collection(model).update({_id: new ObjectID(data.id)}, data, function (err) {
callback(err);
});
};
MongoDB.prototype.exists = function (model, id, callback) {
this.collection(model).findOne({_id: new ObjectID(id)}, function (err, data) {
callback(err, !err && data);
});
};
MongoDB.prototype.find = function find(model, id, callback) {
this.collection(model).findOne({_id: new ObjectID(id)}, function (err, data) {
if (data) data.id = id;
callback(err, data);
});
};
MongoDB.prototype.updateOrCreate = function updateOrCreate(model, data, callback) {
var adapter = this;
if (!data.id) return this.create(data, callback);
this.find(model, data.id, function (err, inst) {
if (err) return callback(err);
if (inst) {
adapter.updateAttributes(model, data.id, data, callback);
} else {
delete data.id;
adapter.create(model, data, function (err, id) {
if (err) return callback(err);
if (id) {
data.id = id;
delete data._id;
callback(null, data);
} else{
callback(null, null); // wtf?
}
});
}
});
};
MongoDB.prototype.destroy = function destroy(model, id, callback) {
this.collection(model).remove({_id: new ObjectID(id)}, callback);
};
MongoDB.prototype.all = function all(model, filter, callback) {
if (!filter) {
filter = {};
}
var query = {};
if (filter.where) {
Object.keys(filter.where).forEach(function (k) {
var cond = filter.where[k];
var spec = false;
if (cond && cond.constructor.name === 'Object') {
spec = Object.keys(cond)[0];
cond = cond[spec];
}
if (spec) {
if (spec === 'between') {
query[k] = { $gte: cond[0], $lte: cond[1]};
} else {
query[k] = {};
query[k]['$' + spec] = cond;
}
} else {
if (cond === null) {
query[k] = {$type: 10};
} else {
query[k] = cond;
}
}
});
}
var cursor = this.collection(model).find(query);
if (filter.order) {
var m = filter.order.match(/\s+(A|DE)SC$/);
var key = filter.order;
var reverse = false;
if (m) {
key = key.replace(/\s+(A|DE)SC$/, '');
if (m[1] === 'DE') reverse = true;
}
if (reverse) {
cursor.sort([[key, 'desc']]);
} else {
cursor.sort(key);
}
}
if (filter.limit) {
cursor.limit(filter.limit);
}
if (filter.skip) {
cursor.skip(filter.skip);
} else if (filter.offset) {
cursor.skip(filter.offset);
}
cursor.toArray(function (err, data) {
if (err) return callback(err);
callback(null, data.map(function (o) { o.id = o._id.toString(); delete o._id; return o; }));
});
};
MongoDB.prototype.destroyAll = function destroyAll(model, callback) {
this.collection(model).remove({}, callback);
};
MongoDB.prototype.count = function count(model, callback, where) {
this.collection(model).count(where, function (err, count) {
callback(err, count);
});
};
MongoDB.prototype.updateAttributes = function updateAttrs(model, id, data, cb) {
this.collection(model).findAndModify({_id: new ObjectID(id)}, [['_id','asc']], {$set: data}, {}, function(err, object) {
cb(err, object);
});
};
MongoDB.prototype.disconnect = function () {
this.client.close();
};