mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-09-22 21:30:44 +02:00
chore: update documentation
This commit is contained in:
@@ -2,8 +2,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* Interface with SQL databases through [sqlx](https://github.com/launchbadge/sqlx).
|
||||
* Which database engines can be used depends on the drivers enabled on the Rust
|
||||
* side of the plugin: SQLite, MySQL and PostgreSQL.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
/**
|
||||
* The outcome of a statement run through {@link Database.execute}.
|
||||
*/
|
||||
export interface QueryResult {
|
||||
/** The number of rows affected by the query. */
|
||||
rowsAffected: number
|
||||
@@ -23,9 +34,30 @@ export interface QueryResult {
|
||||
*
|
||||
* The `Database` class serves as the primary interface for
|
||||
* communicating with the rust side of the sql plugin.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
export default class Database {
|
||||
/**
|
||||
* The connection string identifying the database on the Rust side,
|
||||
* for instance `sqlite:test.db`, `mysql://user:pass@host/database`
|
||||
* or `postgres://user:pass@host/database`.
|
||||
*/
|
||||
path: string
|
||||
|
||||
/**
|
||||
* Creates a `Database` instance for the given connection string without
|
||||
* opening a connection to it. Use {@link Database.load} to connect to the
|
||||
* database, or {@link Database.get} for a database that is already loaded.
|
||||
*
|
||||
* @param path The database connection string, such as `sqlite:test.db`.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import Database from '@tauri-apps/plugin-sql'
|
||||
* const db = new Database('sqlite:test.db')
|
||||
* ```
|
||||
*/
|
||||
constructor(path: string) {
|
||||
this.path = path
|
||||
}
|
||||
@@ -41,9 +73,13 @@ export default class Database {
|
||||
* The path is relative to `tauri::path::BaseDirectory::App` and must start with `sqlite:`.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const db = await Database.load("sqlite:test.db");
|
||||
* ```typescript
|
||||
* import Database from '@tauri-apps/plugin-sql'
|
||||
* const db = await Database.load('sqlite:test.db')
|
||||
* ```
|
||||
*
|
||||
* @param path The database connection string, such as `sqlite:test.db`. The database is created if it does not exist yet, and any migration registered for it on the Rust side is run.
|
||||
* @returns A promise resolving to a `Database` instance connected to the given database.
|
||||
*/
|
||||
static async load(path: string): Promise<Database> {
|
||||
const _path = await invoke<string>('plugin:sql|load', {
|
||||
@@ -65,9 +101,13 @@ export default class Database {
|
||||
* The path is relative to `tauri::path::BaseDirectory::App` and must start with `sqlite:`.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const db = Database.get("sqlite:test.db");
|
||||
* ```typescript
|
||||
* import Database from '@tauri-apps/plugin-sql'
|
||||
* const db = Database.get('sqlite:test.db')
|
||||
* ```
|
||||
*
|
||||
* @param path The database connection string, such as `sqlite:test.db`.
|
||||
* @returns A `Database` instance bound to the given connection string.
|
||||
*/
|
||||
static get(path: string): Database {
|
||||
return new Database(path)
|
||||
@@ -79,7 +119,10 @@ export default class Database {
|
||||
* Passes a SQL expression to the database for execution.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* ```typescript
|
||||
* import Database from '@tauri-apps/plugin-sql'
|
||||
* const db = await Database.load('sqlite:test.db')
|
||||
*
|
||||
* // for sqlite & postgres
|
||||
* // INSERT example
|
||||
* const result = await db.execute(
|
||||
@@ -104,6 +147,10 @@ export default class Database {
|
||||
* [ todos.title, todos.status, todos.id ]
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @param query The SQL statement to run, using `$1`, `$2`, ... placeholders on SQLite and PostgreSQL and `?` placeholders on MySQL.
|
||||
* @param bindValues The values bound to the query placeholders, in the order they appear in the statement. Defaults to no values.
|
||||
* @returns A promise resolving to the number of rows affected by the statement and the last inserted id.
|
||||
*/
|
||||
async execute(query: string, bindValues?: unknown[]): Promise<QueryResult> {
|
||||
const [rowsAffected, lastInsertId] = await invoke<[number, number]>(
|
||||
@@ -126,7 +173,10 @@ export default class Database {
|
||||
* Passes in a SELECT query to the database for execution.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* ```typescript
|
||||
* import Database from '@tauri-apps/plugin-sql'
|
||||
* const db = await Database.load('sqlite:test.db')
|
||||
*
|
||||
* // for sqlite & postgres
|
||||
* const result = await db.select(
|
||||
* "SELECT * from todos WHERE id = $1", [ id ]
|
||||
@@ -137,6 +187,10 @@ export default class Database {
|
||||
* "SELECT * from todos WHERE id = ?", [ id ]
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @param query The SQL query to run, using `$1`, `$2`, ... placeholders on SQLite and PostgreSQL and `?` placeholders on MySQL.
|
||||
* @param bindValues The values bound to the query placeholders, in the order they appear in the query. Defaults to no values.
|
||||
* @returns A promise resolving to the selected rows, each row being an object keyed by column name.
|
||||
*/
|
||||
async select<T>(query: string, bindValues?: unknown[]): Promise<T> {
|
||||
const result = await invoke<T>('plugin:sql|select', {
|
||||
@@ -154,10 +208,14 @@ export default class Database {
|
||||
* Closes the database connection pool.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* ```typescript
|
||||
* import Database from '@tauri-apps/plugin-sql'
|
||||
* const db = await Database.load('sqlite:test.db')
|
||||
* const success = await db.close()
|
||||
* ```
|
||||
*
|
||||
* @param db - Optionally state the name of a database if you are managing more than one. Otherwise, all database pools will be in scope.
|
||||
* @returns A promise resolving to `true` once the matching connection pools have been closed.
|
||||
*/
|
||||
async close(db?: string): Promise<boolean> {
|
||||
const success = await invoke<boolean>('plugin:sql|close', {
|
||||
|
||||
@@ -4,16 +4,30 @@
|
||||
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
/// Errors that can happen while connecting to a database, running migrations
|
||||
/// or executing a query.
|
||||
///
|
||||
/// Serializes to its [`std::fmt::Display`] representation, which is what the
|
||||
/// frontend receives when a command fails.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
/// An error reported by [`sqlx`], such as a failed connection or a query the database rejected.
|
||||
#[error(transparent)]
|
||||
Sql(#[from] sqlx::Error),
|
||||
/// A migration registered with [`crate::Builder::add_migrations`] could not be resolved or applied.
|
||||
#[error(transparent)]
|
||||
Migration(#[from] sqlx::migrate::MigrateError),
|
||||
/// The connection string is missing its `scheme:` prefix, or the scheme does not
|
||||
/// match any of the enabled database drivers. Contains the offending connection string.
|
||||
#[error("invalid connection url: {0}")]
|
||||
InvalidDbUrl(String),
|
||||
/// The requested database has not been connected to with the `load` command
|
||||
/// and is not listed in the plugin's `preload` configuration.
|
||||
/// Contains the connection string of the database.
|
||||
#[error("database {0} not loaded")]
|
||||
DatabaseNotLoaded(String),
|
||||
/// A value selected from the database has a SQL type that cannot be converted
|
||||
/// to JSON. Contains the name of that SQL type.
|
||||
#[error("unsupported datatype: {0}")]
|
||||
UnsupportedDatatype(String),
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@ use tokio::sync::{Mutex, RwLock};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// The connection pools the plugin currently holds, keyed by the connection
|
||||
/// string the database was loaded with.
|
||||
///
|
||||
/// It is managed as Tauri state, so Rust code can reach the pools with
|
||||
/// [`tauri::Manager::state`] and run its own queries.
|
||||
#[derive(Default)]
|
||||
pub struct DbInstances(pub RwLock<HashMap<String, DbPool>>);
|
||||
|
||||
@@ -58,15 +63,22 @@ pub(crate) enum LastInsertId {
|
||||
|
||||
struct Migrations(Mutex<HashMap<String, MigrationList>>);
|
||||
|
||||
/// The `plugins > sql` section of the Tauri configuration file.
|
||||
#[derive(Default, Clone, Deserialize)]
|
||||
pub struct PluginConfig {
|
||||
/// Connection strings of the databases to connect to when the application
|
||||
/// starts. Empty by default.
|
||||
#[serde(default)]
|
||||
preload: Vec<String>,
|
||||
}
|
||||
|
||||
/// The direction of a [`Migration`].
|
||||
#[derive(Debug)]
|
||||
pub enum MigrationKind {
|
||||
/// Moves the schema forward. Only migrations of this kind are executed by the plugin.
|
||||
Up,
|
||||
/// Reverts an [`Up`](Self::Up) migration. Migrations of this kind are currently
|
||||
/// never executed by the plugin.
|
||||
Down,
|
||||
}
|
||||
|
||||
@@ -80,11 +92,23 @@ impl From<MigrationKind> for MigrationType {
|
||||
}
|
||||
|
||||
/// A migration definition.
|
||||
///
|
||||
/// Migrations are attached to a database with [`Builder::add_migrations`] and run
|
||||
/// the first time that database is connected to - on startup for the databases
|
||||
/// listed in the `preload` configuration, otherwise when the frontend loads it.
|
||||
/// Only [`MigrationKind::Up`] migrations are executed, in ascending
|
||||
/// [`version`](Self::version) order, and sqlx keeps track of the versions that
|
||||
/// already ran so each one is applied at most once per database.
|
||||
#[derive(Debug)]
|
||||
pub struct Migration {
|
||||
/// The version of this migration. Determines the order in which migrations
|
||||
/// run and identifies the migration in the database.
|
||||
pub version: i64,
|
||||
/// A human readable description of what the migration does.
|
||||
pub description: &'static str,
|
||||
/// The SQL executed when the migration runs.
|
||||
pub sql: &'static str,
|
||||
/// Whether this migration moves the schema forward or reverts it.
|
||||
pub kind: MigrationKind,
|
||||
}
|
||||
|
||||
@@ -127,6 +151,11 @@ pub struct Builder {
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
/// Creates a new builder with no migrations registered.
|
||||
///
|
||||
/// Prints a message to stderr when none of the `sqlite`, `mysql` and
|
||||
/// `postgres` Cargo features is enabled, since no database can be
|
||||
/// connected to in that case.
|
||||
pub fn new() -> Self {
|
||||
#[cfg(not(any(feature = "sqlite", feature = "mysql", feature = "postgres")))]
|
||||
eprintln!("No sql driver enabled. Please set at least one of the \"sqlite\", \"mysql\", \"postgres\" feature flags.");
|
||||
@@ -143,6 +172,33 @@ impl Builder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Builds the SQL plugin.
|
||||
///
|
||||
/// On setup the plugin connects to every database listed in the `preload`
|
||||
/// array of its [configuration](PluginConfig), running the migrations
|
||||
/// registered for them, and it closes all connection pools when the
|
||||
/// application exits.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tauri_plugin_sql::{Builder, Migration, MigrationKind};
|
||||
///
|
||||
/// fn sql_plugin<R: tauri::Runtime>(
|
||||
/// ) -> tauri::plugin::TauriPlugin<R, Option<tauri_plugin_sql::PluginConfig>> {
|
||||
/// Builder::new()
|
||||
/// .add_migrations(
|
||||
/// "sqlite:mydatabase.db",
|
||||
/// vec![Migration {
|
||||
/// version: 1,
|
||||
/// description: "create todos table",
|
||||
/// sql: "CREATE TABLE todos (id INTEGER PRIMARY KEY, title TEXT);",
|
||||
/// kind: MigrationKind::Up,
|
||||
/// }],
|
||||
/// )
|
||||
/// .build()
|
||||
/// }
|
||||
/// ```
|
||||
pub fn build<R: Runtime>(mut self) -> TauriPlugin<R, Option<PluginConfig>> {
|
||||
PluginBuilder::<R, Option<PluginConfig>>::new("sql")
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
|
||||
@@ -22,13 +22,23 @@ use sqlx::Sqlite;
|
||||
|
||||
use crate::LastInsertId;
|
||||
|
||||
/// A connection pool for one of the supported database drivers.
|
||||
///
|
||||
/// The variant is picked from the scheme of the connection string
|
||||
/// (`sqlite:`, `mysql:` or `postgres:`) and only the variants whose Cargo
|
||||
/// feature is enabled exist.
|
||||
pub enum DbPool {
|
||||
/// A SQLite connection pool. Only available with the `sqlite` Cargo feature.
|
||||
#[cfg(feature = "sqlite")]
|
||||
Sqlite(Pool<Sqlite>),
|
||||
/// A MySQL connection pool. Only available with the `mysql` Cargo feature.
|
||||
#[cfg(feature = "mysql")]
|
||||
MySql(Pool<MySql>),
|
||||
/// A PostgreSQL connection pool. Only available with the `postgres` Cargo feature.
|
||||
#[cfg(feature = "postgres")]
|
||||
Postgres(Pool<Postgres>),
|
||||
/// Placeholder used when none of the `sqlite`, `mysql` and `postgres` Cargo
|
||||
/// features is enabled. Connecting always fails and every other operation is a no-op.
|
||||
#[cfg(not(any(feature = "sqlite", feature = "mysql", feature = "postgres")))]
|
||||
None,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user