LiveArray can manage it's own watchers (across dbs even)
This commit is contained in:
parent
8c138571c2
commit
5c433f1231
@ -18,12 +18,10 @@ export function GalleryView(vm, model) {
|
|||||||
const NAV_OPTIONS = {
|
const NAV_OPTIONS = {
|
||||||
images: {
|
images: {
|
||||||
selector: image.SELECTOR,
|
selector: image.SELECTOR,
|
||||||
watcher: image.watcher,
|
|
||||||
title: 'Images'
|
title: 'Images'
|
||||||
},
|
},
|
||||||
albums: {
|
albums: {
|
||||||
selector: index.SELECTOR,
|
selector: index.SELECTOR,
|
||||||
watcher: Watcher(db, index.SELECTOR),
|
|
||||||
title: 'Albums'
|
title: 'Albums'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -36,7 +34,7 @@ export function GalleryView(vm, model) {
|
|||||||
data.cleanup();
|
data.cleanup();
|
||||||
}
|
}
|
||||||
const o = NAV_OPTIONS[route.name];
|
const o = NAV_OPTIONS[route.name];
|
||||||
data = LiveArray(db, o.selector, o.watcher);
|
data = LiveArray(db, o.selector);
|
||||||
title = o.title;
|
title = o.title;
|
||||||
data.subscribe(() => vm.redraw());
|
data.subscribe(() => vm.redraw());
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,12 +6,15 @@ import { Watcher } from './watcher.js';
|
|||||||
import { pouchDocArrayComparator } from './comparators.js';
|
import { pouchDocArrayComparator } from './comparators.js';
|
||||||
import { difference } from './set.js';
|
import { difference } from './set.js';
|
||||||
|
|
||||||
// The point of the globalWatcher mechanism is that PouchDB.changes doesn't register when a document changes in such a way that removes it from the selector specifications.
|
// The point of the watcher mechanism is that PouchDB.changes doesn't register
|
||||||
// For Example: a selector looks for images with a specific tag. If a change removes that tag, the changes API will not register a change event. globalWatcher watches the document IDs for exactly this type of change and triggers the LiveArray to refresh.
|
// when a document changes in such a way that removes it from the selector
|
||||||
|
// specifications. For Example: a selector looks for images with a specific
|
||||||
const globalWatcher = Watcher(getDatabase(), {}, true);
|
// tag. If a change removes that tag, the changes API will not register a change
|
||||||
|
// event. globalWatcher watches the document IDs for exactly this type of
|
||||||
|
// change and triggers the LiveArray to refresh.
|
||||||
|
const watcherMap = new Map();
|
||||||
const watchingIDs = new Map();
|
const watchingIDs = new Map();
|
||||||
let globalWatcherSubscription = null;
|
const dbIDs = new Map();
|
||||||
|
|
||||||
function checkDocs(id, deleted, doc) {
|
function checkDocs(id, deleted, doc) {
|
||||||
// Is the changed doc one that we're watching?
|
// Is the changed doc one that we're watching?
|
||||||
@ -25,42 +28,53 @@ function checkDocs(id, deleted, doc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addID(id, selector, refresher) {
|
function addID(db, id, selector, refresher) {
|
||||||
|
if (!watcherMap.has(db)) {
|
||||||
|
watcherMap.set(db, Watcher(db, {}, true)(checkDocs));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dbIDs.has(db)) {
|
||||||
|
dbIDs.set(db, new Set());
|
||||||
|
}
|
||||||
|
dbIDs.get(db).add(id);
|
||||||
|
|
||||||
if (!watchingIDs.has(id)) {
|
if (!watchingIDs.has(id)) {
|
||||||
watchingIDs.set(id, new Map());
|
watchingIDs.set(id, new Map());
|
||||||
}
|
}
|
||||||
watchingIDs.get(id).set(selector, refresher);
|
watchingIDs.get(id).set(selector, refresher);
|
||||||
if (globalWatcherSubscription === null) {
|
|
||||||
globalWatcherSubscription = globalWatcher(checkDocs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeID(id, selector) {
|
function removeID(db, id, selector) {
|
||||||
if (watchingIDs.has(id)) {
|
if (watchingIDs.has(id)) {
|
||||||
const idSet = watchingIDs.get(id);
|
const idSet = watchingIDs.get(id);
|
||||||
idSet.delete(selector);
|
idSet.delete(selector);
|
||||||
if (idSet.size === 0) {
|
if (idSet.size === 0) {
|
||||||
watchingIDs.delete(selector);
|
watchingIDs.delete(selector);
|
||||||
if (watchingIDs.size === 0) {
|
|
||||||
globalWatcherSubscription();
|
|
||||||
globalWatcherSubscription = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dbIDMap = dbIDs.get(db);
|
||||||
|
dbIDMap.delete(id);
|
||||||
|
if (dbIDMap.size === 0) {
|
||||||
|
// Unsubscribe from this watcher
|
||||||
|
watcherMap.get(db)();
|
||||||
|
dbIDs.delete(db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LiveArray is a subscribable property function that always returns the db results that match the provided selector and calls subscribers when the results change.
|
// 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, watcher) {
|
export function LiveArray(db, selector, mapper) {
|
||||||
const _watcher = watcher || Watcher(db, selector);
|
const _watcher = Watcher(db, selector);
|
||||||
let changeSub = null;
|
let changeSub = null;
|
||||||
|
let _mapper = mapper || (doc => doc);
|
||||||
|
|
||||||
const ready = prop(false);
|
const ready = prop(false);
|
||||||
const data = prop({ docs: [] });
|
const data = prop({ docs: [] });
|
||||||
const docs = computed(r => r.docs, [data], pouchDocArrayComparator);
|
const docs = computed(r => r.docs.map(_mapper), [data], pouchDocArrayComparator);
|
||||||
|
|
||||||
const idSet = () => docs().reduce((acc, d) => acc.add(d._id), new Set());
|
const idSet = () => docs().reduce((acc, d) => acc.add(d._id), new Set());
|
||||||
const addThisID = id => addID(id, selector, refresh);
|
const addThisID = id => addID(db, id, selector, refresh);
|
||||||
const removeThisID = id => removeID(id, selector);
|
const removeThisID = id => removeID(db, id, selector);
|
||||||
|
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
docs.unsubscribeAll();
|
docs.unsubscribeAll();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user