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

254 lines
7.3 KiB
JavaScript
Raw Normal View History

2011-10-03 13:36:43 +00:00
exports.initialize = function initializeSchema(schema, callback) {
schema.adapter = new Memory();
2013-04-01 13:49:12 +00:00
schema.adapter.connect(callback);
2011-10-03 13:36:43 +00:00
};
2013-04-01 13:49:12 +00:00
function Memory(m) {
if (m) {
this.isTransaction = true;
this.cache = m.cache;
this.ids = m.ids;
this._models = m._models;
} else {
this.isTransaction = false;
this.cache = {};
this.ids = {};
this._models = {};
}
2011-10-03 13:36:43 +00:00
}
2013-04-01 13:49:12 +00:00
Memory.prototype.connect = function(callback) {
if (this.isTransaction) {
this.onTransactionExec = callback;
} else {
process.nextTick(callback);
}
};
2011-10-03 13:36:43 +00:00
Memory.prototype.define = function defineModel(descr) {
var m = descr.model.modelName;
this._models[m] = descr;
this.cache[m] = {};
this.ids[m] = 1;
};
Memory.prototype.create = function create(model, data, callback) {
2012-03-22 19:46:16 +00:00
var id = data.id || this.ids[model]++;
2011-10-03 13:36:43 +00:00
data.id = id;
2013-03-27 13:10:13 +00:00
this.cache[model][id] = JSON.stringify(data);
2013-04-01 13:49:12 +00:00
process.nextTick(function() {
2013-01-21 18:21:43 +00:00
callback(null, id);
});
2011-10-03 13:36:43 +00:00
};
2012-03-22 19:46:16 +00:00
Memory.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);
});
}
});
};
2011-10-03 13:36:43 +00:00
Memory.prototype.save = function save(model, data, callback) {
2013-03-27 13:10:13 +00:00
this.cache[model][data.id] = JSON.stringify(data);
2013-01-21 18:21:43 +00:00
process.nextTick(function () {
callback(null, data);
});
2011-10-03 13:36:43 +00:00
};
Memory.prototype.exists = function exists(model, id, callback) {
2013-01-21 18:21:43 +00:00
process.nextTick(function () {
callback(null, this.cache[model].hasOwnProperty(id));
}.bind(this));
2011-10-03 13:36:43 +00:00
};
Memory.prototype.find = function find(model, id, callback) {
2013-01-21 18:21:43 +00:00
process.nextTick(function () {
2013-04-06 10:50:23 +00:00
callback(null, id in this.cache[model] && this.fromDb(model, this.cache[model][id]));
2013-01-21 18:21:43 +00:00
}.bind(this));
2011-10-03 13:36:43 +00:00
};
Memory.prototype.destroy = function destroy(model, id, callback) {
delete this.cache[model][id];
2013-01-21 18:21:43 +00:00
process.nextTick(callback);
2011-10-03 13:36:43 +00:00
};
2013-04-06 10:50:23 +00:00
Memory.prototype.fromDb = function(model, data) {
if (!data) return null;
data = JSON.parse(data);
var props = this._models[model].properties;
Object.keys(data).forEach(function (key) {
var val = data[key];
if (typeof val === 'undefined' || val === null) {
return;
}
if (props[key]) {
switch(props[key].type.name) {
case 'Date':
val = new Date(val.toString().replace(/GMT.*$/, 'GMT'));
break;
case 'Boolean':
val = new Boolean(val);
break;
}
}
data[key] = val;
});
return data;
};
2011-10-03 13:36:43 +00:00
Memory.prototype.all = function all(model, filter, callback) {
2013-03-27 13:10:13 +00:00
var self = this;
2011-10-03 13:36:43 +00:00
var nodes = Object.keys(this.cache[model]).map(function (key) {
2013-04-06 10:50:23 +00:00
return this.fromDb(model, this.cache[model][key]);
2011-10-03 13:36:43 +00:00
}.bind(this));
if (filter) {
// do we need some sorting?
if (filter.order) {
var props = this._models[model].properties;
var orders = filter.order;
if (typeof filter.order === "string") {
orders = [filter.order];
}
orders.forEach(function (key, i) {
var reverse = 1;
var m = key.match(/\s+(A|DE)SC$/i);
if (m) {
key = key.replace(/\s+(A|DE)SC/i, '');
if (m[1].toLowerCase() === 'de') reverse = -1;
}
orders[i] = {"key": key, "reverse": reverse};
});
nodes = nodes.sort(sorting.bind(orders));
}
2013-03-26 20:50:13 +00:00
// do we need some filtration?
if (filter.where) {
nodes = nodes ? nodes.filter(applyFilter(filter)) : nodes;
}
2013-04-18 20:33:57 +00:00
// limit/skip
filter.skip = filter.skip || 0;
filter.limit = filter.limit || nodes.length;
nodes = nodes.slice(filter.skip, filter.skip + filter.limit);
}
2011-10-03 13:36:43 +00:00
process.nextTick(function () {
2013-03-27 13:10:13 +00:00
if (filter && filter.include) {
self._models[model].model.include(nodes, filter.include, callback);
} else {
callback(null, nodes);
}
2011-10-03 13:36:43 +00:00
});
function sorting(a, b) {
for (var i=0, l=this.length; i<l; i++) {
if (a[this[i].key] > b[this[i].key]) {
return 1*this[i].reverse;
} else if (a[this[i].key] < b[this[i].key]) {
return -1*this[i].reverse;
}
}
return 0;
2013-03-26 20:50:13 +00:00
}
2011-10-03 13:36:43 +00:00
};
function applyFilter(filter) {
if (typeof filter.where === 'function') {
return filter.where;
2011-10-03 13:36:43 +00:00
}
var keys = Object.keys(filter.where);
2011-10-03 13:36:43 +00:00
return function (obj) {
var pass = true;
keys.forEach(function (key) {
if (!test(filter.where[key], obj[key])) {
2011-10-03 13:36:43 +00:00
pass = false;
}
});
return pass;
}
function test(example, value) {
if (typeof value === 'string' && example && example.constructor.name === 'RegExp') {
return value.match(example);
}
if (typeof example === 'undefined') return undefined;
if (typeof value === 'undefined') return undefined;
2013-03-27 13:10:13 +00:00
if (typeof example === 'object') {
if (example.inq) {
if (!value) return false;
for (var i = 0; i < example.inq.length; i += 1) {
if (example.inq[i] == value) return true;
}
return false;
}
if(isNum(example.gt) && example.gt < value) return true;
if(isNum(example.gte) && example.gte <= value) return true;
if(isNum(example.lt) && example.lt > value) return true;
if(isNum(example.lte) && example.lte >= value) return true;
2013-03-27 13:10:13 +00:00
}
2011-10-03 13:36:43 +00:00
// not strict equality
2012-09-09 13:17:08 +00:00
return (example !== null ? example.toString() : example) == (value !== null ? value.toString() : value);
2011-10-03 13:36:43 +00:00
}
function isNum(n) {
return typeof n === 'number';
}
2011-10-03 13:36:43 +00:00
}
Memory.prototype.destroyAll = function destroyAll(model, callback) {
Object.keys(this.cache[model]).forEach(function (id) {
delete this.cache[model][id];
}.bind(this));
this.cache[model] = {};
2013-01-21 18:21:43 +00:00
process.nextTick(callback);
2011-10-03 13:36:43 +00:00
};
Memory.prototype.count = function count(model, callback, where) {
var cache = this.cache[model];
var data = Object.keys(cache)
if (where) {
var filter = {where: where};
data = data.map(function (id) {
return this.fromDb(model, cache[id]);
}.bind(this));
data = data.filter(applyFilter(filter));
}
2013-01-21 18:21:43 +00:00
process.nextTick(function () {
callback(null, data.length);
});
2011-10-03 13:36:43 +00:00
};
Memory.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
data.id = id;
2013-03-30 17:07:16 +00:00
var base = JSON.parse(this.cache[model][id]);
2011-10-03 13:36:43 +00:00
this.save(model, merge(base, data), cb);
};
2013-04-01 13:49:12 +00:00
Memory.prototype.transaction = function () {
return new Memory(this);
};
Memory.prototype.exec = function(callback) {
this.onTransactionExec();
setTimeout(callback, 50);
};
2011-10-03 13:36:43 +00:00
function merge(base, update) {
2012-03-22 19:46:16 +00:00
if (!base) return update;
2011-10-03 13:36:43 +00:00
Object.keys(update).forEach(function (key) {
base[key] = update[key];
});
return base;
}