fix(electron): upgrade db file (#3984)

This commit is contained in:
Alex Yang
2023-08-28 15:38:40 -05:00
committed by GitHub
parent d62935935f
commit d9cb45f466
9 changed files with 177 additions and 11 deletions

View File

@@ -490,9 +490,14 @@ const upgradeV1ToV2 = async (options: UpgradeOptions) => {
return newWorkspace;
};
const upgradeV2ToV3 = async (options: UpgradeOptions): Promise<true> => {
const upgradeV2ToV3 = async (options: UpgradeOptions): Promise<boolean> => {
const rootDoc = await options.getCurrentRootDoc();
const spaces = rootDoc.getMap('spaces') as YMap<any>;
const meta = rootDoc.getMap('meta') as YMap<unknown>;
const versions = meta.get('blockVersions') as YMap<number>;
if (versions.get('affine:database') === 3) {
return false;
}
const schema = options.getSchema();
spaces.forEach(space => {
schema.upgradePage(
@@ -511,8 +516,6 @@ const upgradeV2ToV3 = async (options: UpgradeOptions): Promise<true> => {
space
);
});
const meta = rootDoc.getMap('meta') as YMap<unknown>;
const versions = meta.get('blockVersions') as YMap<number>;
versions.set('affine:database', 3);
return true;
};

View File

@@ -0,0 +1,15 @@
import assert from 'node:assert';
import { test } from 'node:test';
import { fileURLToPath } from 'node:url';
import { SqliteConnection, ValidationResult } from '../index';
test('db', { concurrency: false }, async t => {
await t.test('validate', async () => {
const path = fileURLToPath(
new URL('./fixtures/test01.affine', import.meta.url)
);
const result = await SqliteConnection.validate(path);
assert.equal(result, ValidationResult.MissingVersionColumn);
});
});

Binary file not shown.

View File

@@ -41,8 +41,9 @@ export interface InsertRow {
export enum ValidationResult {
MissingTables = 0,
MissingDocIdColumn = 1,
GeneralError = 2,
Valid = 3,
MissingVersionColumn = 2,
GeneralError = 3,
Valid = 4,
}
export class Subscription {
toString(): string;
@@ -75,6 +76,8 @@ export class SqliteConnection {
docId: string | undefined | null,
updates: Array<InsertRow>
): Promise<void>;
initVersion(): Promise<void>;
setVersion(version: number): Promise<void>;
close(): Promise<void>;
get isClose(): boolean;
static validate(path: string): Promise<ValidationResult>;

View File

@@ -11,4 +11,9 @@ CREATE TABLE IF NOT EXISTS "blobs" (
key TEXT PRIMARY KEY NOT NULL,
data BLOB NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);"#;
);
CREATE TABLE IF NOT EXISTS "version_info" (
version NUMBER NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
)
"#;

View File

@@ -7,6 +7,9 @@ use sqlx::{
Pool, Row,
};
// latest version
const LATEST_VERSION: i32 = 3;
#[napi(object)]
pub struct BlobRow {
pub key: String,
@@ -38,6 +41,7 @@ pub struct SqliteConnection {
pub enum ValidationResult {
MissingTables,
MissingDocIdColumn,
MissingVersionColumn,
GeneralError,
Valid,
}
@@ -228,6 +232,39 @@ impl SqliteConnection {
Ok(())
}
#[napi]
pub async fn init_version(&self) -> napi::Result<()> {
// create version_info table
sqlx::query!(
"CREATE TABLE IF NOT EXISTS version_info (
version NUMBER NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
)"
)
.execute(&self.pool)
.await
.map_err(anyhow::Error::from)?;
// `3` is the first version that has version_info table,
// do not modify the version number.
sqlx::query!("INSERT INTO version_info (version) VALUES (3)")
.execute(&self.pool)
.await
.map_err(anyhow::Error::from)?;
Ok(())
}
#[napi]
pub async fn set_version(&self, version: i32) -> napi::Result<()> {
if version > LATEST_VERSION {
return Err(anyhow::Error::msg("Version is too new").into());
}
sqlx::query!("UPDATE version_info SET version = ?", version)
.execute(&self.pool)
.await
.map_err(anyhow::Error::from)?;
Ok(())
}
#[napi]
pub async fn close(&self) {
self.pool.close().await;
@@ -261,6 +298,18 @@ impl SqliteConnection {
Err(_) => return ValidationResult::GeneralError,
};
let tables_res = sqlx::query("SELECT name FROM sqlite_master WHERE type='table'")
.fetch_all(&pool)
.await;
let version_exist = match tables_res {
Ok(res) => {
let names: Vec<String> = res.iter().map(|row| row.get(0)).collect();
names.contains(&"version_info".to_string())
}
Err(_) => return ValidationResult::GeneralError,
};
let columns_res = sqlx::query("PRAGMA table_info(updates)")
.fetch_all(&pool)
.await;
@@ -277,6 +326,8 @@ impl SqliteConnection {
ValidationResult::MissingTables
} else if !doc_id_exist {
ValidationResult::MissingDocIdColumn
} else if !version_exist {
ValidationResult::MissingVersionColumn
} else {
ValidationResult::Valid
}