Timothy Farrell fad4db8a40 Allow some functions to be overloaded.
With Type.delete, we call the object's delete in case it is overloaded.
2018-05-23 05:08:13 -05:00

114 lines
2.5 KiB
JavaScript

import { LiveArray } from './livearray.js';
import { Watcher } from './watcher.js';
import { isObject } from './utils.js';
export function PouchORM(PouchDB) {
PouchDB.registerType = (name, cls, db) => {
const prefix = name.toLowerCase();
const _db = db || PouchDB(prefix);
_db.setMaxListeners(1000);
const _baseSelector = Object.freeze({
_id: { $gt: `${prefix}_0`, $lt: `${prefix}_\ufff0` }
});
const watch = Watcher(_db, _baseSelector, { include_docs: true });
if (!cls.hasOwnProperty('validate')) {
// warn(`${cls.name} has no validation.`);
}
const instantiate = doc => new cls(doc);
async function find(idOrSelector, opts = {}) {
if (typeof idOrSelector === 'string') {
return instantiate(await _db.get(idOrSelector));
}
const isSelector = isObject(idOrSelector);
const selector = Object.assign(
isSelector && idOrSelector._deleted ? { _deleted: true } : { _deleted: { exists: false } },
isSelector ? idOrSelector : _baseSelector
);
if (opts.index) {
opts.use_index = [prefix, opts.index];
delete opts.index;
}
if (opts.live) {
opts.mapper = instantiate;
return LiveArray(_db, idOrSelector, opts);
}
return (await _db.find(Object.assign({ selector: idOrSelector }, opts))).docs.map(instantiate);
}
async function getOrCreate(props) {
let doc = await new cls(props);
try {
await doc.save();
} catch (e) {
if (e.status !== 409) {
throw e;
}
doc = await find(doc._id);
}
return doc;
}
async function _delete(id) {
try {
const doc = await find(id);
await doc.delete();
} catch (e) {
if (e.status !== 404) {
throw e;
}
}
}
async function _index(name, fields) {
return _db.createIndex({
index: {
ddoc: prefix,
fields,
name
}
});
}
Object.defineProperties(cls.prototype, {
_name: { value: name },
_prefix: { value: prefix },
_db: { value: _db },
_cls: { value: cls },
_baseSelector: { value: _baseSelector }
});
const methods = {
getOrCreate: { value: getOrCreate },
find: { value: find },
index: { value: _index },
delete: { value: _delete },
subscribe: { value: watch }
};
Object.defineProperties(
cls,
Object.assign(
{
db: { value: _db },
name: { value: name },
prefix: { value: prefix },
selector: { value: _baseSelector }
},
Object.entries(methods)
.filter(([name, obj]) => cls[name] === undefined)
.reduce((acc, [name, obj]) => {
acc[name] = obj;
return acc;
}, {})
)
);
return cls;
};
}