Skip to content

Commit

Permalink
fix(core): transform workspace db when enable cloud (#7744)
Browse files Browse the repository at this point in the history
  • Loading branch information
EYHN committed Aug 5, 2024
1 parent a03831f commit cd4e462
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 20 deletions.
1 change: 1 addition & 0 deletions packages/common/infra/src/modules/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions packages/common/infra/src/modules/db/services/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export interface WorkspaceFlavourProvider {
createWorkspace(
initial: (
docCollection: DocCollection,
blobStorage: BlobStorage
blobStorage: BlobStorage,
docStorage: DocStorage
) => Promise<void>
): Promise<WorkspaceMetadata>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);
Expand Down
26 changes: 21 additions & 5 deletions packages/common/infra/src/modules/workspace/services/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -18,33 +19,48 @@ 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);

await local.engine.waitForDocSynced();

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);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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();
Expand All @@ -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));
Expand Down
10 changes: 8 additions & 2 deletions packages/frontend/core/src/hooks/affine/use-enable-cloud.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type ConfirmEnableArgs = [Workspace, ConfirmEnableCloudOptions | undefined];

export const useEnableCloud = () => {
const t = useI18n();
const authService = useService(AuthService);
const account = useLiveData(authService.session.account$);
const loginStatus = useLiveData(useService(AuthService).session.status$);
const setAuthAtom = useSetAtom(authAtom);
const { openConfirmModal, closeConfirmModal } = useConfirmModal();
Expand All @@ -39,7 +41,11 @@ export const useEnableCloud = () => {
async (ws: Workspace | null, options?: ConfirmEnableCloudOptions) => {
try {
if (!ws) return;
const { id: newId } = await workspacesService.transformLocalToCloud(ws);
if (!account) return;
const { id: newId } = await workspacesService.transformLocalToCloud(
ws,
account.id
);
openPage(newId, options?.openPageId || WorkspaceSubPath.ALL);
options?.onSuccess?.();
} catch (e) {
Expand All @@ -49,7 +55,7 @@ export const useEnableCloud = () => {
});
}
},
[openPage, t, workspacesService]
[account, openPage, t, workspacesService]
);

const openSignIn = useCallback(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ApplicationStarted,
type BlobStorage,
catchErrorInto,
type DocStorage,
exhaustMapSwitchUntilChanged,
fromPromise,
type GlobalState,
Expand Down Expand Up @@ -77,11 +78,10 @@ export class CloudWorkspaceFlavourProviderService
async createWorkspace(
initial: (
docCollection: DocCollection,
blobStorage: BlobStorage
blobStorage: BlobStorage,
docStorage: DocStorage
) => Promise<void>
): Promise<WorkspaceMetadata> {
const tempId = nanoid();

// create workspace on cloud, get workspace id
const {
createWorkspace: { id: workspaceId },
Expand All @@ -94,7 +94,7 @@ export class CloudWorkspaceFlavourProviderService
const docStorage = this.storageProvider.getDocStorage(workspaceId);

const docCollection = new DocCollection({
id: tempId,
id: workspaceId,
idGenerator: () => nanoid(),
schema: globalBlockSuiteSchema,
blobSources: {
Expand All @@ -103,7 +103,7 @@ export class CloudWorkspaceFlavourProviderService
});

// apply initial state
await initial(docCollection, blobStorage);
await initial(docCollection, blobStorage, docStorage);

// save workspace to local storage, should be vary fast
await docStorage.doc.set(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { WorkspaceFlavour } from '@affine/env/workspace';
import { DocCollection } from '@blocksuite/store';
import type {
BlobStorage,
DocStorage,
WorkspaceEngineProvider,
WorkspaceFlavourProvider,
WorkspaceMetadata,
Expand Down Expand Up @@ -56,7 +57,8 @@ export class LocalWorkspaceFlavourProvider
async createWorkspace(
initial: (
docCollection: DocCollection,
blobStorage: BlobStorage
blobStorage: BlobStorage,
docStorage: DocStorage
) => Promise<void>
): Promise<WorkspaceMetadata> {
const id = nanoid();
Expand All @@ -73,7 +75,7 @@ export class LocalWorkspaceFlavourProvider
});

// apply initial state
await initial(docCollection, blobStorage);
await initial(docCollection, blobStorage, docStorage);

// save workspace to local storage, should be vary fast
await docStorage.doc.set(id, encodeStateAsUpdate(docCollection.doc));
Expand Down
31 changes: 31 additions & 0 deletions tests/affine-cloud/e2e/workspace.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import {
enableCloudWorkspace,
loginUser,
} from '@affine-test/kit/utils/cloud';
import { clickPageModeButton } from '@affine-test/kit/utils/editor';
import {
clickNewPageButton,
getBlockSuiteEditorTitle,
waitForEditorLoad,
waitForEmptyEditor,
} from '@affine-test/kit/utils/page-logic';
import {
openSettingModal,
Expand Down Expand Up @@ -94,3 +97,31 @@ test('should have pagination in member list', async ({ page }) => {
await page.waitForTimeout(500);
expect(await page.locator('[data-testid="member-item"]').count()).toBe(3);
});

test('should transform local favorites data', async ({ page }) => {
await page.reload();
await waitForEditorLoad(page);
await createLocalWorkspace(
{
name: 'test',
},
page
);
await page.getByTestId('explorer-bar-add-favorite-button').first().click();
await clickPageModeButton(page);
await waitForEmptyEditor(page);

await getBlockSuiteEditorTitle(page).fill('this is a new fav page');
await expect(
page
.getByTestId('explorer-favorites')
.locator('[draggable] >> text=this is a new fav page')
).toBeVisible();

await enableCloudWorkspace(page);
await expect(
page
.getByTestId('explorer-favorites')
.locator('[draggable] >> text=this is a new fav page')
).toBeVisible();
});

0 comments on commit cd4e462

Please sign in to comment.