sql_middleware/sqlite/
config.rs

1use deadpool_sqlite::{Config as DeadpoolSqliteConfig, Runtime};
2
3use crate::middleware::{ConfigAndPool, DatabaseType, MiddlewarePool, SqlMiddlewareDbError};
4
5impl ConfigAndPool {
6    /// Asynchronous initializer for `ConfigAndPool` with Sqlite using `deadpool_sqlite`
7    ///
8    /// # Errors
9    /// Returns `SqlMiddlewareDbError::ConnectionError` if pool creation or connection test fails.
10    pub async fn new_sqlite(db_path: String) -> Result<Self, SqlMiddlewareDbError> {
11        Self::new_sqlite_with_translation(db_path, false).await
12    }
13
14    /// Asynchronous initializer for `ConfigAndPool` with Sqlite using `deadpool_sqlite`
15    /// and optional placeholder translation default.
16    ///
17    /// # Errors
18    /// Returns `SqlMiddlewareDbError::ConnectionError` if pool creation or connection test fails.
19    ///
20    /// Warning: translation skips placeholders inside quoted strings, comments, and dollar-quoted
21    /// blocks via a lightweight state machine; it may miss edge cases in complex SQL. Prefer
22    /// backend-specific SQL instead of relying on translation:
23    /// ```rust
24    /// # use sql_middleware::prelude::*;
25    /// let query = match &conn {
26    ///     MiddlewarePoolConnection::Postgres { .. } => r#"$function$
27    /// BEGIN
28    ///     RETURN ($1 ~ $q$[\t\r\n\v\\]$q$);
29    /// END;
30    /// $function$"#,
31    ///     MiddlewarePoolConnection::Sqlite { .. } | MiddlewarePoolConnection::Turso { .. } => {
32    ///         include_str!("../sql/functions/sqlite/03_sp_get_scores.sql")
33    ///     }
34    /// };
35    /// ```
36    pub async fn new_sqlite_with_translation(
37        db_path: String,
38        translate_placeholders: bool,
39    ) -> Result<Self, SqlMiddlewareDbError> {
40        // Configure deadpool_sqlite
41        let cfg: DeadpoolSqliteConfig = DeadpoolSqliteConfig::new(db_path.clone());
42
43        // Create the pool
44        let pool = cfg.create_pool(Runtime::Tokio1).map_err(|e| {
45            SqlMiddlewareDbError::ConnectionError(format!("Failed to create SQLite pool: {e}"))
46        })?;
47
48        // Initialize the database (e.g., create tables)
49        {
50            let conn = pool
51                .get()
52                .await
53                .map_err(SqlMiddlewareDbError::PoolErrorSqlite)?;
54            let _res = conn
55                .interact(|conn| {
56                    conn.execute_batch(
57                        "
58                    PRAGMA journal_mode = WAL;
59                ",
60                    )
61                    .map_err(SqlMiddlewareDbError::SqliteError)
62                })
63                .await?;
64        }
65
66        Ok(ConfigAndPool {
67            pool: MiddlewarePool::Sqlite(pool),
68            db_type: DatabaseType::Sqlite,
69            translate_placeholders,
70        })
71    }
72}
73
74/// Convert `InteractError` to a more specific `SqlMiddlewareDbError`
75impl From<deadpool_sqlite::InteractError> for SqlMiddlewareDbError {
76    fn from(err: deadpool_sqlite::InteractError) -> Self {
77        SqlMiddlewareDbError::ConnectionError(format!("SQLite Interact Error: {err}"))
78    }
79}