feat(y-indexeddb): remove id (#2810)

This commit is contained in:
Alex Yang 2023-06-17 13:58:48 +08:00 committed by GitHub
parent deeafb3a12
commit c68220166a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 68 deletions

View File

@ -66,7 +66,7 @@ export const CRUD: WorkspaceCRUD<WorkspaceFlavour.LOCAL> = {
WorkspaceFlavour.LOCAL
);
BlockSuiteWorkspace.Y.applyUpdateV2(blockSuiteWorkspace.doc, binary);
const persistence = createIndexedDBProvider(id, blockSuiteWorkspace.doc);
const persistence = createIndexedDBProvider(blockSuiteWorkspace.doc);
persistence.connect();
await persistence.whenSynced.then(() => {
persistence.disconnect();

View File

@ -82,10 +82,7 @@ const createAffineWebSocketProvider = (
const createIndexedDBBackgroundProvider = (
blockSuiteWorkspace: BlockSuiteWorkspace
): LocalIndexedDBBackgroundProvider => {
const indexeddbProvider = create(
blockSuiteWorkspace.id,
blockSuiteWorkspace.doc
);
const indexeddbProvider = create(blockSuiteWorkspace.doc);
const callbacks = new CallbackSet();
return {
flavour: 'local-indexeddb-background',

View File

@ -1,14 +1,24 @@
# @toeverything/y-indexeddb
## Features
- persistence data in indexeddb
- sub-documents support
- fully TypeScript
## Usage
```ts
import { createIndexedDBProvider, downloadBinary } from '@toeverything/y-indexeddb';
import * as Y from 'yjs';
const yDoc = new Y.Doc();
const yDoc = new Y.Doc({
// we use `guid` as unique key
guid: 'my-doc',
});
// sync yDoc with indexedDB
const provider = createIndexedDBProvider('docName', yDoc);
const provider = createIndexedDBProvider(yDoc);
provider.connect();
await provider.whenSynced.then(() => {
console.log('synced');
@ -16,7 +26,7 @@ await provider.whenSynced.then(() => {
});
// dowload binary data from indexedDB for once
downloadBinary('docName').then(blob => {
downloadBinary(yDoc.guid).then(blob => {
if (blob !== false) {
Y.applyUpdate(yDoc, blob);
}

View File

@ -70,7 +70,7 @@ afterEach(() => {
describe('indexeddb provider', () => {
test('connect', async () => {
const provider = createIndexedDBProvider(workspace.id, workspace.doc);
const provider = createIndexedDBProvider(workspace.doc);
provider.connect();
await provider.whenSynced;
const db = await openDB(rootDBName, dbVersion);
@ -119,11 +119,7 @@ describe('indexeddb provider', () => {
})
.register(AffineSchemas)
.register(__unstableSchemas);
const provider2 = createIndexedDBProvider(
secondWorkspace.id,
secondWorkspace.doc,
rootDBName
);
const provider2 = createIndexedDBProvider(secondWorkspace.doc, rootDBName);
provider2.connect();
await provider2.whenSynced;
expect(Workspace.Y.encodeStateAsUpdate(secondWorkspace.doc)).toEqual(
@ -132,11 +128,7 @@ describe('indexeddb provider', () => {
});
test('disconnect suddenly', async () => {
const provider = createIndexedDBProvider(
workspace.id,
workspace.doc,
rootDBName
);
const provider = createIndexedDBProvider(workspace.doc, rootDBName);
const fn = vi.fn();
provider.connect();
provider.disconnect();
@ -146,11 +138,7 @@ describe('indexeddb provider', () => {
});
test('connect and disconnect', async () => {
const provider = createIndexedDBProvider(
workspace.id,
workspace.doc,
rootDBName
);
const provider = createIndexedDBProvider(workspace.doc, rootDBName);
provider.connect();
expect(provider.connected).toBe(true);
const p1 = provider.whenSynced;
@ -186,7 +174,7 @@ describe('indexeddb provider', () => {
});
test('cleanup', async () => {
const provider = createIndexedDBProvider(workspace.id, workspace.doc);
const provider = createIndexedDBProvider(workspace.doc);
provider.connect();
await provider.whenSynced;
const db = await openDB(rootDBName, dbVersion);
@ -212,7 +200,7 @@ describe('indexeddb provider', () => {
});
test('cleanup when connecting', async () => {
const provider = createIndexedDBProvider(workspace.id, workspace.doc);
const provider = createIndexedDBProvider(workspace.doc);
provider.connect();
await expect(() => provider.cleanup()).rejects.toThrowError(
CleanupWhenConnectingError
@ -224,11 +212,7 @@ describe('indexeddb provider', () => {
test('merge', async () => {
setMergeCount(5);
const provider = createIndexedDBProvider(
workspace.id,
workspace.doc,
rootDBName
);
const provider = createIndexedDBProvider(workspace.doc, rootDBName);
provider.connect();
{
const page = workspace.createPage({ id: 'page0' });
@ -247,21 +231,20 @@ describe('indexeddb provider', () => {
});
test("data won't be lost", async () => {
const id = uuidv4();
const doc = new Workspace.Y.Doc();
const map = doc.getMap('map');
for (let i = 0; i < 100; i++) {
map.set(`${i}`, i);
}
{
const provider = createIndexedDBProvider(id, doc, rootDBName);
const provider = createIndexedDBProvider(doc, rootDBName);
provider.connect();
await provider.whenSynced;
provider.disconnect();
}
{
const newDoc = new Workspace.Y.Doc();
const provider = createIndexedDBProvider(id, newDoc, rootDBName);
const provider = createIndexedDBProvider(newDoc, rootDBName);
provider.connect();
await provider.whenSynced;
provider.disconnect();
@ -280,8 +263,10 @@ describe('indexeddb provider', () => {
await persistence.destroy();
}
{
const yDoc = new Doc();
const provider = createIndexedDBProvider('test', yDoc);
const yDoc = new Doc({
guid: 'test',
});
const provider = createIndexedDBProvider(yDoc);
provider.connect();
await provider.whenSynced;
await new Promise(resolve => setTimeout(resolve, 0));
@ -293,9 +278,11 @@ describe('indexeddb provider', () => {
throw new Error('not supported');
});
await expect(indexedDB.databases).rejects.toThrow('not supported');
const yDoc = new Doc();
const yDoc = new Doc({
guid: 'test',
});
expect(indexedDB.databases).toBeCalledTimes(1);
const provider = createIndexedDBProvider('test', yDoc);
const provider = createIndexedDBProvider(yDoc);
provider.connect();
await provider.whenSynced;
expect(indexedDB.databases).toBeCalledTimes(2);
@ -314,8 +301,10 @@ describe('indexeddb provider', () => {
expect(event).toBe('beforeunload');
return oldRemoveEventListener(event, fn, options);
});
const doc = new Doc();
const provider = createIndexedDBProvider('1', doc);
const doc = new Doc({
guid: '1',
});
const provider = createIndexedDBProvider(doc);
const map = doc.getMap('map');
map.set('1', 1);
provider.connect();
@ -394,21 +383,25 @@ describe('subDoc', () => {
test('basic', async () => {
let json1: any, json2: any;
{
const doc = new Doc();
const doc = new Doc({
guid: 'test',
});
const map = doc.getMap();
const subDoc = new Doc();
subDoc.load();
map.set('1', subDoc);
map.set('2', 'test');
const provider = createIndexedDBProvider('test', doc);
const provider = createIndexedDBProvider(doc);
provider.connect();
await provider.whenSynced;
provider.disconnect();
json1 = doc.toJSON();
}
{
const doc = new Doc();
const provider = createIndexedDBProvider('test', doc);
const doc = new Doc({
guid: 'test',
});
const provider = createIndexedDBProvider(doc);
provider.connect();
await provider.whenSynced;
const map = doc.getMap();
@ -427,11 +420,7 @@ describe('subDoc', () => {
});
await page0.waitForLoaded();
const { paragraphBlockId: paragraphBlockIdPage1 } = initEmptyPage(page0);
const provider = createIndexedDBProvider(
workspace.id,
workspace.doc,
rootDBName
);
const provider = createIndexedDBProvider(workspace.doc, rootDBName);
provider.connect();
const page1 = workspace.createPage({
id: 'page1',
@ -446,11 +435,7 @@ describe('subDoc', () => {
isSSR: true,
});
newWorkspace.register(AffineSchemas).register(__unstableSchemas);
const provider = createIndexedDBProvider(
newWorkspace.id,
newWorkspace.doc,
rootDBName
);
const provider = createIndexedDBProvider(newWorkspace.doc, rootDBName);
provider.connect();
await provider.whenSynced;
const page0 = newWorkspace.getPage('page0') as Page;
@ -474,11 +459,7 @@ describe('utils', () => {
const page = workspace.createPage({ id: 'page0' });
await page.waitForLoaded();
initEmptyPage(page);
const provider = createIndexedDBProvider(
workspace.id,
workspace.doc,
rootDBName
);
const provider = createIndexedDBProvider(workspace.doc, rootDBName);
provider.connect();
await provider.whenSynced;
provider.disconnect();

View File

@ -148,10 +148,16 @@ type SubDocsEvent = {
loaded: Set<Doc>;
};
/**
* We use `doc.guid` as the unique key, please make sure it not changes.
*/
export const createIndexedDBProvider = (
id: string,
doc: Doc,
dbName: string = DEFAULT_DB_NAME
dbName: string = DEFAULT_DB_NAME,
/**
* In the future, migrate will be removed and there will be a separate function
*/
migrate = true
): IndexedDBProvider => {
let resolve: () => void;
let reject: (reason?: unknown) => void;
@ -336,15 +342,21 @@ export const createIndexedDBProvider = (
reject = _reject;
});
connected = true;
trackDoc(id, doc);
trackDoc(doc.guid, doc);
// only the runs `await` below, otherwise the logic is incorrect
const db = await dbPromise;
await tryMigrate(db, id, dbName);
if (migrate) {
// Tips:
// this is only backward compatible with the yjs official version of y-indexeddb
await tryMigrate(db, doc.guid, dbName);
}
if (!connected) {
return;
}
// recursively save all docs into indexeddb
const docs: [string, Doc][] = [];
docs.push([id, doc]);
docs.push([doc.guid, doc]);
while (docs.length > 0) {
const [id, doc] = docs.pop() as [string, Doc];
await saveDocOperation(id, doc);
@ -361,13 +373,13 @@ export const createIndexedDBProvider = (
if (early) {
reject(new EarlyDisconnectError());
}
unTrackDoc(id, doc);
unTrackDoc(doc.guid, doc);
},
async cleanup() {
if (connected) {
throw new CleanupWhenConnectingError();
}
await (await dbPromise).delete('workspace', id);
await (await dbPromise).delete('workspace', doc.guid);
},
whenSynced: Promise.resolve(),
get connected() {

View File

@ -128,7 +128,7 @@ export async function tryMigrate(
}
export async function downloadBinary(
id: string,
guid: string,
dbName = DEFAULT_DB_NAME
): Promise<UpdateMessage['update'] | false> {
const dbPromise = openDB<BlockSuiteBinaryDB>(dbName, dbVersion, {
@ -136,7 +136,7 @@ export async function downloadBinary(
});
const db = await dbPromise;
const t = db.transaction('workspace', 'readonly').objectStore('workspace');
const doc = await t.get(id);
const doc = await t.get(guid);
if (!doc) {
return false;
} else {