jugglingdb
Version:
Node.js ORM for every database: redis, mysql, mongodb, postgres, sqlite, ...
315 lines (276 loc) • 9.07 kB
JavaScript
'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
exports.initialize = function initializeSchema(schema, callback) {
schema.adapter = new Memory();
schema.adapter.connect(callback);
};
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 = {};
}
}
Memory.prototype.connect = function (callback) {
if (this.isTransaction) {
this.onTransactionExec = callback;
} else {
process.nextTick(callback);
}
};
Memory.prototype.define = function defineModel(descr) {
var m = descr.model.modelName;
this._models[m] = descr;
this.cache[this.table(m)] = {};
this.ids[m] = 0;
};
Memory.prototype.create = function create(model, data, callback) {
var id = data.id ? data.id : this.ids[model] += 1;
data.id = id;
this.cache[this.table(model)][id] = JSON.stringify(data);
process.nextTick(function () {
callback(null, id, 1);
});
};
/**
* Updates the respective record
*
* @param {Object} params - { where:{uid:'10'}, update:{ Name:'New name' } }
* @param callback(err, obj)
*/
Memory.prototype.update = function (model, params, callback) {
var mem = this;
this.all(model, { where: params.where, limit: params.limit, skip: params.skip }, function (err, records) {
var wait = records.length;
records.forEach(function (record) {
mem.updateAttributes(model, record.id, params.update, done);
});
if (wait === 0) {
callback();
}
function done() {
wait += -1;
if (wait === 0) {
callback();
}
}
});
};
Memory.prototype.updateOrCreate = function (model, data, callback) {
var mem = this;
this.find(model, data.id, function (err, exists) {
if (exists) {
mem.save(model, merge(exists, data), callback);
} else {
mem.create(model, data, function (err, id) {
data.id = id;
callback(err, data);
});
}
});
};
Memory.prototype.save = function save(model, data, callback) {
this.cache[this.table(model)][data.id] = JSON.stringify(data);
process.nextTick(function () {
return callback(null, data);
});
};
Memory.prototype.exists = function exists(model, id, callback) {
var _this = this;
var table = this.table(model);
process.nextTick(function () {
callback(null, _this.cache[table].hasOwnProperty(id));
});
};
Memory.prototype.find = function find(model, id, callback) {
var _this2 = this;
var table = this.table(model);
process.nextTick(function () {
callback(null, id in _this2.cache[table] && _this2.fromDb(model, _this2.cache[table][id]));
});
};
Memory.prototype.destroy = function destroy(model, id, callback) {
delete this.cache[this.table(model)][id];
process.nextTick(callback);
};
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 = Boolean(val);
break;
}
}
data[key] = val;
});
return data;
};
Memory.prototype.all = function all(model, filter, callback) {
var _this3 = this;
var table = this.table(model);
var nodes = Object.keys(this.cache[table]).map(function (key) {
return _this3.fromDb(model, _this3.cache[table][key]);
});
if (filter) {
// do we need some sorting?
if (filter.order) {
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));
}
// do we need some filtration?
if (filter.where) {
nodes = nodes ? nodes.filter(applyFilter(filter)) : nodes;
}
// limit/skip
filter.skip = filter.skip || 0;
filter.limit = filter.limit || nodes.length;
var countBeforeLimit = nodes.length;
nodes = nodes.slice(filter.skip, filter.skip + filter.limit);
nodes.countBeforeLimit = countBeforeLimit;
}
process.nextTick(function () {
if (filter && filter.include) {
_this3._models[model].model.include(nodes, filter.include, callback);
} else {
callback(null, nodes);
}
});
function sorting(a, b) {
for (var i = 0, l = this.length; i < l; i += 1) {
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;
}
};
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 example === 'undefined') {
return undefined;
}
if (typeof value === 'undefined') {
return undefined;
}
if ((typeof example === 'undefined' ? 'undefined' : _typeof(example)) === 'object') {
if (example === null) {
return value === null;
}
if (example.inq) {
if (!value) {
return false;
}
for (var i = 0; i < example.inq.length; i += 1) {
if (String(example.inq[i]) === String(value)) {
return true;
}
}
return false;
}
}
// not strict equality
return String(example !== null ? example.toString() : example) === String(value !== null ? value.toString() : value);
}
}
Memory.prototype.destroyAll = function destroyAll(model, callback) {
var _this4 = this;
var table = this.table(model);
Object.keys(this.cache[table]).forEach(function (id) {
delete _this4.cache[table][id];
});
this.cache[table] = {};
process.nextTick(callback);
};
Memory.prototype.count = function count(model, where, callback) {
var cache = this.cache[this.table(model)];
var data = Object.keys(cache);
if (where) {
data = data.filter(function (id) {
var ok = true;
Object.keys(where).forEach(function (key) {
if (String(JSON.parse(cache[id])[key]) !== String(where[key])) {
ok = false;
}
});
return ok;
});
}
process.nextTick(function () {
return callback(null, data.length);
});
};
Memory.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
data.id = id;
var base = JSON.parse(this.cache[this.table(model)][id]);
this.save(model, merge(base, data), cb);
};
Memory.prototype.transaction = function () {
return new Memory(this);
};
Memory.prototype.exec = function (callback) {
this.onTransactionExec();
setTimeout(callback, 50);
};
Memory.prototype.table = function (model) {
return this._models[model].model.tableName;
};
function merge(base, update) {
if (!base) {
return update;
}
Object.keys(update).forEach(function (key) {
return base[key] = update[key];
});
return base;
}