You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
3.9 KiB
JavaScript
164 lines
3.9 KiB
JavaScript
'use strict';
|
|
|
|
const Promise = require("bluebird");
|
|
const knex = require("knex");
|
|
const fs = Promise.promisifyAll(require("fs"));
|
|
const matchObject = require("match-object");
|
|
const uuid = require("uuid");
|
|
const pick = require("object-pick");
|
|
const snakeCase = require("snake-case");
|
|
const rfr = require("rfr");
|
|
|
|
const knexErrors = rfr("lib/db/knex-error-type");
|
|
|
|
function loadCollection(db, collection) {
|
|
return Promise.try(() => {
|
|
return db(collection).select();
|
|
}).then((results) => {
|
|
return results.map((result) => {
|
|
return Object.assign(JSON.parse(result.value), {
|
|
$id: result.id
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
module.exports = function(path) {
|
|
let collections = {};
|
|
|
|
let db = knex({
|
|
client: "sqlite3",
|
|
connection: {
|
|
filename: path
|
|
},
|
|
useNullAsDefault: true,
|
|
debug: true
|
|
});
|
|
|
|
function createTable(name) {
|
|
return db.schema.createTable(name, function(table) {
|
|
table.text("id");
|
|
table.text("value");
|
|
});
|
|
}
|
|
|
|
function getCollection(name) {
|
|
let indexes; // TODO
|
|
|
|
function findIdIndex(id) {
|
|
if (id == null) {
|
|
return null;
|
|
}
|
|
|
|
return collections[name].findIndex((item) => item.$id === id);
|
|
}
|
|
|
|
return {
|
|
find: function(query) {
|
|
return collections[name].filter((item) => matchObject(query, item));
|
|
},
|
|
findOne: function(query) {
|
|
let result = collections[name].find((item) => matchObject(query, item));
|
|
|
|
if (result == null) {
|
|
throw new Error("No results found");
|
|
} else {
|
|
return result;
|
|
}
|
|
},
|
|
insert: function(object, options = {}) {
|
|
/* Intentional mutation. */
|
|
Object.assign(object, {$id: uuid.v4()});
|
|
collections[name].push(object);
|
|
|
|
return db(name).insert({
|
|
id: object.$id,
|
|
value: JSON.stringify(object)
|
|
}).then(() => {});
|
|
},
|
|
update: function(object, options = {}) {
|
|
let index;
|
|
if (index = findIdIndex(object.$id)) {
|
|
if (options.patch === true) {
|
|
Object.assign(collections[name][index], object);
|
|
} else {
|
|
collections[name][index] = object;
|
|
}
|
|
|
|
return db(name).where({id: object.$id}).update({
|
|
value: JSON.stringify(collections[name][index])
|
|
}).then(() => {});
|
|
} else {
|
|
throw new Error("No such object exists");
|
|
}
|
|
},
|
|
upsert: function(object, options = {}) {
|
|
try {
|
|
this.update(object, options);
|
|
} catch (err) {
|
|
this.insert(object, options);
|
|
}
|
|
},
|
|
upsertBy: function(keys, object, options = {}) {
|
|
let query = pick(object, keys);
|
|
|
|
try {
|
|
let result = this.findOne(query);
|
|
// FIXME: The following shouldn't be in the try block...
|
|
object.$id = result.$id;
|
|
return this.update(object, options);
|
|
} catch (err) {
|
|
return this.insert(object, options);
|
|
}
|
|
|
|
},
|
|
delete: function(object) {
|
|
let index;
|
|
if (index = findIdIndex(object.$id)) {
|
|
collections[name].splice(index, 1);
|
|
|
|
return db(name).where({id: object.$id}).delete().then(() => {});
|
|
} else {
|
|
throw new Error("No such object exists");
|
|
}
|
|
},
|
|
deleteBy: function(query) {
|
|
let toRemove = collections[name].filter((item) => matchObject(query, item));
|
|
collections[name] = collections[name].filter((item) => (toRemove.indexOf(item) !== -1));
|
|
|
|
return Promise.map(toRemove, (item) => {
|
|
return db(name).where({id: item.$id}).delete();
|
|
});
|
|
},
|
|
ensureIndex: function(property) {
|
|
// TODO
|
|
}
|
|
}
|
|
}
|
|
|
|
let dbAPI = {
|
|
close: function() {},
|
|
collection: function(name) {
|
|
return Promise.try(() => {
|
|
let snakeCasedName = snakeCase(name);
|
|
|
|
if (collections[snakeCasedName] != null) {
|
|
return getCollection(snakeCasedName);
|
|
} else {
|
|
return Promise.try(() => {
|
|
return loadCollection(db, snakeCasedName);
|
|
}).then((collectionData) => {
|
|
collections[snakeCasedName] = collectionData;
|
|
}).catch(knexErrors.sqlite.NoSuchTable, (err) => {
|
|
collections[snakeCasedName] = [];
|
|
return createTable(snakeCasedName);
|
|
}).then(() => {
|
|
return getCollection(snakeCasedName);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
return dbAPI;
|
|
} |