Skip to content

Commit

Permalink
Made it possible to reach the Y.Doc cache from addons or outside dexie:
Browse files Browse the repository at this point in the history
* To lookup whether a certain document is open and find it
  • Loading branch information
dfahlander committed Jul 28, 2024
1 parent 54ef0e7 commit c013c51
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 25 deletions.
9 changes: 9 additions & 0 deletions src/public/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,17 @@ export function remove(num: number | bigint | any[]): PropModification;
declare var DexieYProvider: {
(doc: DucktypedYDoc): DexieYProvider;
new (doc: DucktypedYDoc): DexieYProvider;
getDocCache: (db: Dexie) => {
cache: { [key: string]: WeakRef<DucktypedYDoc> };
readonly size: number;
find: (updatesTable: string, parentId: any) => DucktypedYDoc | undefined;
add: (doc: DucktypedYDoc) => void;
delete: (doc: DucktypedYDoc) => void;
};
}

export { DexieYProvider, RangeSet };

/** Exporting 'Dexie' as the default export.
**/
export default Dexie;
14 changes: 8 additions & 6 deletions src/yjs/DexieYProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import type {
DexieYProvider,
DucktypedYDoc,
} from '../public/types/yjs-related';
import { throwIfDestroyed } from './docCache';
import { throwIfDestroyed, getDocCache } from './docCache';
import { getYLibrary } from './getYLibrary';
import { observeYDocUpdates } from './observeYDocUpdates';

export function DexieYProvider (doc: DucktypedYDoc): DexieYProvider {
const { guid, collectionid: updatesTable, meta: { db, table }} =
const { meta: { db, parentTable, parentId, updatesTable }} =
(doc as DucktypedYDoc) || {};
if (!db || !table || !updatesTable)
if (!db || !parentTable || !updatesTable)
throw new Error('Y.Doc not generated by Dexie');
if (!db.table(table) || !db.table(updatesTable)) {
throw new Error(`Table ${table} or ${updatesTable} not found in db`);
if (!db.table(parentTable) || !db.table(updatesTable)) {
throw new Error(`Table ${parentTable} or ${updatesTable} not found in db`);
}
throwIfDestroyed(doc);
const Y = getYLibrary(db);
Expand All @@ -41,9 +41,11 @@ export function DexieYProvider (doc: DucktypedYDoc): DexieYProvider {
on = this.on = createEvents(); // Releases listeners for GC
}
};
const stopObserving = observeYDocUpdates(provider, doc, db, table, updatesTable, guid, Y);
const stopObserving = observeYDocUpdates(provider, doc, db, parentTable, updatesTable, parentId, Y);
doc.on('destroy', provider.destroy.bind(provider));
db.on.y.fire(provider, Y); // Allow for addons to invoke their sync- and awareness providers here.

return provider;
}

DexieYProvider.getDocCache = getDocCache;
27 changes: 12 additions & 15 deletions src/yjs/createYDocProperty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,37 @@ import type { Table } from '../public/types/table';
import type { Dexie } from '../public/types/dexie';
import type { DexieYDocMeta, DucktypedY } from '../public/types/yjs-related';
import { getByKeyPath } from '../functions/utils';
import { docCache, destroyed, registry } from './docCache';
import { destroyed, getDocCache } from './docCache';

export function createYDocProperty(
db: Dexie,
Y: DucktypedY,
table: Table,
prop: string,
updatesTable: string
) {
const pkKeyPath = table.schema.primKey.keyPath;
const docCache = getDocCache(db);
return {
get(this: object) {
const id = getByKeyPath(this, pkKeyPath);
const cacheKey = `${table.name}[${id}].${prop}`;
let docRef = docCache[cacheKey];
if (docRef) return docRef.deref();

const doc = new Y.Doc({
collectionid: updatesTable,
guid: ''+id,
let doc = docCache.find(updatesTable, id);
if (doc) return doc;

doc = new Y.Doc({
meta: {
db,
table: table.name,
cacheKey,
} as DexieYDocMeta,
updatesTable,
parentTable: table.name,
parentId: id
} satisfies DexieYDocMeta,
});

docCache[cacheKey] = new WeakRef(doc);
registry.register(doc, cacheKey);
docCache.add(doc);

doc.on('destroy', () => {
destroyed.add(doc);
registry.unregister(doc);
delete docCache[cacheKey];
docCache.delete(doc);
});

return doc;
Expand Down
40 changes: 36 additions & 4 deletions src/yjs/docCache.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
import { Dexie } from '../public/types/dexie';
import type { DucktypedYDoc } from '../public/types/yjs-related';

// The cache
export let docCache: { [key: string]: WeakRef<DucktypedYDoc>; } = {};
// The Y.Doc cache containing all active documents
export function getDocCache(db: Dexie) {
return db._novip['_docCache'] ??= {
cache: {} as { [key: string]: WeakRef<DucktypedYDoc>; },
get size() {
return Object.keys(this.cache).length;
},
find(updatesTable: string, parentId: any): DucktypedYDoc | undefined {
const cacheKey = getYDocCacheKey(updatesTable, parentId);
const docRef = this.cache[cacheKey];
return docRef ? docRef.deref() : undefined;
},
add(doc: DucktypedYDoc): void {
const { updatesTable, parentId } = doc.meta;
if (!updatesTable || parentId == null)
throw new Error(`Missing Dexie-related metadata in Y.Doc`);
const cacheKey = getYDocCacheKey(updatesTable, parentId);
this.cache[cacheKey] = new WeakRef(doc);
docRegistry.register(doc, { cache: this.cache, key: cacheKey });
},
delete(doc: DucktypedYDoc): void {
docRegistry.unregister(doc);
delete this.cache[
getYDocCacheKey(doc.meta.updatesTable, doc.meta.parentId)
];
},
};
}
//export let docCache: { [key: string]: WeakRef<DucktypedYDoc>; } = {};
// The finalization registry
export const registry = new FinalizationRegistry<string>((heldValue) => {
delete docCache[heldValue];
const docRegistry = new FinalizationRegistry<{cache: any, key: string}>(({cache, key}) => {
delete cache[key];
});
// The weak map
//export const doc2ProviderWeakMap = new WeakMap<object, WeakRef<DexieYProvider<any>>>();
Expand All @@ -14,3 +42,7 @@ export function throwIfDestroyed(doc: object) {
if (destroyed.has(doc))
throw new Error('Y.Doc has been destroyed');
}

export function getYDocCacheKey(yTable: string, parentId: any): string {
return `${yTable}[${parentId}]`;
}

0 comments on commit c013c51

Please sign in to comment.