feat(sql): support multi sql features

pull/2553/head
Huakun Shen 4 months ago
parent 2477559fff
commit 65a77b73d5
No known key found for this signature in database

@ -1,3 +1,3 @@
{ {
"rust-analyzer.cargo.features": ["sqlite"] "rust-analyzer.cargo.features": ["mysql", "postgres", "sqlite"]
} }

@ -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__})}

@ -59,12 +59,14 @@ export default class Database {
static async load( static async load(
path: string, path: string,
options?: { options?: {
pragmas?: Record<string, string> sqlite?: {
pragmas?: Record<string, string>
}
} }
): Promise<Database> { ): Promise<Database> {
const _path = await invoke<string>('plugin:sql|load', { const _path = await invoke<string>('plugin:sql|load', {
db: path, db: path,
pragmas: options?.pragmas options
}) })
return new Database(_path) return new Database(_path)

@ -2,62 +2,21 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use crate::{wrapper::ConnectionOptions, DbInstances, DbPool, Error, LastInsertId, Migrations};
use indexmap::IndexMap; use indexmap::IndexMap;
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
use sqlx::migrate::Migrator; use sqlx::migrate::Migrator;
use tauri::{command, AppHandle, Runtime, State}; 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<R: Runtime>(
app: AppHandle<R>,
db_instances: State<'_, DbInstances>,
migrations: State<'_, Migrations>,
db: String,
) -> Result<String, crate::Error> {
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] #[command]
pub(crate) async fn load<R: Runtime>( pub(crate) async fn load<R: Runtime>(
app: AppHandle<R>, app: AppHandle<R>,
db_instances: State<'_, DbInstances>, db_instances: State<'_, DbInstances>,
migrations: State<'_, Migrations>, migrations: State<'_, Migrations>,
db: String, db: String,
pragmas: Option<HashMap<String, String>>, options: Option<ConnectionOptions>,
) -> Result<String, crate::Error> { ) -> Result<String, crate::Error> {
let sqlite_options = if db.starts_with("sqlite:") { let pool = DbPool::connect(&db, &app, options).await?;
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?;
if let Some(migrations) = migrations.0.lock().await.remove(&db) { if let Some(migrations) = migrations.0.lock().await.remove(&db) {
let migrator = Migrator::new(migrations).await?; let migrator = Migrator::new(migrations).await?;
pool.migrate(&migrator).await?; pool.migrate(&migrator).await?;

@ -18,6 +18,7 @@ pub use error::Error;
pub use wrapper::DbPool; pub use wrapper::DbPool;
#[cfg(feature = "sqlite")] #[cfg(feature = "sqlite")]
pub use wrapper::SqliteOptions; pub use wrapper::SqliteOptions;
pub use wrapper::ConnectionOptions;
use futures_core::future::BoxFuture; use futures_core::future::BoxFuture;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -25,8 +26,6 @@ use sqlx::{
error::BoxDynError, error::BoxDynError,
migrate::{Migration as SqlxMigration, MigrationSource, MigrationType, Migrator}, migrate::{Migration as SqlxMigration, MigrationSource, MigrationType, Migrator},
}; };
#[cfg(feature = "sqlite")]
use sqlx::sqlite::SqliteConnectOptions;
use tauri::{ use tauri::{
plugin::{Builder as PluginBuilder, TauriPlugin}, plugin::{Builder as PluginBuilder, TauriPlugin},
Manager, RunEvent, Runtime, Manager, RunEvent, Runtime,
@ -38,9 +37,6 @@ use std::collections::HashMap;
#[derive(Default)] #[derive(Default)]
pub struct DbInstances(pub RwLock<HashMap<String, DbPool>>); pub struct DbInstances(pub RwLock<HashMap<String, DbPool>>);
#[cfg(feature = "sqlite")]
struct SqlLiteOptionStore(Mutex<HashMap<String, SqliteConnectOptions>>);
#[derive(Serialize)] #[derive(Serialize)]
#[serde(untagged)] #[serde(untagged)]
pub(crate) enum LastInsertId { pub(crate) enum LastInsertId {
@ -160,12 +156,8 @@ impl Builder {
let mut lock = instances.0.write().await; let mut lock = instances.0.write().await;
for db in config.preload { for db in config.preload {
#[cfg(feature = "sqlite")]
let pool = DbPool::connect(&db, app, None).await?; let pool = DbPool::connect(&db, app, None).await?;
#[cfg(not(feature = "sqlite"))]
let pool = DbPool::connect(&db, app).await?;
if let Some(migrations) = if let Some(migrations) =
self.migrations.as_mut().and_then(|mm| mm.remove(&db)) self.migrations.as_mut().and_then(|mm| mm.remove(&db))
{ {

@ -2,10 +2,10 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#[cfg(feature = "sqlite")]
use std::fs::create_dir_all;
#[cfg(feature = "sqlite")] #[cfg(feature = "sqlite")]
use std::collections::HashMap; use std::collections::HashMap;
#[cfg(feature = "sqlite")]
use std::fs::create_dir_all;
use indexmap::IndexMap; use indexmap::IndexMap;
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
@ -38,6 +38,7 @@ pub enum DbPool {
} }
#[cfg(feature = "sqlite")] #[cfg(feature = "sqlite")]
#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct SqliteOptions { pub struct SqliteOptions {
pub pragmas: HashMap<String, String>, pub pragmas: HashMap<String, String>,
} }
@ -51,6 +52,25 @@ impl Default for SqliteOptions {
} }
} }
#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct ConnectionOptions {
#[cfg(feature = "sqlite")]
pub sqlite: Option<SqliteOptions>,
// #[cfg(feature = "mysql")]
// mysql: Option<MySqlOptions>,
// #[cfg(feature = "postgres")]
// postgres: Option<PostgresOptions>,
}
impl Default for ConnectionOptions {
fn default() -> Self {
Self {
#[cfg(feature = "sqlite")]
sqlite: None,
}
}
}
// public methods // public methods
/* impl DbPool { /* impl DbPool {
/// Get the inner Sqlite Pool. Returns None for MySql and Postgres pools. /// Get the inner Sqlite Pool. Returns None for MySql and Postgres pools.
@ -86,7 +106,7 @@ impl DbPool {
pub(crate) async fn connect<R: Runtime>( pub(crate) async fn connect<R: Runtime>(
conn_url: &str, conn_url: &str,
_app: &AppHandle<R>, _app: &AppHandle<R>,
#[cfg(feature = "sqlite")] sqlite_options: Option<SqliteOptions>, options: Option<ConnectionOptions>,
) -> Result<Self, crate::Error> { ) -> Result<Self, crate::Error> {
match conn_url match conn_url
.split_once(':') .split_once(':')
@ -104,19 +124,20 @@ impl DbPool {
let conn_url = &path_mapper(app_path, conn_url); let conn_url = &path_mapper(app_path, conn_url);
let filename = conn_url.split_once(':').unwrap().1; let filename = conn_url.split_once(':').unwrap().1;
let mut options = SqliteConnectOptions::new() let mut sqlite_options = SqliteConnectOptions::new()
.filename(filename) .filename(filename)
.create_if_missing(true); .create_if_missing(true);
// Apply pragmas if provided // Apply pragmas if provided
if let Some(sqlite_opts) = sqlite_options { if let Some(conn_opts) = options {
for (pragma_name, pragma_value) in sqlite_opts.pragmas { if let Some(sqlite_opts) = conn_opts.sqlite {
options = options.pragma(pragma_name, pragma_value); 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) // 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")] #[cfg(feature = "mysql")]
"mysql" => { "mysql" => {

Loading…
Cancel
Save