diff --git a/Cargo.lock b/Cargo.lock index f4c95b5faf..7dbb1cbc57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -300,7 +300,7 @@ dependencies = [ "objc2-foundation 0.3.0", "parking_lot", "percent-encoding", - "windows-sys 0.52.0", + "windows-sys 0.59.0", "wl-clipboard-rs", "x11rb", ] @@ -1041,7 +1041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1862,7 +1862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4720,7 +4720,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5170,7 +5170,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5183,7 +5183,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -5240,7 +5240,7 @@ dependencies = [ "security-framework 3.5.1", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -6135,6 +6135,27 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "subtle" version = "2.6.1" @@ -6809,6 +6830,7 @@ dependencies = [ "serde", "serde_json", "sqlx", + "strum", "tauri", "tauri-plugin", "thiserror 2.0.12", @@ -7055,7 +7077,7 @@ dependencies = [ "getrandom 0.3.2", "once_cell", "rustix 1.1.3", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -8195,7 +8217,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/plugins/sql/Cargo.toml b/plugins/sql/Cargo.toml index 1608412e35..b4655adac6 100644 --- a/plugins/sql/Cargo.toml +++ b/plugins/sql/Cargo.toml @@ -35,6 +35,7 @@ time = "0.3" tokio = { version = "1", features = ["sync"] } indexmap = { version = "2", features = ["serde"] } uuid = "1" +strum = { version = "0.28", features = ["derive"] } [features] sqlite = ["sqlx/sqlite", "sqlx/runtime-tokio"] diff --git a/plugins/sql/guest-js/index.ts b/plugins/sql/guest-js/index.ts index 11d39e70b4..abd7e0b41c 100644 --- a/plugins/sql/guest-js/index.ts +++ b/plugins/sql/guest-js/index.ts @@ -2,11 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -import { invoke } from '@tauri-apps/api/core' +import { invoke } from '@tauri-apps/api/core'; export interface QueryResult { /** The number of rows affected by the query. */ - rowsAffected: number + rowsAffected: number; /** * The last inserted `id`. * @@ -15,7 +15,12 @@ export interface QueryResult { * must be used, with a `RETURNING` clause * (`INSERT INTO todos (title) VALUES ($1) RETURNING id`). */ - lastInsertId?: number + lastInsertId?: number; +} + +export interface ErrorInfo { + kind: 'Sql' | 'Migration' | 'InvalidDbUrl' | 'DatabaseNotLoaded' | 'UnsupportedDatatype' | (string & {}); + message: string; } /** @@ -25,9 +30,9 @@ export interface QueryResult { * communicating with the rust side of the sql plugin. */ export default class Database { - path: string + path: string; constructor(path: string) { - this.path = path + this.path = path; } /** @@ -45,12 +50,19 @@ export default class Database { * const db = await Database.load("sqlite:test.db"); * ``` */ - static async load(path: string): Promise { - const _path = await invoke('plugin:sql|load', { - db: path - }) + static async load(path: string, applyMigrations = true): Promise { + try { + const _path = await invoke('plugin:sql|load', { + db: path, + applyMigrations: applyMigrations, + }); + + return new Database(_path); + } + catch (err) { + return err as ErrorInfo; + } - return new Database(_path) } /** @@ -70,7 +82,7 @@ export default class Database { * ``` */ static get(path: string): Database { - return new Database(path) + return new Database(path); } /** @@ -105,18 +117,23 @@ export default class Database { * ); * ``` */ - async execute(query: string, bindValues?: unknown[]): Promise { - const [rowsAffected, lastInsertId] = await invoke<[number, number]>( - 'plugin:sql|execute', - { - db: this.path, - query, - values: bindValues ?? [] - } - ) - return { - lastInsertId, - rowsAffected + async execute(query: string, bindValues?: unknown[]): Promise { + try { + const [rowsAffected, lastInsertId] = await invoke<[number, number]>( + 'plugin:sql|execute', + { + db: this.path, + query, + values: bindValues ?? [] + } + ); + return { + lastInsertId, + rowsAffected + }; + } + catch (err) { + return err as ErrorInfo; } } @@ -138,14 +155,19 @@ export default class Database { * ); * ``` */ - async select(query: string, bindValues?: unknown[]): Promise { - const result = await invoke('plugin:sql|select', { - db: this.path, - query, - values: bindValues ?? [] - }) + async select(query: string, bindValues?: unknown[]): Promise { + try { + const result = await invoke('plugin:sql|select', { + db: this.path, + query, + values: bindValues ?? [] + }); - return result + return result; + } + catch (err) { + return err as ErrorInfo; + } } /** @@ -159,10 +181,15 @@ export default class Database { * ``` * @param db - Optionally state the name of a database if you are managing more than one. Otherwise, all database pools will be in scope. */ - async close(db?: string): Promise { - const success = await invoke('plugin:sql|close', { - db - }) - return success + async close(db?: string): Promise { + try { + const success = await invoke('plugin:sql|close', { + db + }); + return success; + } + catch (err) { + return err as ErrorInfo; + } } } diff --git a/plugins/sql/src/commands.rs b/plugins/sql/src/commands.rs index 760d00b2d2..d26d3730c2 100644 --- a/plugins/sql/src/commands.rs +++ b/plugins/sql/src/commands.rs @@ -15,12 +15,15 @@ pub(crate) async fn load( db_instances: State<'_, DbInstances>, migrations: State<'_, Migrations>, db: String, + apply_migrations: bool, ) -> Result { let pool = DbPool::connect(&db, &app).await?; - if let Some(migrations) = migrations.0.lock().await.remove(&db) { - let migrator = Migrator::new(migrations).await?; - pool.migrate(&migrator).await?; + if apply_migrations { + if let Some(migrations) = migrations.0.lock().await.remove(&db) { + let migrator = Migrator::new(migrations).await?; + pool.migrate(&migrator).await?; + } } db_instances.0.write().await.insert(db.clone(), pool); diff --git a/plugins/sql/src/error.rs b/plugins/sql/src/error.rs index 5ac845b8a1..21b3adaef5 100644 --- a/plugins/sql/src/error.rs +++ b/plugins/sql/src/error.rs @@ -4,7 +4,7 @@ use serde::{Serialize, Serializer}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, strum::AsRefStr)] pub enum Error { #[error(transparent)] Sql(#[from] sqlx::Error), @@ -18,11 +18,23 @@ pub enum Error { UnsupportedDatatype(String), } +#[derive(serde::Serialize)] +pub struct ErrorInfo { + kind: String, + message: String, +} + impl Serialize for Error { fn serialize(&self, serializer: S) -> std::result::Result where S: Serializer, { - serializer.serialize_str(self.to_string().as_ref()) + let error_kind = self.as_ref().to_string(); + let error_message = self.to_string(); + let error_info = ErrorInfo { + kind: error_kind, + message: error_message, + }; + error_info.serialize(serializer) } }