Integrate PouchORM package into Gallery project
This commit is contained in:
parent
ad779629a5
commit
8cfb7f575e
@ -14,7 +14,7 @@
|
|||||||
"domvm": "~3.2.1",
|
"domvm": "~3.2.1",
|
||||||
"exif-parser": "~0.1.9",
|
"exif-parser": "~0.1.9",
|
||||||
"extract-text-webpack-plugin": "^3.0.2",
|
"extract-text-webpack-plugin": "^3.0.2",
|
||||||
"frptools": "3.1.0",
|
"frptools": "3.1.1",
|
||||||
"linear-partitioning": "0.3.2",
|
"linear-partitioning": "0.3.2",
|
||||||
"pica": "~2.0.8",
|
"pica": "~2.0.8",
|
||||||
"pouchdb-adapter-http": "~6.4.1",
|
"pouchdb-adapter-http": "~6.4.1",
|
||||||
@ -24,6 +24,7 @@
|
|||||||
"pouchdb-core": "~6.4.1",
|
"pouchdb-core": "~6.4.1",
|
||||||
"pouchdb-find": "~6.4.1",
|
"pouchdb-find": "~6.4.1",
|
||||||
"pouchdb-replication": "~6.4.1",
|
"pouchdb-replication": "~6.4.1",
|
||||||
|
"pouchorm": "~1.0.0",
|
||||||
"router": "2.1.0",
|
"router": "2.1.0",
|
||||||
"semantic-ui-reset": "^2.2.12",
|
"semantic-ui-reset": "^2.2.12",
|
||||||
"semantic-ui-site": "^2.2.12",
|
"semantic-ui-site": "^2.2.12",
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import { PouchDB, TypeSpec } from '../services/db.js';
|
import { TypeSpec } from 'pouchorm';
|
||||||
|
|
||||||
|
import { PouchDB } from '../services/db.js';
|
||||||
import { ImageType } from '../data/image.js';
|
import { ImageType } from '../data/image.js';
|
||||||
import { extractID } from '../utils/conversion.js';
|
import { extractID } from '../utils/conversion.js';
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import { PouchDB, TypeSpec } from '../services/db.js';
|
import { TypeSpec } from 'pouchorm';
|
||||||
|
|
||||||
|
import { PouchDB } from '../services/db.js';
|
||||||
import { sha256 } from '../utils/crypto.js';
|
import { sha256 } from '../utils/crypto.js';
|
||||||
import { blobToArrayBuffer } from '../utils/conversion.js';
|
import { blobToArrayBuffer } from '../utils/conversion.js';
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import { PouchDB, TypeSpec } from '../services/db.js';
|
import { TypeSpec } from 'pouchorm';
|
||||||
|
|
||||||
|
import { PouchDB } from '../services/db.js';
|
||||||
import { blobToArrayBuffer, deepAssign } from '../utils/conversion.js';
|
import { blobToArrayBuffer, deepAssign } from '../utils/conversion.js';
|
||||||
import { backgroundTask } from '../utils/event.js';
|
import { backgroundTask } from '../utils/event.js';
|
||||||
import { FileType } from './file.js';
|
import { FileType } from './file.js';
|
||||||
|
|||||||
@ -4,11 +4,7 @@ import http from 'pouchdb-adapter-http';
|
|||||||
import replication from 'pouchdb-replication';
|
import replication from 'pouchdb-replication';
|
||||||
import find from 'pouchdb-find';
|
import find from 'pouchdb-find';
|
||||||
|
|
||||||
import { log, warn } from './console.js';
|
import { PouchORM } from 'pouchorm';
|
||||||
import { isObject } from '../utils/comparators.js';
|
|
||||||
import { LiveArray } from '../utils/livearray.js';
|
|
||||||
import { Watcher } from '../utils/watcher.js';
|
|
||||||
import { deepAssign, pouchDocHash } from '../utils/conversion.js';
|
|
||||||
|
|
||||||
export const PouchDB = core
|
export const PouchDB = core
|
||||||
.plugin(idb)
|
.plugin(idb)
|
||||||
@ -16,168 +12,3 @@ export const PouchDB = core
|
|||||||
.plugin(replication)
|
.plugin(replication)
|
||||||
.plugin(find)
|
.plugin(find)
|
||||||
.plugin(PouchORM);
|
.plugin(PouchORM);
|
||||||
|
|
||||||
export class TypeSpec {
|
|
||||||
constructor(props) {
|
|
||||||
this._populateId(props);
|
|
||||||
Object.assign(this, { $links: {} }, props, { type: this._prefix });
|
|
||||||
}
|
|
||||||
|
|
||||||
static getUniqueID(doc) {
|
|
||||||
throw 'NotImplemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
static validate(doc) {}
|
|
||||||
|
|
||||||
instantiate(doc) {
|
|
||||||
return new this._cls(docs);
|
|
||||||
}
|
|
||||||
|
|
||||||
_populateId(doc) {
|
|
||||||
if (!doc._id) {
|
|
||||||
doc._id = `${this._prefix}_${this._cls.getUniqueID(doc)}`;
|
|
||||||
}
|
|
||||||
return doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
_hash() {
|
|
||||||
return pouchDocHash(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
async delete() {
|
|
||||||
return await this.update({ _deleted: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
async save() {
|
|
||||||
this._cls.validate(this);
|
|
||||||
const { rev } = await this._db.put(this);
|
|
||||||
this._rev = rev;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
async addAttachment(attName, dataBlob) {
|
|
||||||
const { rev } = await this._db.putAttachment(
|
|
||||||
this._id,
|
|
||||||
attName,
|
|
||||||
this._rev,
|
|
||||||
dataBlob,
|
|
||||||
dataBlob.type
|
|
||||||
);
|
|
||||||
|
|
||||||
this._rev = rev;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAttachment(attName) {
|
|
||||||
return await this._db.getAttachment(this._id, attName);
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeAttachment(attName) {
|
|
||||||
return await this._db.removeAttachment(this._id, attName, this._rev);
|
|
||||||
}
|
|
||||||
|
|
||||||
async update(props, save = true) {
|
|
||||||
deepAssign(this, props);
|
|
||||||
if (save) {
|
|
||||||
await this.save();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
doc._deleted = true;
|
|
||||||
await _db.put(doc);
|
|
||||||
} 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 }
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperties(cls, {
|
|
||||||
getOrCreate: { value: getOrCreate },
|
|
||||||
find: { value: find },
|
|
||||||
index: { value: _index },
|
|
||||||
delete: { value: _delete },
|
|
||||||
subscribe: { value: watch },
|
|
||||||
db: { value: _db },
|
|
||||||
name: { value: name },
|
|
||||||
prefix: { value: prefix },
|
|
||||||
selector: { value: _baseSelector }
|
|
||||||
});
|
|
||||||
|
|
||||||
return cls;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,42 +0,0 @@
|
|||||||
import { prop, computed, id } from 'frptools';
|
|
||||||
|
|
||||||
import { Watcher } from './watcher.js';
|
|
||||||
import { pouchDocArrayHash } from './conversion.js';
|
|
||||||
|
|
||||||
// LiveArray is a subscribable property function that always returns the db results that match the provided selector and calls subscribers when the results change.
|
|
||||||
export function LiveArray(db, selector, opts = {}) {
|
|
||||||
const mapper = opts.mapper || id;
|
|
||||||
opts.mapper && delete opts.mapper;
|
|
||||||
opts.include_docs = true;
|
|
||||||
const _watcher = Watcher(db, selector, opts);
|
|
||||||
let changeSub = null;
|
|
||||||
|
|
||||||
const ready = prop(false);
|
|
||||||
const data = prop({ docs: [] });
|
|
||||||
const docs = computed(r => r.docs.map(mapper), [data], pouchDocArrayHash);
|
|
||||||
|
|
||||||
const cleanup = () => {
|
|
||||||
docs.unsubscribeAll();
|
|
||||||
ready.unsubscribeAll();
|
|
||||||
if (changeSub) {
|
|
||||||
changeSub();
|
|
||||||
changeSub = null;
|
|
||||||
}
|
|
||||||
data({ docs: [] });
|
|
||||||
};
|
|
||||||
|
|
||||||
const refresh = async function refresh(...args) {
|
|
||||||
data(await db.find({ selector }));
|
|
||||||
};
|
|
||||||
|
|
||||||
docs.ready = ready;
|
|
||||||
docs.cleanup = cleanup;
|
|
||||||
docs.selector = selector;
|
|
||||||
docs.db = db;
|
|
||||||
|
|
||||||
refresh().then(() => {
|
|
||||||
changeSub = _watcher(refresh);
|
|
||||||
ready(true);
|
|
||||||
});
|
|
||||||
return docs;
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
import { log, error } from '../services/console.js';
|
|
||||||
|
|
||||||
export function Watcher(db, selector, opts) {
|
|
||||||
const subscribers = new Set();
|
|
||||||
let changes = null;
|
|
||||||
|
|
||||||
return function subscribe(fn) {
|
|
||||||
subscribers.add(fn);
|
|
||||||
|
|
||||||
if (subscribers.size === 1 && !changes) {
|
|
||||||
log(`Watching "${db.name}" for ${JSON.stringify(selector)}`);
|
|
||||||
changes = db
|
|
||||||
.changes(
|
|
||||||
Object.assign(
|
|
||||||
{
|
|
||||||
since: 'now',
|
|
||||||
live: true,
|
|
||||||
selector
|
|
||||||
},
|
|
||||||
opts
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.on('change', change => {
|
|
||||||
const { id, deleted, doc } = change;
|
|
||||||
log(
|
|
||||||
`Change from "${db.name}" for ${JSON.stringify(selector)} ${id} ${deleted ? 'deleted' : ''}`
|
|
||||||
);
|
|
||||||
subscribers.forEach(s => s(id, !!deleted, doc));
|
|
||||||
})
|
|
||||||
.on('error', err => {
|
|
||||||
error(err);
|
|
||||||
subscribers.empty();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return () => {
|
|
||||||
subscribers.delete(fn);
|
|
||||||
if (subscribers.size === 0 && changes) {
|
|
||||||
log('Unwatching:', db, selector);
|
|
||||||
changes.cancel();
|
|
||||||
changes = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -2,8 +2,7 @@
|
|||||||
"name": "pouchorm",
|
"name": "pouchorm",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Document Abstraction Layer for PouchDB",
|
"description": "Document Abstraction Layer for PouchDB",
|
||||||
"main": "lib/index.js",
|
"main": "src/index.js",
|
||||||
"jsnext:main": "src/index.js",
|
|
||||||
"files": ["dist", "lib", "src"],
|
"files": ["dist", "lib", "src"],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node ../../bin/runTests.js ./"
|
"test": "node ../../bin/runTests.js ./"
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { LiveArray } from './livearray.js';
|
import { LiveArray } from './livearray.js';
|
||||||
|
import { Watcher } from './watcher.js';
|
||||||
import { isObject } from './utils.js';
|
import { isObject } from './utils.js';
|
||||||
|
|
||||||
export function PouchORM(PouchDB) {
|
export function PouchORM(PouchDB) {
|
||||||
@ -12,7 +13,7 @@ export function PouchORM(PouchDB) {
|
|||||||
const watch = Watcher(_db, _baseSelector, { include_docs: true });
|
const watch = Watcher(_db, _baseSelector, { include_docs: true });
|
||||||
|
|
||||||
if (!cls.hasOwnProperty('validate')) {
|
if (!cls.hasOwnProperty('validate')) {
|
||||||
warn(`${cls.name} has no validation.`);
|
// warn(`${cls.name} has no validation.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const instantiate = doc => new cls(doc);
|
const instantiate = doc => new cls(doc);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { pouchDocHash } from './utils.js';
|
import { pouchDocHash, deepAssign } from './utils.js';
|
||||||
|
|
||||||
export class TypeSpec {
|
export class TypeSpec {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|||||||
@ -11,11 +11,13 @@ const digestRoutes = (routes, baseUrl) =>
|
|||||||
return '(' + regExStr.substring(1, regExStr.lastIndexOf('/')) + ')';
|
return '(' + regExStr.substring(1, regExStr.lastIndexOf('/')) + ')';
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return Object.assign(
|
||||||
|
{
|
||||||
matcher: new RegExp(`^${baseUrl}${reg}$`),
|
matcher: new RegExp(`^${baseUrl}${reg}$`),
|
||||||
_i: i,
|
_i: i
|
||||||
...route
|
},
|
||||||
};
|
route
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export function Router(routes, baseUrl = '#') {
|
export function Router(routes, baseUrl = '#') {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user