arrow-orm
Version:
API Builder ORM
186 lines (164 loc) • 5 kB
JavaScript
const util = require('util');
const _ = require('lodash');
const Mingo = require('mingo');
const Instance = require('../instance');
const Collection = require('../collection');
const Connector = require('../connector');
const apiBuilderConfig = require('@axway/api-builder-config');
module.exports = MemoryConnector;
util.inherits(MemoryConnector, Connector);
var PK = 0;
Mingo.setup({
key: 'id'
});
function MemoryConnector() {
this.name = 'memory';
this.version = 'built-in';
this.description = 'In-Memory database connector';
this.DB = {};
this.translateWhereRegex = apiBuilderConfig.flags.enableMemoryConnectorLike;
this.enabled = true;
// default metadata that will be applied to each model if none included
this.defaultMetadata = {
primarykey: 'id',
primaryKeyDetails: {
type: 'number',
autogenerated: true
}
};
Connector.apply(this, arguments);
}
MemoryConnector.resetPrimaryKeys = function (options = { startAt: 1 }) {
// start at 1, so initial set is 0
PK = (options && options.startAt - 1) || 0;
};
MemoryConnector.prototype.getTable = function (name) {
var array = this.DB[name];
if (!array) {
array = [];
this.DB[name] = array;
}
return array;
};
MemoryConnector.prototype.create = function create(Model, values, callback) {
var instance = Model.instance(values);
instance.setPrimaryKey(values.id || ++PK);
this.getTable(Model.name).push(instance);
callback && callback(null, instance);
};
MemoryConnector.prototype.save = function save(Model, instance, callback) {
var table = this.getTable(Model.name);
for (var c = 0; c < table.length; c++) {
var entry = table[c];
if (entry.getPrimaryKey() === instance.getPrimaryKey()) {
var obj = instance.toJSON();
for (var k in obj) {
entry.set(k, obj[k], true);
}
break;
}
}
callback && callback(null, instance);
};
function iterator(DB, instance, fn) {
var results = [],
pk = instance && ((typeof(instance) === 'object' && instance instanceof Instance) ? instance.getPrimaryKey() : instance),
pkStr = String(pk);
for (var c = 0; c < DB.length; c++) {
var object = DB[c];
if (!pk || String(object.getPrimaryKey()) === pkStr) {
if (fn) {
if (fn(c, object)) {
results.push(object);
}
} else {
results.push(object);
}
if (pk) {
// if we have a primary key, then bail after we find one
break;
}
}
}
return results;
}
MemoryConnector.prototype.delete = function remove(Model, instance, callback) {
var table = this.getTable(Model.name),
keys = [],
found = iterator(table, instance, function iterate(index, object) {
if (instance.getPrimaryKey() === object.getPrimaryKey()) {
keys.push(index);
return true;
}
});
keys.forEach(function (index) {
table.splice(index, 1);
});
callback && callback(null, found && found[0]);
};
MemoryConnector.prototype.deleteAll = function deleteAll(Model, callback) {
var table = this.getTable(Model.name),
count = table.length;
this.DB[Model.name] = [];
callback && callback(null, count);
};
MemoryConnector.prototype.count = function find(Model, options, callback) {
let where = Model.translateKeysForPayload(options.where) || {},
cursor = Mingo.find(this.getTable(Model.name), where);
callback(null, cursor.count());
};
MemoryConnector.prototype.query = function find(Model, options, callback) {
if (options.where && !_.isObject(options.where)) {
throw new Error('query "where" parameter must be an object; got: ' + options.where);
}
let where = Model.translateKeysForPayload(options.where) || {};
const cursor = Mingo.find(this.getTable(Model.name), where),
sort = options.sort,
skip = options.skip,
limit = options.limit;
let sel = Model.translateKeysForPayload(options.sel),
unsel = Model.translateKeysForPayload(options.unsel);
if (sort) {
cursor.sort(sort);
}
if (skip) {
cursor.skip(skip);
}
cursor.limit(limit);
let records = cursor.all();
// filter out fields
if (sel || unsel) {
sel = sel && fieldsToArray(options.sel);
unsel = unsel && fieldsToArray(options.unsel);
records = records.map(function (record) {
const id = record.getPrimaryKey();
let rec = record.toJSON();
if (sel && sel.length) {
rec = _.pick(rec, sel);
}
if (unsel && unsel.length) {
rec = _.omit(rec, unsel);
}
const instance = Model.instance(rec, true);
instance.setPrimaryKey(id);
return instance;
});
}
let collection = new Collection(Model, records);
callback(null, collection);
};
MemoryConnector.prototype.findAll = function findAll(Model, callback) {
callback(null, new Collection(Model, this.getTable(Model.name)));
};
MemoryConnector.prototype.findByID = function findByID(Model, id, callback) {
var found = iterator(this.getTable(Model.name), id);
callback(null, found && found[0]);
};
function fieldsToArray(fields) {
if (Array.isArray(fields)) {
return fields;
} else if (_.isObject(fields)) {
return Object.keys(fields);
}
throw new Error('invalid sel field type');
}