mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
feat!: unified migration logic in server electron, and browser (#4079)
Co-authored-by: Mirone <Saul-Mirone@outlook.com>
This commit is contained in:
@@ -3,8 +3,9 @@ import {
|
||||
SqliteConnection,
|
||||
ValidationResult,
|
||||
} from '@affine/native';
|
||||
import { WorkspaceVersion } from '@toeverything/infra/blocksuite';
|
||||
|
||||
import { migrateToLatestDatabase } from '../db/migration';
|
||||
import { migrateToLatest } from '../db/migration';
|
||||
import { logger } from '../logger';
|
||||
|
||||
/**
|
||||
@@ -20,10 +21,14 @@ export abstract class BaseSQLiteAdapter {
|
||||
if (!this.db) {
|
||||
const validation = await SqliteConnection.validate(this.path);
|
||||
if (validation === ValidationResult.MissingVersionColumn) {
|
||||
await migrateToLatestDatabase(this.path);
|
||||
await migrateToLatest(this.path, WorkspaceVersion.SubDoc);
|
||||
}
|
||||
this.db = new SqliteConnection(this.path);
|
||||
await this.db.connect();
|
||||
const maxVersion = await this.db.getMaxVersion();
|
||||
if (maxVersion !== WorkspaceVersion.Surface) {
|
||||
await migrateToLatest(this.path, WorkspaceVersion.Surface);
|
||||
}
|
||||
logger.info(`[SQLiteAdapter:${this.role}]`, 'connected:', this.path);
|
||||
}
|
||||
return this.db;
|
||||
|
||||
@@ -2,7 +2,10 @@ import { equal } from 'node:assert';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { SqliteConnection } from '@affine/native';
|
||||
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
|
||||
import { Schema } from '@blocksuite/store';
|
||||
import {
|
||||
forceUpgradePages,
|
||||
migrateToSubdoc,
|
||||
WorkspaceVersion,
|
||||
} from '@toeverything/infra/blocksuite';
|
||||
@@ -34,15 +37,19 @@ export const migrateToSubdocAndReplaceDatabase = async (path: string) => {
|
||||
await db.close();
|
||||
};
|
||||
|
||||
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
|
||||
import { Schema, Workspace } from '@blocksuite/store';
|
||||
import { migrateWorkspace } from '@toeverything/infra/blocksuite';
|
||||
|
||||
// v1 v2 -> v3
|
||||
export const migrateToLatestDatabase = async (path: string) => {
|
||||
// v3 -> v4
|
||||
export const migrateToLatest = async (
|
||||
path: string,
|
||||
version: WorkspaceVersion
|
||||
) => {
|
||||
const connection = new SqliteConnection(path);
|
||||
await connection.connect();
|
||||
await connection.initVersion();
|
||||
if (version === WorkspaceVersion.SubDoc) {
|
||||
await connection.initVersion();
|
||||
} else {
|
||||
await connection.setVersion(version);
|
||||
}
|
||||
const schema = new Schema();
|
||||
schema.register(AffineSchemas).register(__unstableSchemas);
|
||||
const rootDoc = new YDoc();
|
||||
@@ -69,24 +76,11 @@ export const migrateToLatestDatabase = async (path: string) => {
|
||||
);
|
||||
};
|
||||
await downloadBinary(rootDoc, true);
|
||||
const result = await migrateWorkspace(WorkspaceVersion.SubDoc, {
|
||||
const result = await forceUpgradePages({
|
||||
getSchema: () => schema,
|
||||
getCurrentRootDoc: () => Promise.resolve(rootDoc),
|
||||
createWorkspace: () =>
|
||||
Promise.resolve(
|
||||
new Workspace({
|
||||
id: nanoid(10),
|
||||
schema,
|
||||
blobStorages: [],
|
||||
providerCreators: [],
|
||||
})
|
||||
),
|
||||
});
|
||||
equal(
|
||||
typeof result,
|
||||
'boolean',
|
||||
'migrateWorkspace should return boolean value'
|
||||
);
|
||||
equal(result, true, 'migrateWorkspace should return boolean value');
|
||||
const uploadBinary = async (doc: YDoc, isRoot: boolean) => {
|
||||
await connection.replaceUpdates(doc.guid, [
|
||||
{ docId: isRoot ? undefined : doc.guid, data: encodeStateAsUpdate(doc) },
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import path from 'node:path';
|
||||
|
||||
import { ValidationResult } from '@affine/native';
|
||||
import { WorkspaceVersion } from '@toeverything/infra/blocksuite';
|
||||
import type {
|
||||
FakeDialogResult,
|
||||
LoadDBFileResult,
|
||||
@@ -14,7 +15,7 @@ import { nanoid } from 'nanoid';
|
||||
import { ensureSQLiteDB } from '../db/ensure-db';
|
||||
import {
|
||||
copyToTemp,
|
||||
migrateToLatestDatabase,
|
||||
migrateToLatest,
|
||||
migrateToSubdocAndReplaceDatabase,
|
||||
} from '../db/migration';
|
||||
import type { WorkspaceSQLiteDB } from '../db/workspace-db-adapter';
|
||||
@@ -204,7 +205,7 @@ export async function loadDBFile(): Promise<LoadDBFileResult> {
|
||||
if (validationResult === ValidationResult.MissingVersionColumn) {
|
||||
try {
|
||||
const tmpDBPath = await copyToTemp(originalPath);
|
||||
await migrateToLatestDatabase(tmpDBPath);
|
||||
await migrateToLatest(tmpDBPath, WorkspaceVersion.SubDoc);
|
||||
originalPath = tmpDBPath;
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
@@ -223,6 +224,24 @@ export async function loadDBFile(): Promise<LoadDBFileResult> {
|
||||
return { error: 'DB_FILE_INVALID' }; // invalid db file
|
||||
}
|
||||
|
||||
const db = new SqliteConnection(originalPath);
|
||||
try {
|
||||
await db.connect();
|
||||
if ((await db.getMaxVersion()) === WorkspaceVersion.DatabaseV3) {
|
||||
const tmpDBPath = await copyToTemp(originalPath);
|
||||
await migrateToLatest(tmpDBPath, WorkspaceVersion.SubDoc);
|
||||
originalPath = tmpDBPath;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
`loadDBFile, migration version column failed: ${originalPath}`,
|
||||
error
|
||||
);
|
||||
return { error: 'DB_FILE_MIGRATION_FAILED' };
|
||||
} finally {
|
||||
await db.close();
|
||||
}
|
||||
|
||||
// copy the db file to a new workspace id
|
||||
const workspaceId = nanoid(10);
|
||||
const internalFilePath = await getWorkspaceDBPath(workspaceId);
|
||||
|
||||
Reference in New Issue
Block a user