summaryrefslogtreecommitdiff
path: root/app/node_modules/okdb/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/node_modules/okdb/index.js')
-rw-r--r--app/node_modules/okdb/index.js213
1 files changed, 161 insertions, 52 deletions
diff --git a/app/node_modules/okdb/index.js b/app/node_modules/okdb/index.js
index 79ce1eb..ad8d9a7 100644
--- a/app/node_modules/okdb/index.js
+++ b/app/node_modules/okdb/index.js
@@ -1,6 +1,10 @@
-var Q = require('q');
+var assign = require('object-assign')
+var cloneDeep = require('lodash.clonedeep');
+var isobject = require('lodash.isobject');
var format = require('util').format;
var low = require('lowdb');
+var Q = require('q');
+
low.mixin(low.mixin(require('underscore-db')));
/**
@@ -10,14 +14,14 @@ low.mixin(low.mixin(require('underscore-db')));
function OKDB(options) {
if (!(this instanceof OKDB)) return new OKDB(options);
options = options || {};
- var type;
+ var db;
if (typeof options === 'string')
- type = options;
+ db = options;
else
- type = options.type;
- if (!type)
- throw new Error('No DB type provided');
- switch (type) {
+ db = options.db;
+ if (!db)
+ throw new Error('No DB db provided to OKDB');
+ switch (db) {
case 'fs':
return FSDB(options);
default:
@@ -27,81 +31,186 @@ function OKDB(options) {
/**
* DB implementation backed by a JSON file.
- * TODO Incomplete
*/
function FSDB(options) {
if (!(this instanceof FSDB)) return new FSDB(options);
options = options || {};
+ if (!options.schemas)
+ throw new Error('No schemas provided to FSDB')
+ this._schemas = options.schemas;
var name = options.name || 'db';
var filename = name + '.json';
this._db = low(filename);
}
-FSDB.prototype._resolve = function(data, error) {
- return Q.Promise(function resolvePromise(resolve, reject) {
- if (error) {
- reject(error);
- } else {
- resolve(data);
- }
- });
+FSDB.prototype.get = function(collection, id) {
+ var schema = this._schemas[collection];
+ if (!schema)
+ return resolve(null, new Error('No such collection type'));
+
+ var query = getQuery(schema, id);
+ if (!query)
+ return resolve(null, new Error('Bad query'));
+
+ var result = this._db(collection).find(query);
+ return resolve(result ? cloneDeep(result) : result);
};
-FSDB.prototype.get = function(collection, query) {
- if (!query) {
- return this._resolve(null, new Error('No query given'));
+/**
+ * Add a new document to the DB
+ */
+FSDB.prototype.insert = function(collection, data) {
+ var schema = this._schemas[collection];
+ var wrapped = this._db(collection);
+ if (!schema)
+ return resolve(null, new Error('No such collection type'));
+ // Get detached, clone deep, data sleep, beep beep
+ data = cloneDeep(data);
+ // Auto-increment fields
+ data = autoincrement(wrapped, schema, data);
+ // Record date created
+ // TODO Should this meta prop logic be moved out of the DB?
+ data.dateCreated = new Date().toUTCString();
+ var result = wrapped.chain().push(data).last().value();
+
+ if (result) {
+ return resolve(cloneDeep(result));
} else {
- var data = this._db(collection).find(query);
- return this._resolve(data);
+ return resolve(null, new Error('Problem inserting document'));
}
};
-FSDB.prototype.put = function(collection, query, data) {
- data = data || {};
- if (!query) {
- return this._resolve(null, new Error('No query given'));
- } else if (this._db(collection).find(query)) {
- var updated = this._db(collection)
- .chain()
- .find(query)
- .assign(data)
- .value();
- return this._resolve(updated);
+/**
+ * Update an existing document in the DB
+ */
+FSDB.prototype.update = function(collection, id, data) {
+ var schema = this._schemas[collection];
+ if (!schema)
+ return resolve(null, new Error('No such collection type'));
+
+ var query = getQuery(schema, id);
+ var wrapped = this._db(collection);
+ var chain = wrapped.chain().find(query);
+
+ if (!chain.value()) {
+ return resolve(null, new Error('Cannot update nonexistent entry'));
+ }
+
+ var result = chain.assign(cloneDeep(data)).value();
+ if (result) {
+ return resolve(cloneDeep(result));
} else {
- return this._resolve(null, new Error('Cannot update nonexistent entry'));
+ return resolve(null, new Error('Problem updating document'));
}
};
-FSDB.prototype.create = function(collection, data) {
- var created = this._db(collection)
- .chain()
- .push(data)
- .last()
- .value();
- return this._resolve(created);
-};
+/**
+ * TODO Should be atomic ¯\_(ツ)_/¯
+ */
+FSDB.prototype.updateBatch = function(collection, ids, datas) {
+ var schema = this._schemas[collection];
+ if (!schema)
+ return resolve(null, new Error('No such collection type'));
+ if (!ids || !ids.length || !datas || !datas.length ||
+ ids.length !== datas.length) {
+ return resolve(null, new Error('Bad input'));
+ }
-FSDB.prototype.remove = function(collection, id, data) {
- throw new Error('Not implemented!');
+ var doc = this._db(collection);
+ var results = ids.map(function(id, i) {
+ return doc.chain().find(getQuery(schema, id)).assign(datas[i]).value();
+ });
+
+ return resolve(results);
};
-FSDB.prototype.find = function(collection, query) {
- if (!collection || !query) {
- return this._resolve(null, new Error('Bad input'));
+FSDB.prototype.remove = function(collection, id) {
+ var schema = this._schemas[collection];
+ if (!schema)
+ return resolve(null, new Error('No such collection type'));
+
+ var query = getQuery(schema, id);
+ var result = this._db(collection).removeWhere(query);
+
+ if (result) {
+ // Don't need to clone this ref, since it's removed anyway
+ return resolve(result);
} else {
- var data = this._db(collection).find(query);
- return this._resolve(data);
+ return resolve(null, new Error('Cannot remove nonexistent entry'));
}
};
+FSDB.prototype.sortBy = function(collection, prop, descend) {
+ var schema = this._schemas[collection];
+ if (!schema)
+ return resolve(null, new Error('No such collection type'));
+ if (!prop)
+ return resolve(null, new Error('Bad input'));
+
+ var result = this._db(collection).sortByOrder([prop], [!descend]);
+ return resolve(result);
+};
+
+FSDB.prototype.find = function(collection, query) {
+ var schema = this._schemas[collection];
+ if (!schema)
+ return resolve(null, new Error('No such collection type'));
+ if (!query)
+ return resolve(null, new Error('Bad input'));
+
+ var result = this._db(collection).find(query);
+
+ return resolve(cloneDeep(result));
+};
+
+FSDB.prototype.all = function(collection) {
+ var schema = this._schemas[collection];
+ if (!schema)
+ return resolve(null, new Error('No such collection type'));
+
+ var data = this._db(collection).value();
+ return resolve(cloneDeep(data || []));
+};
+
FSDB.prototype.getMeta = function() {
var data = this._db('meta').first();
- return this._resolve(data || {});
+ return resolve(data || {});
};
-FSDB.prototype.getAll = function(collection) {
- var data = this._db(collection).toArray();
- return this._resolve(data || []);
+/**
+ * Function implementing DB auto increment support
+ * Naive implementation, assumes DB is relatively small.
+ */
+function autoincrement(wrapper, schema, data) {
+ return schema.autoIncrementFields.reduce(function(data, field) {
+ var last = wrapper.chain().sortByOrder([field], [true]).last().value();
+ var index = last ? last[field] : -1;
+ var incremented = {};
+ incremented[field] = (parseInt(index) + 1);
+ return assign(data, incremented);
+ }, data);
+}
+
+function getQuery(schema, id) {
+ if (schema && id) {
+ var query = {};
+ query[schema.idField] = id;
+ return query;
+ }
+}
+
+/**
+ * Helper function to create promises for DB data
+ */
+function resolve(data, error) {
+ return Q.promise(function resolvePromise(resolve, reject) {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(data);
+ }
+ });
};
+
module.exports = OKDB;