171 lines
4.0 KiB
JavaScript
171 lines
4.0 KiB
JavaScript
import core from 'pouchdb-core';
|
|
import idb from 'pouchdb-adapter-idb';
|
|
import http from 'pouchdb-adapter-http';
|
|
import replication from 'pouchdb-replication';
|
|
import find from 'pouchdb-find';
|
|
|
|
import { log } from './console.js';
|
|
import { isObject } from '../utils/comparators.js';
|
|
import { LiveArray } from '../utils/livearray.js';
|
|
import { deepAssign } from '../utils/conversion.js';
|
|
|
|
export const PouchDB = core
|
|
.plugin(idb)
|
|
.plugin(http)
|
|
.plugin(replication)
|
|
.plugin(find)
|
|
.plugin(PouchORM);
|
|
|
|
export function generateAttachmentUrl(dbName, docId, attachmentKey) {
|
|
return `/_doc_attachments/${dbName}/${docId}/${attachmentKey}`;
|
|
}
|
|
|
|
const dbs = new Map();
|
|
export function getDatabase(name = 'gallery') {
|
|
if (!dbs.has(name)) {
|
|
dbs.set(name, new PouchDB(name));
|
|
}
|
|
return dbs.get(name);
|
|
}
|
|
|
|
export async function getOrCreate(doc) {
|
|
const db = getDatabase();
|
|
try {
|
|
const results = await db.get(doc._id);
|
|
return [results, false];
|
|
} catch (e) {
|
|
if (e.status === 404) {
|
|
const results = db.put(doc);
|
|
return [results, true];
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
export function PouchORM(PouchDB) {
|
|
async function update(props, save = true) {
|
|
deepAssign(this, props);
|
|
if (save) {
|
|
await this.save();
|
|
} else {
|
|
this.validate();
|
|
}
|
|
return this;
|
|
}
|
|
|
|
PouchDB.registerType = opts => {
|
|
const { getUniqueID, getSequence, schema, name } = opts;
|
|
const prefix = name.toLowerCase();
|
|
const db = opts.db || new PouchDB(prefix);
|
|
|
|
function populateId(doc) {
|
|
if (!doc._id) {
|
|
const sequence = getSequence ? getSequence(doc).toString(36) : '';
|
|
doc._id = `${prefix}_${sequence}_${getUniqueID(doc)}`;
|
|
}
|
|
return doc;
|
|
}
|
|
|
|
function validate() {
|
|
// FIXME
|
|
return this;
|
|
}
|
|
|
|
async function save() {
|
|
const { rev } = await db.put(this.validate());
|
|
this._rev = rev;
|
|
return this;
|
|
}
|
|
|
|
async function addAttachment(attName, dataBlob) {
|
|
const { rev } = await db.putAttachment(this._id, attName, this._rev, dataBlob, dataBlob.type);
|
|
|
|
this._rev = rev;
|
|
return this;
|
|
}
|
|
|
|
async function getAttachment(attName) {
|
|
return await db.getAttachment(this._id, attName);
|
|
}
|
|
|
|
async function removeAttachment(attName) {
|
|
return await db.removeAttachment(this._id, attName, this._rev);
|
|
}
|
|
|
|
function instantiate(docOrResultSet) {
|
|
Object.defineProperties(docOrResultSet, {
|
|
update: { value: update.bind(docOrResultSet) },
|
|
save: { value: save.bind(docOrResultSet) },
|
|
delete: { value: _delete.bind(docOrResultSet) },
|
|
addAttachment: { value: addAttachment.bind(docOrResultSet) },
|
|
getAttachment: { value: getAttachment.bind(docOrResultSet) },
|
|
removeAttachment: { value: removeAttachment.bind(docOrResultSet) },
|
|
validate: { value: validate.bind(docOrResultSet) }
|
|
});
|
|
return docOrResultSet;
|
|
}
|
|
|
|
async function find(idOrQuery, live = false, raw = false) {
|
|
let results = [];
|
|
if (typeof idOrQuery === 'undefined') {
|
|
results = await db.find({
|
|
selector: {
|
|
_id: { $gt: `${prefix}_0`, $lt: `${prefix}_\ufff0` }
|
|
}
|
|
});
|
|
} else if (typeof idOrQuery === 'string') {
|
|
results = await db.find({
|
|
selector: { _id: idOrQuery }
|
|
});
|
|
} else if (isObject(idOrQuery)) {
|
|
if (live) {
|
|
return LiveArray(db, idOrQuery, instantiate);
|
|
}
|
|
results = await db.find({
|
|
selector: idOrQuery
|
|
});
|
|
}
|
|
|
|
return raw ? results : instantiate(results);
|
|
}
|
|
|
|
async function _delete() {
|
|
try {
|
|
const { ok } = await db.remove(this);
|
|
this.update({ _id: undefined, _rev: undefined }, false);
|
|
return ok;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function _new(props, save = false) {
|
|
const doc = instantiate(populateId(props));
|
|
if (save) {
|
|
doc.save();
|
|
}
|
|
return doc;
|
|
}
|
|
|
|
return Object.assign(
|
|
{
|
|
new: _new,
|
|
find
|
|
},
|
|
opts.methods || {}
|
|
);
|
|
};
|
|
}
|
|
|
|
export const TYPES = {
|
|
STRING: { type: 'string' },
|
|
INTEGER: { type: 'integer' },
|
|
BOOLEAN: { type: 'boolean' },
|
|
DATE: { type: 'date' }
|
|
};
|
|
|
|
// Add required types
|
|
Object.keys(TYPES).forEach(k => {
|
|
TYPES['REQUIRED_' + k] = Object.assign({ required: true }, TYPES[k]);
|
|
});
|