Merge branch 'feature/remove-unsupported-connectors' into 2.0
Close #120
This commit is contained in:
commit
42a7ed5d20
|
@ -1,343 +0,0 @@
|
||||||
var safeRequire = require('../utils').safeRequire;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
var cradle = safeRequire('cradle');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private functions for internal use
|
|
||||||
*/
|
|
||||||
function CradleAdapter(client) {
|
|
||||||
this._models = {};
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createdbif(client, callback) {
|
|
||||||
client.exists(function (err, exists) {
|
|
||||||
if (err) callback(err);
|
|
||||||
if (!exists) {
|
|
||||||
client.create(function () {
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function naturalize(data, model) {
|
|
||||||
data.nature = model;
|
|
||||||
//TODO: maybe this is not a really good idea
|
|
||||||
if (data.date) data.date = data.date.toString();
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
function idealize(data) {
|
|
||||||
data.id = data._id;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
function stringify(data) {
|
|
||||||
return data ? data.toString() : data
|
|
||||||
}
|
|
||||||
|
|
||||||
function errorHandler(callback, func) {
|
|
||||||
return function (err, res) {
|
|
||||||
if (err) {
|
|
||||||
console.log('cradle', err);
|
|
||||||
callback(err);
|
|
||||||
} else {
|
|
||||||
if (func) {
|
|
||||||
func(res, function (res) {
|
|
||||||
callback(null, res);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
callback(null, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function synchronize(functions, args, callback) {
|
|
||||||
if (functions.length === 0) callback();
|
|
||||||
if (functions.length > 0 && args.length === functions.length) {
|
|
||||||
functions[0](args[0][0], args[0][1], function (err, res) {
|
|
||||||
if (err) callback(err);
|
|
||||||
functions.splice(0, 1);
|
|
||||||
args.splice(0, 1);
|
|
||||||
synchronize(functions, args, callback);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function applyFilter(filter) {
|
|
||||||
if (typeof filter.where === 'function') {
|
|
||||||
return filter.where;
|
|
||||||
}
|
|
||||||
var keys = Object.keys(filter.where);
|
|
||||||
return function (obj) {
|
|
||||||
var pass = true;
|
|
||||||
keys.forEach(function (key) {
|
|
||||||
if (!test(filter.where[key], obj[key])) {
|
|
||||||
pass = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
function test(example, value) {
|
|
||||||
if (typeof value === 'string' && example && example.constructor.name === 'RegExp') {
|
|
||||||
return value.match(example);
|
|
||||||
}
|
|
||||||
// not strict equality
|
|
||||||
return example == value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function numerically(a, b) {
|
|
||||||
return a[this[0]] - b[this[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
function literally(a, b) {
|
|
||||||
return a[this[0]] > b[this[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
function filtering(res, model, filter, instance) {
|
|
||||||
|
|
||||||
if (model) {
|
|
||||||
if (filter == null) filter = {};
|
|
||||||
if (filter.where == null) filter.where = {};
|
|
||||||
filter.where.nature = model;
|
|
||||||
}
|
|
||||||
// do we need some filtration?
|
|
||||||
if (filter.where) {
|
|
||||||
res = res ? res.filter(applyFilter(filter)) : res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// do we need some sorting?
|
|
||||||
if (filter.order) {
|
|
||||||
var props = instance[model].properties;
|
|
||||||
var allNumeric = true;
|
|
||||||
var orders = filter.order;
|
|
||||||
var reverse = false;
|
|
||||||
if (typeof filter.order === "string") {
|
|
||||||
orders = [filter.order];
|
|
||||||
}
|
|
||||||
|
|
||||||
orders.forEach(function (key, i) {
|
|
||||||
var m = key.match(/\s+(A|DE)SC$/i);
|
|
||||||
if (m) {
|
|
||||||
key = key.replace(/\s+(A|DE)SC/i, '');
|
|
||||||
if (m[1] === 'DE') reverse = true;
|
|
||||||
}
|
|
||||||
orders[i] = key;
|
|
||||||
if (props[key].type.name !== 'Number') {
|
|
||||||
allNumeric = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (allNumeric) {
|
|
||||||
res = res.sort(numerically.bind(orders));
|
|
||||||
} else {
|
|
||||||
res = res.sort(literally.bind(orders));
|
|
||||||
}
|
|
||||||
if (reverse) res = res.reverse();
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection/Disconnection
|
|
||||||
*/
|
|
||||||
exports.initialize = function (dataSource, callback) {
|
|
||||||
if (!cradle) return;
|
|
||||||
|
|
||||||
// when using cradle if we dont wait for the dataSource to be connected, the models fails to load correctly.
|
|
||||||
dataSource.waitForConnect = true;
|
|
||||||
if (!dataSource.settings.url) {
|
|
||||||
var host = dataSource.settings.host || 'localhost';
|
|
||||||
var port = dataSource.settings.port || '5984';
|
|
||||||
var options = dataSource.settings.options || {
|
|
||||||
cache: true,
|
|
||||||
raw: false
|
|
||||||
};
|
|
||||||
if (dataSource.settings.username) {
|
|
||||||
options.auth = {};
|
|
||||||
options.auth.username = dataSource.settings.username;
|
|
||||||
if (dataSource.settings.password) {
|
|
||||||
options.auth.password = dataSource.settings.password;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var database = dataSource.settings.database || 'loopback-datasource-juggler';
|
|
||||||
|
|
||||||
dataSource.settings.host = host;
|
|
||||||
dataSource.settings.port = port;
|
|
||||||
dataSource.settings.database = database;
|
|
||||||
dataSource.settings.options = options;
|
|
||||||
}
|
|
||||||
dataSource.client = new (cradle.Connection)(dataSource.settings.host, dataSource.settings.port, dataSource.settings.options).database(dataSource.settings.database);
|
|
||||||
|
|
||||||
createdbif(
|
|
||||||
dataSource.client,
|
|
||||||
errorHandler(callback, function () {
|
|
||||||
dataSource.connector = new CradleAdapter(dataSource.client);
|
|
||||||
process.nextTick(callback);
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
CradleAdapter.prototype.disconnect = function () {
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write methods
|
|
||||||
*/
|
|
||||||
CradleAdapter.prototype.define = function (descr) {
|
|
||||||
this._models[descr.model.modelName] = descr;
|
|
||||||
};
|
|
||||||
|
|
||||||
CradleAdapter.prototype.create = function (model, data, callback) {
|
|
||||||
this.client.save(
|
|
||||||
stringify(data.id),
|
|
||||||
naturalize(data, model),
|
|
||||||
errorHandler(callback, function (res, cb) {
|
|
||||||
cb(res.id);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CradleAdapter.prototype.save = function (model, data, callback) {
|
|
||||||
this.client.save(
|
|
||||||
stringify(data.id),
|
|
||||||
naturalize(data, model),
|
|
||||||
errorHandler(callback)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
CradleAdapter.prototype.updateAttributes = function (model, id, data, callback) {
|
|
||||||
this.client.merge(
|
|
||||||
stringify(id),
|
|
||||||
data,
|
|
||||||
errorHandler(callback, function (doc, cb) {
|
|
||||||
cb(idealize(doc));
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CradleAdapter.prototype.updateOrCreate = function (model, data, callback) {
|
|
||||||
this.client.get(
|
|
||||||
stringify(data.id),
|
|
||||||
function (err, doc) {
|
|
||||||
if (err) {
|
|
||||||
this.create(model, data, callback);
|
|
||||||
} else {
|
|
||||||
this.updateAttributes(model, data.id, data, callback);
|
|
||||||
}
|
|
||||||
}.bind(this)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read methods
|
|
||||||
*/
|
|
||||||
CradleAdapter.prototype.exists = function (model, id, callback) {
|
|
||||||
this.client.get(
|
|
||||||
stringify(id),
|
|
||||||
errorHandler(callback, function (doc, cb) {
|
|
||||||
cb(!!doc);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CradleAdapter.prototype.find = function (model, id, callback) {
|
|
||||||
this.client.get(
|
|
||||||
stringify(id),
|
|
||||||
errorHandler(callback, function (doc, cb) {
|
|
||||||
cb(idealize(doc));
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CradleAdapter.prototype.count = function (model, callback, where) {
|
|
||||||
this.models(
|
|
||||||
model,
|
|
||||||
{where: where},
|
|
||||||
callback,
|
|
||||||
function (docs, cb) {
|
|
||||||
cb(docs.length);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CradleAdapter.prototype.models = function (model, filter, callback, func) {
|
|
||||||
var limit = 200;
|
|
||||||
var skip = 0;
|
|
||||||
if (filter != null) {
|
|
||||||
limit = filter.limit || limit;
|
|
||||||
skip = filter.skip || skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.client.save('_design/' + model, {
|
|
||||||
views: {
|
|
||||||
all: {
|
|
||||||
map: 'function(doc) { if (doc.nature == "' + model + '") { emit(doc._id, doc); } }'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, function () {
|
|
||||||
self.client.view(model + '/all', {include_docs: true, limit: limit, skip: skip},
|
|
||||||
errorHandler(callback, function (res, cb) {
|
|
||||||
var docs = res.map(function (doc) {
|
|
||||||
return idealize(doc);
|
|
||||||
});
|
|
||||||
var filtered = filtering(docs, model, filter, this._models)
|
|
||||||
|
|
||||||
func ? func(filtered, cb) : cb(filtered);
|
|
||||||
}.bind(self)));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
CradleAdapter.prototype.all = function (model, filter, callback) {
|
|
||||||
this.models(
|
|
||||||
model,
|
|
||||||
filter,
|
|
||||||
callback
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detroy methods
|
|
||||||
*/
|
|
||||||
CradleAdapter.prototype.destroy = function (model, id, callback) {
|
|
||||||
this.client.remove(
|
|
||||||
stringify(id),
|
|
||||||
function (err, doc) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CradleAdapter.prototype.destroyAll = function (model, callback) {
|
|
||||||
this.models(
|
|
||||||
model,
|
|
||||||
null,
|
|
||||||
callback,
|
|
||||||
function (docs, cb) {
|
|
||||||
var docIds = docs.map(function (doc) {
|
|
||||||
return doc.id;
|
|
||||||
});
|
|
||||||
this.client.get(docIds, function (err, res) {
|
|
||||||
if (err) cb(err);
|
|
||||||
|
|
||||||
var funcs = res.map(function (doc) {
|
|
||||||
return this.client.remove.bind(this.client);
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
var args = res.map(function (doc) {
|
|
||||||
return [doc._id, doc._rev];
|
|
||||||
});
|
|
||||||
|
|
||||||
synchronize(funcs, args, cb);
|
|
||||||
}.bind(this));
|
|
||||||
}.bind(this)
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,190 +0,0 @@
|
||||||
exports.initialize = function initializeSchema(dataSource, callback) {
|
|
||||||
dataSource.connector = new WebService();
|
|
||||||
process.nextTick(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
function WebService() {
|
|
||||||
this._models = {};
|
|
||||||
this.cache = {};
|
|
||||||
this.ids = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
WebService.prototype.installPostProcessor = function installPostProcessor(descr) {
|
|
||||||
var dates = [];
|
|
||||||
Object.keys(descr.properties).forEach(function (column) {
|
|
||||||
if (descr.properties[column].type.name === 'Date') {
|
|
||||||
dates.push(column);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var postProcessor = function (model) {
|
|
||||||
var max = dates.length;
|
|
||||||
for (var i = 0; i < max; i++) {
|
|
||||||
var column = dates[i];
|
|
||||||
if (model[column]) {
|
|
||||||
model[column] = new Date(model[column]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
descr.postProcessor = postProcessor;
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.preProcess = function preProcess(data) {
|
|
||||||
var result = {};
|
|
||||||
Object.keys(data).forEach(function (key) {
|
|
||||||
if (data[key] != null) {
|
|
||||||
result[key] = data[key];
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.postProcess = function postProcess(model, data) {
|
|
||||||
var postProcessor = this._models[model].postProcessor;
|
|
||||||
if (postProcessor && data) {
|
|
||||||
postProcessor(data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.postProcessMultiple = function postProcessMultiple(model, data) {
|
|
||||||
var postProcessor = this._models[model].postProcessor;
|
|
||||||
if (postProcessor) {
|
|
||||||
var max = data.length;
|
|
||||||
for (var i = 0; i < max; i++) {
|
|
||||||
if (data[i]) {
|
|
||||||
postProcessor(data[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.define = function defineModel(descr) {
|
|
||||||
var m = descr.model.modelName;
|
|
||||||
this.installPostProcessor(descr);
|
|
||||||
this._models[m] = descr;
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.getResourceUrl = function getResourceUrl(model) {
|
|
||||||
var url = this._models[model].settings.restPath;
|
|
||||||
if (!url) throw new Error('Resource url (restPath) for ' + model + ' is not defined');
|
|
||||||
return url;
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.getBlankReq = function () {
|
|
||||||
if (!this.csrfToken) {
|
|
||||||
this.csrfToken = $('meta[name=csrf-token]').attr('content');
|
|
||||||
this.csrfParam = $('meta[name=csrf-param]').attr('content');
|
|
||||||
}
|
|
||||||
var req = {};
|
|
||||||
req[this.csrfParam] = this.csrfToken;
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebService.prototype.create = function create(model, data, callback) {
|
|
||||||
var req = this.getBlankReq();
|
|
||||||
req[model] = this.preProcess(data);
|
|
||||||
$.post(this.getResourceUrl(model) + '.json', req, function (res) {
|
|
||||||
if (res.code === 200) {
|
|
||||||
callback(null, res.data.id);
|
|
||||||
} else {
|
|
||||||
callback(res.error);
|
|
||||||
}
|
|
||||||
}, 'json');
|
|
||||||
// this.cache[model][id] = data;
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.updateOrCreate = function (model, data, callback) {
|
|
||||||
var mem = this;
|
|
||||||
this.exists(model, data.id, function (err, exists) {
|
|
||||||
if (exists) {
|
|
||||||
mem.save(model, data, callback);
|
|
||||||
} else {
|
|
||||||
mem.create(model, data, function (err, id) {
|
|
||||||
data.id = id;
|
|
||||||
callback(err, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.save = function save(model, data, callback) {
|
|
||||||
var _this = this;
|
|
||||||
var req = this.getBlankReq();
|
|
||||||
req._method = 'PUT';
|
|
||||||
req[model] = this.preProcess(data);
|
|
||||||
$.post(this.getResourceUrl(model) + '/' + data.id + '.json', req, function (res) {
|
|
||||||
if (res.code === 200) {
|
|
||||||
_this.postProcess(model, res.data);
|
|
||||||
callback(null, res.data);
|
|
||||||
} else {
|
|
||||||
callback(res.error);
|
|
||||||
}
|
|
||||||
}, 'json');
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.exists = function exists(model, id, callback) {
|
|
||||||
$.getJSON(this.getResourceUrl(model) + '/' + id + '.json', function (res) {
|
|
||||||
if (res.code === 200) {
|
|
||||||
callback(null, true);
|
|
||||||
} else if (res.code === 404) {
|
|
||||||
callback(null, false);
|
|
||||||
} else {
|
|
||||||
callback(res.error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.find = function find(model, id, callback) {
|
|
||||||
var _this = this;
|
|
||||||
$.getJSON(this.getResourceUrl(model) + '/' + id + '.json', function (res) {
|
|
||||||
if (res.code === 200) {
|
|
||||||
_this.postProcess(model, res.data);
|
|
||||||
callback(null, res.data);
|
|
||||||
} else {
|
|
||||||
callback(res.error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.destroy = function destroy(model, id, callback) {
|
|
||||||
var _this = this;
|
|
||||||
var req = this.getBlankReq();
|
|
||||||
req._method = 'DELETE';
|
|
||||||
$.post(this.getResourceUrl(model) + '/' + id + '.json', req, function (res) {
|
|
||||||
if (res.code === 200) {
|
|
||||||
//delete _this.cache[model][id];
|
|
||||||
callback(null, res.data);
|
|
||||||
} else {
|
|
||||||
callback(res.error);
|
|
||||||
}
|
|
||||||
}, 'json');
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.all = function all(model, filter, callback) {
|
|
||||||
var _this = this;
|
|
||||||
$.getJSON(this.getResourceUrl(model) + '.json?query=' + encodeURIComponent(JSON.stringify(filter)), function (res) {
|
|
||||||
if (res.code === 200) {
|
|
||||||
_this.postProcessMultiple(model, res.data);
|
|
||||||
callback(null, res.data);
|
|
||||||
} else {
|
|
||||||
callback(res.error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.destroyAll = function destroyAll(model, callback) {
|
|
||||||
throw new Error('Not supported');
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.count = function count(model, callback, where) {
|
|
||||||
throw new Error('Not supported');
|
|
||||||
};
|
|
||||||
|
|
||||||
WebService.prototype.updateAttributes = function (model, id, data, callback) {
|
|
||||||
data.id = id;
|
|
||||||
this.save(model, data, callback);
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,373 +0,0 @@
|
||||||
var safeRequire = require('../utils').safeRequire;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
var neo4j = safeRequire('neo4j');
|
|
||||||
|
|
||||||
exports.initialize = function initializeSchema(dataSource, callback) {
|
|
||||||
dataSource.client = new neo4j.GraphDatabase(dataSource.settings.url);
|
|
||||||
dataSource.connector = new Neo4j(dataSource.client);
|
|
||||||
process.nextTick(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
function Neo4j(client) {
|
|
||||||
this._models = {};
|
|
||||||
this.client = client;
|
|
||||||
this.cache = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Neo4j.prototype.define = function defineModel(descr) {
|
|
||||||
this.mixClassMethods(descr.model, descr.properties);
|
|
||||||
this.mixInstanceMethods(descr.model.prototype, descr.properties);
|
|
||||||
this._models[descr.model.modelName] = descr;
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.createIndexHelper = function (cls, indexName) {
|
|
||||||
var db = this.client;
|
|
||||||
var method = 'findBy' + indexName[0].toUpperCase() + indexName.substr(1);
|
|
||||||
cls[method] = function (value, cb) {
|
|
||||||
db.getIndexedNode(cls.modelName, indexName, value, function (err, node) {
|
|
||||||
if (err) return cb(err);
|
|
||||||
if (node) {
|
|
||||||
node.data.id = node.id;
|
|
||||||
cb(null, new cls(node.data));
|
|
||||||
} else {
|
|
||||||
cb(null, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.mixClassMethods = function mixClassMethods(cls, properties) {
|
|
||||||
var neo = this;
|
|
||||||
|
|
||||||
Object.keys(properties).forEach(function (name) {
|
|
||||||
if (properties[name].index) {
|
|
||||||
neo.createIndexHelper(cls, name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
cls.setupCypherQuery = function (name, queryStr, rowHandler) {
|
|
||||||
cls[name] = function cypherQuery(params, cb) {
|
|
||||||
if (typeof params === 'function') {
|
|
||||||
cb = params;
|
|
||||||
params = [];
|
|
||||||
} else if (params.constructor.name !== 'Array') {
|
|
||||||
params = [params];
|
|
||||||
}
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
var q = queryStr.replace(/\?/g, function () {
|
|
||||||
return params[i++];
|
|
||||||
});
|
|
||||||
|
|
||||||
neo.client.query(function (err, result) {
|
|
||||||
if (err) return cb(err, []);
|
|
||||||
cb(null, result.map(rowHandler));
|
|
||||||
}, q);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param from - id of object to check relation from
|
|
||||||
* @param to - id of object to check relation to
|
|
||||||
* @param type - type of relation
|
|
||||||
* @param direction - all | incoming | outgoing
|
|
||||||
* @param cb - callback (err, rel || false)
|
|
||||||
*/
|
|
||||||
cls.relationshipExists = function relationshipExists(from, to, type, direction, cb) {
|
|
||||||
neo.node(from, function (err, node) {
|
|
||||||
if (err) return cb(err);
|
|
||||||
node._getRelationships(direction, type, function (err, rels) {
|
|
||||||
if (err && cb) return cb(err);
|
|
||||||
if (err && !cb) throw err;
|
|
||||||
var found = false;
|
|
||||||
if (rels && rels.forEach) {
|
|
||||||
rels.forEach(function (r) {
|
|
||||||
if (r.start.id === from && r.end.id === to) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
cb && cb(err, found);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
cls.createRelationshipTo = function createRelationshipTo(id1, id2, type, data, cb) {
|
|
||||||
var fromNode, toNode;
|
|
||||||
neo.node(id1, function (err, node) {
|
|
||||||
if (err && cb) return cb(err);
|
|
||||||
if (err && !cb) throw err;
|
|
||||||
fromNode = node;
|
|
||||||
ok();
|
|
||||||
});
|
|
||||||
neo.node(id2, function (err, node) {
|
|
||||||
if (err && cb) return cb(err);
|
|
||||||
if (err && !cb) throw err;
|
|
||||||
toNode = node;
|
|
||||||
ok();
|
|
||||||
});
|
|
||||||
function ok() {
|
|
||||||
if (fromNode && toNode) {
|
|
||||||
fromNode.createRelationshipTo(toNode, type, cleanup(data), cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
cls.createRelationshipFrom = function createRelationshipFrom(id1, id2, type, data, cb) {
|
|
||||||
cls.createRelationshipTo(id2, id1, type, data, cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
// only create relationship if it is not exists
|
|
||||||
cls.ensureRelationshipTo = function (id1, id2, type, data, cb) {
|
|
||||||
cls.relationshipExists(id1, id2, type, 'outgoing', function (err, exists) {
|
|
||||||
if (err && cb) return cb(err);
|
|
||||||
if (err && !cb) throw err;
|
|
||||||
if (exists) return cb && cb(null);
|
|
||||||
cls.createRelationshipTo(id1, id2, type, data, cb);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.mixInstanceMethods = function mixInstanceMethods(proto) {
|
|
||||||
var neo = this;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param obj - Object or id of object to check relation with
|
|
||||||
* @param type - type of relation
|
|
||||||
* @param cb - callback (err, rel || false)
|
|
||||||
*/
|
|
||||||
proto.isInRelationWith = function isInRelationWith(obj, type, direction, cb) {
|
|
||||||
this.constructor.relationshipExists(this.id, obj.id || obj, type, 'all', cb);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.node = function find(id, callback) {
|
|
||||||
if (this.cache[id]) {
|
|
||||||
callback(null, this.cache[id]);
|
|
||||||
} else {
|
|
||||||
this.client.getNodeById(id, function (err, node) {
|
|
||||||
if (node) {
|
|
||||||
this.cache[id] = node;
|
|
||||||
}
|
|
||||||
callback(err, node);
|
|
||||||
}.bind(this));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.create = function create(model, data, callback) {
|
|
||||||
data.nodeType = model;
|
|
||||||
var node = this.client.createNode();
|
|
||||||
node.data = cleanup(data);
|
|
||||||
node.data.nodeType = model;
|
|
||||||
node.save(function (err) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
this.cache[node.id] = node;
|
|
||||||
node.index(model, 'id', node.id, function (err) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
this.updateIndexes(model, node, function (err) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
callback(null, node.id);
|
|
||||||
});
|
|
||||||
}.bind(this));
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.updateIndexes = function updateIndexes(model, node, cb) {
|
|
||||||
var props = this._models[model].properties;
|
|
||||||
var wait = 1;
|
|
||||||
Object.keys(props).forEach(function (key) {
|
|
||||||
if (props[key].index && node.data[key]) {
|
|
||||||
wait += 1;
|
|
||||||
node.index(model, key, node.data[key], done);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
done();
|
|
||||||
|
|
||||||
var error = false;
|
|
||||||
|
|
||||||
function done(err) {
|
|
||||||
error = error || err;
|
|
||||||
if (--wait === 0) {
|
|
||||||
cb(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.save = function save(model, data, callback) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.node(data.id, function (err, node) {
|
|
||||||
//delete id property since that's redundant and we use the node.id
|
|
||||||
delete data.id;
|
|
||||||
if (err) return callback(err);
|
|
||||||
node.data = cleanup(data);
|
|
||||||
node.save(function (err) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
self.updateIndexes(model, node, function (err) {
|
|
||||||
if (err) return console.log(err);
|
|
||||||
//map node id to the id property being sent back
|
|
||||||
node.data.id = node.id;
|
|
||||||
callback(null, node.data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.exists = function exists(model, id, callback) {
|
|
||||||
delete this.cache[id];
|
|
||||||
this.node(id, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.find = function find(model, id, callback) {
|
|
||||||
delete this.cache[id];
|
|
||||||
this.node(id, function (err, node) {
|
|
||||||
if (node && node.data) {
|
|
||||||
node.data.id = id;
|
|
||||||
}
|
|
||||||
callback(err, this.readFromDb(model, node && node.data));
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.readFromDb = function readFromDb(model, data) {
|
|
||||||
if (!data) return data;
|
|
||||||
var res = {};
|
|
||||||
var props = this._models[model].properties;
|
|
||||||
Object.keys(data).forEach(function (key) {
|
|
||||||
if (props[key] && props[key].type.name === 'Date') {
|
|
||||||
res[key] = new Date(data[key]);
|
|
||||||
} else {
|
|
||||||
res[key] = data[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.destroy = function destroy(model, id, callback) {
|
|
||||||
var force = true;
|
|
||||||
this.node(id, function (err, node) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
node.delete(function (err) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
delete this.cache[id];
|
|
||||||
}.bind(this), force);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.all = function all(model, filter, callback) {
|
|
||||||
this.client.queryNodeIndex(model, 'id:*', function (err, nodes) {
|
|
||||||
if (nodes) {
|
|
||||||
nodes = nodes.map(function (obj) {
|
|
||||||
obj.data.id = obj.id;
|
|
||||||
return this.readFromDb(model, obj.data);
|
|
||||||
}.bind(this));
|
|
||||||
}
|
|
||||||
if (filter) {
|
|
||||||
nodes = nodes ? nodes.filter(applyFilter(filter)) : nodes;
|
|
||||||
if (filter.order) {
|
|
||||||
var key = filter.order.split(' ')[0];
|
|
||||||
var dir = filter.order.split(' ')[1];
|
|
||||||
nodes = nodes.sort(function (a, b) {
|
|
||||||
return a[key] > b[key];
|
|
||||||
});
|
|
||||||
if (dir === 'DESC') nodes = nodes.reverse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callback(err, nodes);
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.allNodes = function all(model, callback) {
|
|
||||||
this.client.queryNodeIndex(model, 'id:*', function (err, nodes) {
|
|
||||||
callback(err, nodes);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function applyFilter(filter) {
|
|
||||||
if (typeof filter.where === 'function') {
|
|
||||||
return filter.where;
|
|
||||||
}
|
|
||||||
var keys = Object.keys(filter.where || {});
|
|
||||||
return function (obj) {
|
|
||||||
var pass = true;
|
|
||||||
keys.forEach(function (key) {
|
|
||||||
if (!test(filter.where[key], obj[key])) {
|
|
||||||
pass = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
function test(example, value) {
|
|
||||||
if (typeof value === 'string' && example && example.constructor.name === 'RegExp') {
|
|
||||||
return value.match(example);
|
|
||||||
}
|
|
||||||
if (typeof value === 'object' && value.constructor.name === 'Date' && typeof example === 'object' && example.constructor.name === 'Date') {
|
|
||||||
return example.toString() === value.toString();
|
|
||||||
}
|
|
||||||
// not strict equality
|
|
||||||
return example == value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Neo4j.prototype.destroyAll = function destroyAll(model, callback) {
|
|
||||||
var wait, error = null;
|
|
||||||
this.allNodes(model, function (err, collection) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
wait = collection.length;
|
|
||||||
collection && collection.forEach && collection.forEach(function (node) {
|
|
||||||
node.delete(done, true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function done(err) {
|
|
||||||
error = error || err;
|
|
||||||
if (--wait === 0) {
|
|
||||||
callback(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.count = function count(model, callback, conds) {
|
|
||||||
this.all(model, {where: conds}, function (err, collection) {
|
|
||||||
callback(err, collection ? collection.length : 0);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Neo4j.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
|
|
||||||
data.id = id;
|
|
||||||
this.node(id, function (err, node) {
|
|
||||||
this.save(model, merge(node.data, data), cb);
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
function cleanup(data) {
|
|
||||||
if (!data) return null;
|
|
||||||
|
|
||||||
var res = {};
|
|
||||||
Object.keys(data).forEach(function (key) {
|
|
||||||
var v = data[key];
|
|
||||||
if (v === null) {
|
|
||||||
// skip
|
|
||||||
// console.log('skip null', key);
|
|
||||||
} else if (v && v.constructor.name === 'Array' && v.length === 0) {
|
|
||||||
// skip
|
|
||||||
// console.log('skip blank array', key);
|
|
||||||
} else if (typeof v !== 'undefined') {
|
|
||||||
res[key] = v;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
function merge(base, update) {
|
|
||||||
Object.keys(update).forEach(function (key) {
|
|
||||||
base[key] = update[key];
|
|
||||||
});
|
|
||||||
return base;
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
var safeRequire = require('../utils').safeRequire;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
var uuid = require('node-uuid');
|
|
||||||
var riak = safeRequire('riak-js');
|
|
||||||
|
|
||||||
exports.initialize = function initializeSchema(dataSource, callback) {
|
|
||||||
dataSource.client = riak.getClient({
|
|
||||||
host: dataSource.settings.host || '127.0.0.1',
|
|
||||||
port: dataSource.settings.port || 8091
|
|
||||||
});
|
|
||||||
dataSource.connector = new Riak(dataSource.client);
|
|
||||||
};
|
|
||||||
|
|
||||||
function Riak(client) {
|
|
||||||
this._models = {};
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
Riak.prototype.define = function (descr) {
|
|
||||||
this._models[descr.model.modelName] = descr;
|
|
||||||
};
|
|
||||||
|
|
||||||
Riak.prototype.save = function (model, data, callback) {
|
|
||||||
this.client.save(model, data.id, data, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
Riak.prototype.create = function (model, data, callback) {
|
|
||||||
data.id = uuid();
|
|
||||||
this.save(model, data, function (err) {
|
|
||||||
if (callback) {
|
|
||||||
callback(err, data.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Riak.prototype.exists = function (model, id, callback) {
|
|
||||||
this.client.exists(model, id, function (err, exists, meta) {
|
|
||||||
if (callback) {
|
|
||||||
callback(err, exists);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Riak.prototype.find = function find(model, id, callback) {
|
|
||||||
this.client.get(model, id, function (err, data, meta) {
|
|
||||||
if (data && data.id) {
|
|
||||||
data.id = id;
|
|
||||||
} else {
|
|
||||||
data = null;
|
|
||||||
}
|
|
||||||
if (typeof callback === 'function') callback(err, data);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Riak.prototype.destroy = function destroy(model, id, callback) {
|
|
||||||
this.client.remove(model, id, function (err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Riak.prototype.all = function all(model, filter, callback) {
|
|
||||||
var opts = {};
|
|
||||||
if (filter && filter.where) opts.where = filter.where;
|
|
||||||
this.client.getAll(model, function (err, result, meta) {
|
|
||||||
if (err) return callback(err, []);
|
|
||||||
/// return callback(err, result.map(function (x) { return {id: x}; }));
|
|
||||||
result = (result || []).map(function (row) {
|
|
||||||
var record = row.data;
|
|
||||||
record.id = row.meta.key;
|
|
||||||
console.log(record);
|
|
||||||
return record;
|
|
||||||
});
|
|
||||||
|
|
||||||
return callback(err, result);
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
Riak.prototype.destroyAll = function destroyAll(model, callback) {
|
|
||||||
var self = this;
|
|
||||||
this.all(model, {}, function (err, recs) {
|
|
||||||
if (err) callback(err);
|
|
||||||
|
|
||||||
removeOne();
|
|
||||||
|
|
||||||
function removeOne(error) {
|
|
||||||
err = err || error;
|
|
||||||
var rec = recs.pop();
|
|
||||||
if (!rec) return callback(err && err.statusCode != '404' ? err : null);
|
|
||||||
console.log(rec.id);
|
|
||||||
self.client.remove(model, rec.id, removeOne);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
Riak.prototype.count = function count(model, callback) {
|
|
||||||
this.client.keys(model + ':*', function (err, keys) {
|
|
||||||
callback(err, err ? null : keys.length);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Riak.prototype.updateAttributes = function updateAttrs(model, id, data, cb) {
|
|
||||||
data.id = id;
|
|
||||||
this.save(model, data, cb);
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in New Issue