fix: add DB migration to add workspace (#3115)

(cherry picked from commit dac4e390aa)
This commit is contained in:
Peng Xiao
2023-07-10 16:03:18 +08:00
committed by Alex Yang
parent 77200ed8fc
commit 9b948613dc
14 changed files with 213 additions and 28 deletions

View File

@@ -7,7 +7,7 @@ export interface WatchOptions {
recursive?: boolean;
}
/** Watcher kind enumeration */
export const enum WatcherKind {
export enum WatcherKind {
/** inotify backend (linux) */
Inotify = 'Inotify',
/** FS-Event backend (mac) */
@@ -38,6 +38,12 @@ export interface InsertRow {
docId?: string;
data: Uint8Array;
}
export enum ValidationResult {
MissingTables = 0,
MissingDocIdColumn = 1,
GeneralError = 2,
Valid = 3,
}
export class Subscription {
toString(): string;
unsubscribe(): void;
@@ -71,5 +77,6 @@ export class SqliteConnection {
): Promise<void>;
close(): Promise<void>;
get isClose(): boolean;
static validate(path: string): Promise<boolean>;
static validate(path: string): Promise<ValidationResult>;
migrateAddDocId(): Promise<void>;
}

View File

@@ -263,11 +263,18 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`);
}
const { WatcherKind, Subscription, FsWatcher, moveFile, SqliteConnection } =
nativeBinding;
const {
WatcherKind,
Subscription,
FsWatcher,
moveFile,
SqliteConnection,
ValidationResult,
} = nativeBinding;
module.exports.WatcherKind = WatcherKind;
module.exports.Subscription = Subscription;
module.exports.FsWatcher = FsWatcher;
module.exports.moveFile = moveFile;
module.exports.SqliteConnection = SqliteConnection;
module.exports.ValidationResult = ValidationResult;

View File

@@ -11,6 +11,9 @@
"aarch64-unknown-linux-gnu",
"aarch64-pc-windows-msvc"
]
},
"ts": {
"constEnum": false
}
},
"license": "MPL-2.0",
@@ -29,8 +32,8 @@
},
"scripts": {
"artifacts": "napi artifacts",
"build": "napi build --platform --release",
"build:debug": "napi build --platform",
"build": "napi build --platform --release --no-const-enum",
"build:debug": "napi build --platform --no-const-enum",
"universal": "napi universal",
"test": "cross-env TS_NODE_TRANSPILE_ONLY=1 TS_NODE_PROJECT=./tsconfig.json node --test --loader ts-node/esm --experimental-specifier-resolution=node ./__tests__/**/*.mts",
"version": "napi version"

View File

@@ -1,5 +1,5 @@
use chrono::NaiveDateTime;
use napi::bindgen_prelude::{Buffer, Uint8Array};
use napi::bindgen_prelude::{Buffer, FromNapiValue, ToNapiValue, Uint8Array};
use napi_derive::napi;
use sqlx::{
migrate::MigrateDatabase,
@@ -34,6 +34,14 @@ pub struct SqliteConnection {
path: String,
}
#[napi]
pub enum ValidationResult {
MissingTables,
MissingDocIdColumn,
GeneralError,
Valid,
}
#[napi]
impl SqliteConnection {
#[napi(constructor)]
@@ -231,14 +239,14 @@ impl SqliteConnection {
}
#[napi]
pub async fn validate(path: String) -> bool {
pub async fn validate(path: String) -> ValidationResult {
let pool = match SqlitePoolOptions::new()
.max_connections(1)
.connect(&path)
.await
{
Ok(pool) => pool,
Err(_) => return false,
Err(_) => return ValidationResult::GeneralError,
};
let tables_res = sqlx::query("SELECT name FROM sqlite_master WHERE type='table'")
@@ -250,26 +258,32 @@ impl SqliteConnection {
let names: Vec<String> = res.iter().map(|row| row.get(0)).collect();
names.contains(&"updates".to_string()) && names.contains(&"blobs".to_string())
}
Err(_) => return false,
Err(_) => return ValidationResult::GeneralError,
};
let columns_res = sqlx::query("PRAGMA table_info(updates)")
.fetch_all(&pool)
.await;
let columns_exist = match columns_res {
let doc_id_exist = match columns_res {
Ok(res) => {
let names: Vec<String> = res.iter().map(|row| row.get(1)).collect();
names.contains(&"data".to_string()) && names.contains(&"doc_id".to_string())
names.contains(&"doc_id".to_string())
}
Err(_) => return false,
Err(_) => return ValidationResult::GeneralError,
};
tables_exist && columns_exist
if !tables_exist {
ValidationResult::MissingTables
} else if !doc_id_exist {
ValidationResult::MissingDocIdColumn
} else {
ValidationResult::Valid
}
}
// todo: have a better way to handle migration
async fn migrate_add_doc_id(&self) -> Result<(), anyhow::Error> {
#[napi]
pub async fn migrate_add_doc_id(&self) -> napi::Result<()> {
// ignore errors
match sqlx::query("ALTER TABLE updates ADD COLUMN doc_id TEXT")
.execute(&self.pool)
@@ -280,7 +294,7 @@ impl SqliteConnection {
if err.to_string().contains("duplicate column name") {
Ok(()) // Ignore error if it's due to duplicate column
} else {
Err(anyhow::Error::from(err)) // Propagate other errors
Err(anyhow::Error::from(err).into()) // Propagate other errors
}
}
}