pull/2553/merge
Huakun 3 months ago committed by GitHub
commit 58603e6af8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

1
Cargo.lock generated

@ -6920,6 +6920,7 @@ version = "2.2.0"
dependencies = [
"futures-core",
"indexmap 2.7.0",
"libsqlite3-sys",
"log",
"serde",
"serde_json",

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

@ -36,8 +36,9 @@ time = "0.3"
tokio = { version = "1", features = ["sync"] }
indexmap = { version = "2", features = ["serde"] }
libsqlite3-sys = { version = "0.30.1", features = ["bundled-sqlcipher"] }
[features]
sqlite = ["sqlx/sqlite", "sqlx/runtime-tokio"]
mysql = ["sqlx/mysql", "sqlx/runtime-tokio-rustls"]
postgres = ["sqlx/postgres", "sqlx/runtime-tokio-rustls"]
# TODO: bundled-cipher etc

@ -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){const n=await e("plugin:sql|load",{db:s});return new t(n)}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__})}

@ -42,12 +42,31 @@ export default class Database {
*
* @example
* ```ts
* // Basic connection to a SQLite database
* const db = await Database.load("sqlite:test.db");
*
* // Connecting with an encryption key for added security
* const db = await Database.load("sqlite:encrypted.db", {
* sqlite: { pragmas: { "key": "encryption_key" } }
* });
*
* // Connecting with specific pragmas for configuration
* const db = await Database.load("sqlite:test.db", {
* sqlite: { pragmas: { "journal_mode": "WAL", "foreign_keys": "ON" } }
* });
* ```
*/
static async load(path: string): Promise<Database> {
static async load(
path: string,
options?: {
sqlite?: {
pragmas?: Record<string, string>
}
}
): Promise<Database> {
const _path = await invoke<string>('plugin:sql|load', {
db: path
db: path,
options
})
return new Database(_path)

@ -2,22 +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};
use crate::{DbInstances, DbPool, Error, LastInsertId, Migrations};
#[command]
pub(crate) async fn load<R: Runtime>(
app: AppHandle<R>,
db_instances: State<'_, DbInstances>,
migrations: State<'_, Migrations>,
db: String,
options: Option<ConnectionOptions>,
) -> Result<String, crate::Error> {
let pool = DbPool::connect(&db, &app).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?;

@ -16,6 +16,9 @@ mod wrapper;
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};
@ -150,7 +153,7 @@ impl Builder {
let mut lock = instances.0.write().await;
for db in config.preload {
let pool = DbPool::connect(&db, app).await?;
let pool = DbPool::connect(&db, app, None).await?;
if let Some(migrations) =
self.migrations.as_mut().and_then(|mm| mm.remove(&db))

@ -2,11 +2,15 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
#[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;
#[cfg(feature = "sqlite")]
use sqlx::sqlite::SqliteConnectOptions;
#[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgres"))]
use sqlx::{migrate::MigrateDatabase, Column, Executor, Pool, Row};
#[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgres"))]
@ -33,6 +37,40 @@ pub enum DbPool {
None,
}
#[cfg(feature = "sqlite")]
#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct SqliteOptions {
pub pragmas: HashMap<String, String>,
}
#[cfg(feature = "sqlite")]
impl Default for SqliteOptions {
fn default() -> Self {
Self {
pragmas: HashMap::new(),
}
}
}
#[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
/* impl DbPool {
/// Get the inner Sqlite Pool. Returns None for MySql and Postgres pools.
@ -68,6 +106,7 @@ impl DbPool {
pub(crate) async fn connect<R: Runtime>(
conn_url: &str,
_app: &AppHandle<R>,
options: Option<ConnectionOptions>,
) -> Result<Self, crate::Error> {
match conn_url
.split_once(':')
@ -82,13 +121,23 @@ impl DbPool {
.expect("No App config path was found!");
create_dir_all(&app_path).expect("Couldn't create app config dir");
let conn_url = &path_mapper(app_path, conn_url);
let filename = conn_url.split_once(':').unwrap().1;
if !Sqlite::database_exists(conn_url).await.unwrap_or(false) {
Sqlite::create_database(conn_url).await?;
let mut sqlite_options = SqliteConnectOptions::new()
.filename(filename)
.create_if_missing(true);
// Apply pragmas if provided
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);
}
}
}
Ok(Self::Sqlite(Pool::connect(conn_url).await?))
// Connect with options (which includes create_if_missing)
Ok(Self::Sqlite(Pool::connect_with(sqlite_options).await?))
}
#[cfg(feature = "mysql")]
"mysql" => {

Loading…
Cancel
Save