114 lines
2.5 KiB
JavaScript
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;
|
|
};
|
|
}
|