feat(y-indexeddb): cleanup (#2207)

Co-authored-by: himself65 <himself65@outlook.com>
This commit is contained in:
三咲智子 Kevin Deng 2023-05-05 04:25:58 +08:00 committed by GitHub
parent 6d7f06c1c3
commit 52b9734a7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 11 deletions

2
.github/CLA.md vendored
View File

@ -56,5 +56,5 @@ Example:
- Skye Sun, @skyesun, 2023/04/14
- Jordy Delgado, @Jdelgad8, 2023/04/17
- Howard Do, @howarddo2208, 2023/04/20
- Kevin Deng, @sxzz, 2023/04/21
- 三咲智子 Kevin Deng, @sxzz, 2023/04/21
- Moeyua, @moeyua, 2023/04/22

View File

@ -13,6 +13,7 @@ import { applyUpdate, Doc, encodeStateAsUpdate } from 'yjs';
import type { WorkspacePersist } from '../index';
import {
CleanupWhenConnectingError,
createIndexedDBProvider,
dbVersion,
DEFAULT_DB_NAME,
@ -59,7 +60,7 @@ describe('indexeddb provider', () => {
await provider.whenSynced;
const db = await openDB(rootDBName, dbVersion);
{
const store = await db
const store = db
.transaction('workspace', 'readonly')
.objectStore('workspace');
const data = await store.get(id);
@ -161,6 +162,43 @@ describe('indexeddb provider', () => {
expect(p1).not.toBe(p2);
});
test('cleanup', async () => {
const provider = createIndexedDBProvider(workspace.id, workspace.doc);
provider.connect();
await provider.whenSynced;
const db = await openDB(rootDBName, dbVersion);
{
const store = db
.transaction('workspace', 'readonly')
.objectStore('workspace');
const keys = await store.getAllKeys();
expect(keys).contain(workspace.id);
}
provider.disconnect();
await provider.cleanup();
{
const store = db
.transaction('workspace', 'readonly')
.objectStore('workspace');
const keys = await store.getAllKeys();
expect(keys).not.contain(workspace.id);
}
});
test('cleanup when connecting', async () => {
const provider = createIndexedDBProvider(workspace.id, workspace.doc);
provider.connect();
expect(() => provider.cleanup()).rejects.toThrowError(
CleanupWhenConnectingError
);
await provider.whenSynced;
provider.disconnect();
await provider.cleanup();
});
test('merge', async () => {
setMergeCount(5);
const provider = createIndexedDBProvider(

View File

@ -90,6 +90,12 @@ export class EarlyDisconnectError extends Error {
}
}
export class CleanupWhenConnectingError extends Error {
constructor() {
super('Cleanup when connecting');
}
}
export const markMilestone = async (
id: string,
doc: Doc,
@ -144,11 +150,11 @@ export const createIndexedDBProvider = (
let resolve: () => void;
let reject: (reason?: unknown) => void;
let early = true;
let connect = false;
let connected = false;
async function handleUpdate(update: Uint8Array, origin: unknown) {
const db = await dbPromise;
if (!connect) {
if (!connected) {
return;
}
if (origin === indexeddbOrigin) {
@ -197,7 +203,7 @@ export const createIndexedDBProvider = (
upgrade: upgradeDB,
});
const handleDestroy = async () => {
connect = true;
connected = true;
const db = await dbPromise;
db.close();
};
@ -208,7 +214,7 @@ export const createIndexedDBProvider = (
resolve = _resolve;
reject = _reject;
});
connect = true;
connected = true;
doc.on('update', handleUpdate);
doc.on('destroy', handleDestroy);
// only run promise below, otherwise the logic is incorrect
@ -218,7 +224,7 @@ export const createIndexedDBProvider = (
.transaction('workspace', 'readwrite')
.objectStore('workspace');
const data = await store.get(id);
if (!connect) {
if (!connected) {
return;
}
if (!data) {
@ -267,15 +273,18 @@ export const createIndexedDBProvider = (
resolve();
},
disconnect() {
connect = false;
connected = false;
if (early) {
reject(new EarlyDisconnectError());
}
doc.off('update', handleUpdate);
doc.off('destroy', handleDestroy);
},
cleanup() {
// todo
async cleanup() {
if (connected) {
throw new CleanupWhenConnectingError();
}
(await dbPromise).delete('workspace', id);
},
whenSynced: Promise.resolve(),
};

View File

@ -11,7 +11,7 @@ export function upgradeDB(db: IDBPDatabase<BlockSuiteBinaryDB>) {
export interface IndexedDBProvider {
connect: () => void;
disconnect: () => void;
cleanup: () => void;
cleanup: () => Promise<void>;
whenSynced: Promise<void>;
}