fix(core): transform workspace db when enable cloud (#7744)

This commit is contained in:
EYHN
2024-08-05 15:17:19 +00:00
parent a03831f2a2
commit cd4e462d8c
10 changed files with 110 additions and 20 deletions

View File

@@ -6,6 +6,7 @@ import { WorkspaceDBService } from './services/db';
export { AFFiNE_WORKSPACE_DB_SCHEMA } from './schema';
export { WorkspaceDBService } from './services/db';
export { transformWorkspaceDBLocalToCloud } from './services/db';
export function configureWorkspaceDBModule(framework: Framework) {
framework

View File

@@ -2,6 +2,7 @@ import { Doc as YDoc } from 'yjs';
import { Service } from '../../../framework';
import { createORMClient, YjsDBAdapter } from '../../../orm';
import type { DocStorage } from '../../../sync';
import { ObjectPool } from '../../../utils';
import type { WorkspaceService } from '../../workspace';
import { DB, type DBWithTables } from '../entities/db';
@@ -90,3 +91,29 @@ export class WorkspaceDBService extends Service {
return docId.startsWith('db$') || docId.startsWith('userdata$');
}
}
export async function transformWorkspaceDBLocalToCloud(
localWorkspaceId: string,
cloudWorkspaceId: string,
localDocStorage: DocStorage,
cloudDocStorage: DocStorage,
accountId: string
) {
for (const tableName of Object.keys(AFFiNE_WORKSPACE_DB_SCHEMA)) {
const localDocName = `db$${localWorkspaceId}$${tableName}`;
const localDoc = await localDocStorage.doc.get(localDocName);
if (localDoc) {
const cloudDocName = `db$${cloudWorkspaceId}$${tableName}`;
await cloudDocStorage.doc.set(cloudDocName, localDoc);
}
}
for (const tableName of Object.keys(AFFiNE_WORKSPACE_USERDATA_DB_SCHEMA)) {
const localDocName = `userdata$__local__$${localWorkspaceId}$${tableName}`;
const localDoc = await localDocStorage.doc.get(localDocName);
if (localDoc) {
const cloudDocName = `userdata$${accountId}$${cloudWorkspaceId}$${tableName}`;
await cloudDocStorage.doc.set(cloudDocName, localDoc);
}
}
}

View File

@@ -28,7 +28,8 @@ export interface WorkspaceFlavourProvider {
createWorkspace(
initial: (
docCollection: DocCollection,
blobStorage: BlobStorage
blobStorage: BlobStorage,
docStorage: DocStorage
) => Promise<void>
): Promise<WorkspaceMetadata>;

View File

@@ -2,7 +2,7 @@ import type { WorkspaceFlavour } from '@affine/env/workspace';
import type { DocCollection } from '@blocksuite/store';
import { Service } from '../../../framework';
import type { BlobStorage } from '../../../sync';
import type { BlobStorage, DocStorage } from '../../../sync';
import type { WorkspaceFlavourProvider } from '../providers/flavour';
export class WorkspaceFactoryService extends Service {
@@ -20,7 +20,8 @@ export class WorkspaceFactoryService extends Service {
flavour: WorkspaceFlavour,
initial: (
docCollection: DocCollection,
blobStorage: BlobStorage
blobStorage: BlobStorage,
docStorage: DocStorage
) => Promise<void> = () => Promise.resolve()
) => {
const provider = this.providers.find(x => x.flavour === flavour);

View File

@@ -3,6 +3,7 @@ import { assertEquals } from '@blocksuite/global/utils';
import { applyUpdate, encodeStateAsUpdate } from 'yjs';
import { Service } from '../../../framework';
import { transformWorkspaceDBLocalToCloud } from '../../db';
import type { Workspace } from '../entities/workspace';
import type { WorkspaceMetadata } from '../metadata';
import type { WorkspaceDestroyService } from './destroy';
@@ -18,9 +19,12 @@ export class WorkspaceTransformService extends Service {
/**
* helper function to transform local workspace to cloud workspace
*
* @param accountId - all local user data will be transformed to this account
*/
transformLocalToCloud = async (
local: Workspace
local: Workspace,
accountId: string
): Promise<WorkspaceMetadata> => {
assertEquals(local.flavour, WorkspaceFlavour.LOCAL);
@@ -28,23 +32,35 @@ export class WorkspaceTransformService extends Service {
const newMetadata = await this.factory.create(
WorkspaceFlavour.AFFINE_CLOUD,
async (ws, bs) => {
applyUpdate(ws.doc, encodeStateAsUpdate(local.docCollection.doc));
async (docCollection, blobStorage, docStorage) => {
applyUpdate(
docCollection.doc,
encodeStateAsUpdate(local.docCollection.doc)
);
for (const subdoc of local.docCollection.doc.getSubdocs()) {
for (const newSubdoc of ws.doc.getSubdocs()) {
for (const newSubdoc of docCollection.doc.getSubdocs()) {
if (newSubdoc.guid === subdoc.guid) {
applyUpdate(newSubdoc, encodeStateAsUpdate(subdoc));
}
}
}
// transform db
await transformWorkspaceDBLocalToCloud(
local.id,
docCollection.id,
local.engine.doc.storage.behavior,
docStorage,
accountId
);
const blobList = await local.engine.blob.list();
for (const blobKey of blobList) {
const blob = await local.engine.blob.get(blobKey);
if (blob) {
await bs.set(blobKey, blob);
await blobStorage.set(blobKey, blob);
}
}
}

View File

@@ -6,7 +6,11 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs';
import { Service } from '../../../framework';
import { LiveData } from '../../../livedata';
import { wrapMemento } from '../../../storage';
import { type BlobStorage, MemoryDocStorage } from '../../../sync';
import {
type BlobStorage,
type DocStorage,
MemoryDocStorage,
} from '../../../sync';
import { MemoryBlobStorage } from '../../../sync/blob/blob';
import type { GlobalState } from '../../storage';
import type { WorkspaceProfileInfo } from '../entities/profile';
@@ -39,7 +43,8 @@ export class TestingWorkspaceLocalProvider
async createWorkspace(
initial: (
docCollection: DocCollection,
blobStorage: BlobStorage
blobStorage: BlobStorage,
docStorage: DocStorage
) => Promise<void>
): Promise<WorkspaceMetadata> {
const id = nanoid();
@@ -59,7 +64,7 @@ export class TestingWorkspaceLocalProvider
});
// apply initial state
await initial(docCollection, blobStorage);
await initial(docCollection, blobStorage, this.docStorage);
// save workspace to storage
await this.docStorage.doc.set(id, encodeStateAsUpdate(docCollection.doc));