From 65a77b73d5e81b71faf130242f5b7c7230556ba4 Mon Sep 17 00:00:00 2001 From: Huakun Shen Date: Fri, 21 Mar 2025 00:18:15 -0400 Subject: [PATCH] feat(sql): support multi sql features --- plugins/sql/.vscode/settings.json | 2 +- plugins/sql/api-iife.js | 2 +- plugins/sql/guest-js/index.ts | 6 ++-- plugins/sql/src/commands.rs | 47 ++----------------------------- plugins/sql/src/lib.rs | 10 +------ plugins/sql/src/wrapper.rs | 39 +++++++++++++++++++------ 6 files changed, 40 insertions(+), 66 deletions(-) diff --git a/plugins/sql/.vscode/settings.json b/plugins/sql/.vscode/settings.json index 95ee6b2e..b12ccd3d 100644 --- a/plugins/sql/.vscode/settings.json +++ b/plugins/sql/.vscode/settings.json @@ -1,3 +1,3 @@ { - "rust-analyzer.cargo.features": ["sqlite"] + "rust-analyzer.cargo.features": ["mysql", "postgres", "sqlite"] } diff --git a/plugins/sql/api-iife.js b/plugins/sql/api-iife.js index e5765f1b..86daa539 100644 --- a/plugins/sql/api-iife.js +++ b/plugins/sql/api-iife.js @@ -1 +1 @@ -if("__TAURI__"in window){var __TAURI_PLUGIN_SQL__=function(){"use strict";async function e(e,t={},s){return window.__TAURI_INTERNALS__.invoke(e,t,s)}"function"==typeof SuppressedError&&SuppressedError;class t{constructor(e){this.path=e}static async load(s,n){const r=await e("plugin:sql|load",{db:s,pragmas:n?.pragmas});return new t(r)}static get(e){return new t(e)}async execute(t,s){const[n,r]=await e("plugin:sql|execute",{db:this.path,query:t,values:s??[]});return{lastInsertId:r,rowsAffected:n}}async select(t,s){return await e("plugin:sql|select",{db:this.path,query:t,values:s??[]})}async close(t){return await e("plugin:sql|close",{db:t})}}return t}();Object.defineProperty(window.__TAURI__,"sql",{value:__TAURI_PLUGIN_SQL__})} +if("__TAURI__"in window){var __TAURI_PLUGIN_SQL__=function(){"use strict";async function t(t,e={},s){return window.__TAURI_INTERNALS__.invoke(t,e,s)}"function"==typeof SuppressedError&&SuppressedError;class e{constructor(t){this.path=t}static async load(s,n){const r=await t("plugin:sql|load",{db:s,options:n});return new e(r)}static get(t){return new e(t)}async execute(e,s){const[n,r]=await t("plugin:sql|execute",{db:this.path,query:e,values:s??[]});return{lastInsertId:r,rowsAffected:n}}async select(e,s){return await t("plugin:sql|select",{db:this.path,query:e,values:s??[]})}async close(e){return await t("plugin:sql|close",{db:e})}}return e}();Object.defineProperty(window.__TAURI__,"sql",{value:__TAURI_PLUGIN_SQL__})} diff --git a/plugins/sql/guest-js/index.ts b/plugins/sql/guest-js/index.ts index f778e416..cba9928e 100644 --- a/plugins/sql/guest-js/index.ts +++ b/plugins/sql/guest-js/index.ts @@ -59,12 +59,14 @@ export default class Database { static async load( path: string, options?: { - pragmas?: Record + sqlite?: { + pragmas?: Record + } } ): Promise { const _path = await invoke('plugin:sql|load', { db: path, - pragmas: options?.pragmas + options }) return new Database(_path) diff --git a/plugins/sql/src/commands.rs b/plugins/sql/src/commands.rs index 0cff4a6b..ef6eaf49 100644 --- a/plugins/sql/src/commands.rs +++ b/plugins/sql/src/commands.rs @@ -2,62 +2,21 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +use crate::{wrapper::ConnectionOptions, DbInstances, DbPool, Error, LastInsertId, Migrations}; use indexmap::IndexMap; use serde_json::Value as JsonValue; use sqlx::migrate::Migrator; use tauri::{command, AppHandle, Runtime, State}; -#[cfg(feature = "sqlite")] -use std::collections::HashMap; - -use crate::{DbInstances, DbPool, Error, LastInsertId, Migrations}; -#[cfg(feature = "sqlite")] -use crate::SqliteOptions; - -#[cfg(not(feature = "sqlite"))] -#[command] -pub(crate) async fn load( - app: AppHandle, - db_instances: State<'_, DbInstances>, - migrations: State<'_, Migrations>, - db: String, -) -> 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?; - } - - db_instances.0.write().await.insert(db.clone(), pool); - - Ok(db) -} - -#[cfg(feature = "sqlite")] #[command] pub(crate) async fn load( app: AppHandle, db_instances: State<'_, DbInstances>, migrations: State<'_, Migrations>, db: String, - pragmas: Option>, + options: Option, ) -> Result { - let sqlite_options = if db.starts_with("sqlite:") { - let mut options = SqliteOptions::default(); - - // Apply pragmas if provided - if let Some(provided_pragmas) = pragmas { - options.pragmas.extend(provided_pragmas); - } - - Some(options) - } else { - None - }; - - let pool = DbPool::connect(&db, &app, sqlite_options).await?; - + let pool = DbPool::connect(&db, &app, options).await?; if let Some(migrations) = migrations.0.lock().await.remove(&db) { let migrator = Migrator::new(migrations).await?; pool.migrate(&migrator).await?; diff --git a/plugins/sql/src/lib.rs b/plugins/sql/src/lib.rs index ca2d1bfc..3de734d1 100644 --- a/plugins/sql/src/lib.rs +++ b/plugins/sql/src/lib.rs @@ -18,6 +18,7 @@ pub use error::Error; pub use wrapper::DbPool; #[cfg(feature = "sqlite")] pub use wrapper::SqliteOptions; +pub use wrapper::ConnectionOptions; use futures_core::future::BoxFuture; use serde::{Deserialize, Serialize}; @@ -25,8 +26,6 @@ use sqlx::{ error::BoxDynError, migrate::{Migration as SqlxMigration, MigrationSource, MigrationType, Migrator}, }; -#[cfg(feature = "sqlite")] -use sqlx::sqlite::SqliteConnectOptions; use tauri::{ plugin::{Builder as PluginBuilder, TauriPlugin}, Manager, RunEvent, Runtime, @@ -38,9 +37,6 @@ use std::collections::HashMap; #[derive(Default)] pub struct DbInstances(pub RwLock>); -#[cfg(feature = "sqlite")] -struct SqlLiteOptionStore(Mutex>); - #[derive(Serialize)] #[serde(untagged)] pub(crate) enum LastInsertId { @@ -160,12 +156,8 @@ impl Builder { let mut lock = instances.0.write().await; for db in config.preload { - #[cfg(feature = "sqlite")] let pool = DbPool::connect(&db, app, None).await?; - #[cfg(not(feature = "sqlite"))] - let pool = DbPool::connect(&db, app).await?; - if let Some(migrations) = self.migrations.as_mut().and_then(|mm| mm.remove(&db)) { diff --git a/plugins/sql/src/wrapper.rs b/plugins/sql/src/wrapper.rs index e5348ec6..cd146764 100644 --- a/plugins/sql/src/wrapper.rs +++ b/plugins/sql/src/wrapper.rs @@ -2,10 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -#[cfg(feature = "sqlite")] -use std::fs::create_dir_all; #[cfg(feature = "sqlite")] use std::collections::HashMap; +#[cfg(feature = "sqlite")] +use std::fs::create_dir_all; use indexmap::IndexMap; use serde_json::Value as JsonValue; @@ -38,6 +38,7 @@ pub enum DbPool { } #[cfg(feature = "sqlite")] +#[derive(serde::Serialize, serde::Deserialize, Debug)] pub struct SqliteOptions { pub pragmas: HashMap, } @@ -51,6 +52,25 @@ impl Default for SqliteOptions { } } +#[derive(serde::Serialize, serde::Deserialize, Debug)] +pub struct ConnectionOptions { + #[cfg(feature = "sqlite")] + pub sqlite: Option, + // #[cfg(feature = "mysql")] + // mysql: Option, + // #[cfg(feature = "postgres")] + // postgres: Option, +} + +impl Default for ConnectionOptions { + fn default() -> Self { + Self { + #[cfg(feature = "sqlite")] + sqlite: None, + } + } +} + // public methods /* impl DbPool { /// Get the inner Sqlite Pool. Returns None for MySql and Postgres pools. @@ -86,7 +106,7 @@ impl DbPool { pub(crate) async fn connect( conn_url: &str, _app: &AppHandle, - #[cfg(feature = "sqlite")] sqlite_options: Option, + options: Option, ) -> Result { match conn_url .split_once(':') @@ -104,19 +124,20 @@ impl DbPool { let conn_url = &path_mapper(app_path, conn_url); let filename = conn_url.split_once(':').unwrap().1; - let mut options = SqliteConnectOptions::new() + let mut sqlite_options = SqliteConnectOptions::new() .filename(filename) .create_if_missing(true); - // Apply pragmas if provided - if let Some(sqlite_opts) = sqlite_options { - for (pragma_name, pragma_value) in sqlite_opts.pragmas { - options = options.pragma(pragma_name, pragma_value); + if let Some(conn_opts) = options { + if let Some(sqlite_opts) = conn_opts.sqlite { + for (pragma_name, pragma_value) in sqlite_opts.pragmas { + sqlite_options = sqlite_options.pragma(pragma_name, pragma_value); + } } } // Connect with options (which includes create_if_missing) - Ok(Self::Sqlite(Pool::connect_with(options).await?)) + Ok(Self::Sqlite(Pool::connect_with(sqlite_options).await?)) } #[cfg(feature = "mysql")] "mysql" => {