Files
tauri-plugins-workspace/plugins/sql/src/commands.rs
T
kxrn_guptaandLucas Nogueira c91a9e6af5 feat(sql): add autoCreate option to Database.load (#3702)
* feat(sql): add autoCreate option to Database.load

Add utoCreate option to Database.load allowing users to disable implicit database creation when loading a database.

Closes #299

* fix(sql): fix unused variable without a database feature

* refactor(sql): share the database existence check between drivers

* fix(sql): don't report a failed existence check as a missing database

* fix(sql): name the database as passed, without password, in the missing database error

* fix(sql): don't create the app config dir when autoCreate is false

* refactor(sql): use the LoadOptions default for missing options

* test(sql): cover autoCreate and password redaction

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-12 10:46:00 -03:00

95 lines
2.5 KiB
Rust

// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use indexmap::IndexMap;
use serde_json::Value as JsonValue;
use sqlx::migrate::Migrator;
use tauri::{AppHandle, Runtime, State, command};
use crate::{DbInstances, DbPool, Error, LastInsertId, Migrations};
#[derive(Debug, Clone, Copy, serde::Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub(crate) struct LoadOptions {
pub auto_create: bool,
}
impl Default for LoadOptions {
fn default() -> Self {
Self { auto_create: true }
}
}
#[command]
pub(crate) async fn load<R: Runtime>(
app: AppHandle<R>,
db_instances: State<'_, DbInstances>,
migrations: State<'_, Migrations>,
db: String,
options: Option<LoadOptions>,
) -> Result<String, crate::Error> {
let options = options.unwrap_or_default();
let pool = DbPool::connect(&db, &app, options.auto_create).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)
}
/// Allows the database connection(s) to be closed; if no database
/// name is passed in then _all_ database connection pools will be
/// shut down.
#[command]
pub(crate) async fn close(
db_instances: State<'_, DbInstances>,
db: Option<String>,
) -> Result<bool, crate::Error> {
let instances = db_instances.0.read().await;
let pools = if let Some(db) = db {
vec![db]
} else {
instances.keys().cloned().collect()
};
for pool in pools {
let db = instances.get(&pool).ok_or(Error::DatabaseNotLoaded(pool))?;
db.close().await;
}
Ok(true)
}
/// Execute a command against the database
#[command]
pub(crate) async fn execute(
db_instances: State<'_, DbInstances>,
db: String,
query: String,
values: Vec<JsonValue>,
) -> Result<(u64, LastInsertId), crate::Error> {
let instances = db_instances.0.read().await;
let db = instances.get(&db).ok_or(Error::DatabaseNotLoaded(db))?;
db.execute(query, values).await
}
#[command]
pub(crate) async fn select(
db_instances: State<'_, DbInstances>,
db: String,
query: String,
values: Vec<JsonValue>,
) -> Result<Vec<IndexMap<String, JsonValue>>, crate::Error> {
let instances = db_instances.0.read().await;
let db = instances.get(&db).ok_or(Error::DatabaseNotLoaded(db))?;
db.select(query, values).await
}