diff --git a/packages/gallery/package.json b/packages/gallery/package.json index eb9e897..be34ceb 100644 --- a/packages/gallery/package.json +++ b/packages/gallery/package.json @@ -14,7 +14,7 @@ "domvm": "~3.2.1", "exif-parser": "~0.1.9", "extract-text-webpack-plugin": "^3.0.2", - "frptools": "3.1.0", + "frptools": "3.1.1", "linear-partitioning": "0.3.2", "pica": "~2.0.8", "pouchdb-adapter-http": "~6.4.1", @@ -24,6 +24,7 @@ "pouchdb-core": "~6.4.1", "pouchdb-find": "~6.4.1", "pouchdb-replication": "~6.4.1", + "pouchorm": "~1.0.0", "router": "2.1.0", "semantic-ui-reset": "^2.2.12", "semantic-ui-site": "^2.2.12", diff --git a/packages/gallery/src/data/album.js b/packages/gallery/src/data/album.js index 8a7f7a9..bdc5c0f 100644 --- a/packages/gallery/src/data/album.js +++ b/packages/gallery/src/data/album.js @@ -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 { extractID } from '../utils/conversion.js'; diff --git a/packages/gallery/src/data/file.js b/packages/gallery/src/data/file.js index 0319556..b511af7 100644 --- a/packages/gallery/src/data/file.js +++ b/packages/gallery/src/data/file.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 { blobToArrayBuffer } from '../utils/conversion.js'; diff --git a/packages/gallery/src/data/image.js b/packages/gallery/src/data/image.js index a74a144..b79d535 100644 --- a/packages/gallery/src/data/image.js +++ b/packages/gallery/src/data/image.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 { backgroundTask } from '../utils/event.js'; import { FileType } from './file.js'; diff --git a/packages/gallery/src/services/db.js b/packages/gallery/src/services/db.js index 5d0ddc4..98627e5 100644 --- a/packages/gallery/src/services/db.js +++ b/packages/gallery/src/services/db.js @@ -4,11 +4,7 @@ import http from 'pouchdb-adapter-http'; import replication from 'pouchdb-replication'; import find from 'pouchdb-find'; -import { log, warn } from './console.js'; -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'; +import { PouchORM } from 'pouchorm'; export const PouchDB = core .plugin(idb) @@ -16,168 +12,3 @@ export const PouchDB = core .plugin(replication) .plugin(find) .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; - }; -} diff --git a/packages/gallery/src/utils/livearray.js b/packages/gallery/src/utils/livearray.js deleted file mode 100644 index 88a338d..0000000 --- a/packages/gallery/src/utils/livearray.js +++ /dev/null @@ -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; -} diff --git a/packages/gallery/src/utils/watcher.js b/packages/gallery/src/utils/watcher.js deleted file mode 100644 index 8d3bc5a..0000000 --- a/packages/gallery/src/utils/watcher.js +++ /dev/null @@ -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; - } - }; - }; -} diff --git a/packages/pouchorm/package.json b/packages/pouchorm/package.json index 45eba91..2b1226e 100644 --- a/packages/pouchorm/package.json +++ b/packages/pouchorm/package.json @@ -2,8 +2,7 @@ "name": "pouchorm", "version": "1.0.0", "description": "Document Abstraction Layer for PouchDB", - "main": "lib/index.js", - "jsnext:main": "src/index.js", + "main": "src/index.js", "files": ["dist", "lib", "src"], "scripts": { "test": "node ../../bin/runTests.js ./" diff --git a/packages/pouchorm/src/plugin.js b/packages/pouchorm/src/plugin.js index af8ef41..896ab08 100644 --- a/packages/pouchorm/src/plugin.js +++ b/packages/pouchorm/src/plugin.js @@ -1,4 +1,5 @@ import { LiveArray } from './livearray.js'; +import { Watcher } from './watcher.js'; import { isObject } from './utils.js'; export function PouchORM(PouchDB) { @@ -12,7 +13,7 @@ export function PouchORM(PouchDB) { const watch = Watcher(_db, _baseSelector, { include_docs: true }); if (!cls.hasOwnProperty('validate')) { - warn(`${cls.name} has no validation.`); + // warn(`${cls.name} has no validation.`); } const instantiate = doc => new cls(doc); diff --git a/packages/pouchorm/src/type.js b/packages/pouchorm/src/type.js index 8c210da..377ca26 100644 --- a/packages/pouchorm/src/type.js +++ b/packages/pouchorm/src/type.js @@ -1,4 +1,4 @@ -import { pouchDocHash } from './utils.js'; +import { pouchDocHash, deepAssign } from './utils.js'; export class TypeSpec { constructor(props) { diff --git a/packages/router/src/index.js b/packages/router/src/index.js index 6ccc02b..3800e4d 100644 --- a/packages/router/src/index.js +++ b/packages/router/src/index.js @@ -11,11 +11,13 @@ const digestRoutes = (routes, baseUrl) => return '(' + regExStr.substring(1, regExStr.lastIndexOf('/')) + ')'; }); - return { - matcher: new RegExp(`^${baseUrl}${reg}$`), - _i: i, - ...route - }; + return Object.assign( + { + matcher: new RegExp(`^${baseUrl}${reg}$`), + _i: i + }, + route + ); }); export function Router(routes, baseUrl = '#') {