Skip to main content

sql_middleware/sqlite/
config_options.rs

1use std::path::PathBuf;
2
3use crate::middleware::{
4    ConfigAndPool, DatabaseType, MiddlewarePool, MiddlewarePoolOptions, SqlMiddlewareDbError,
5};
6use crate::types::StatementCacheMode;
7
8use super::config::SqliteManager;
9
10/// Options for configuring a `SQLite` pool.
11#[derive(Debug, Clone)]
12pub struct SqliteOptions {
13    pub db_path: PathBuf,
14    pub translate_placeholders: bool,
15    pub pool_options: MiddlewarePoolOptions,
16    pub statement_cache_mode: StatementCacheMode,
17    pub statement_cache_capacity: Option<usize>,
18}
19
20impl SqliteOptions {
21    #[must_use]
22    pub fn new(db_path: String) -> Self {
23        Self {
24            db_path: db_path.into(),
25            translate_placeholders: false,
26            pool_options: MiddlewarePoolOptions::default(),
27            statement_cache_mode: StatementCacheMode::Cached,
28            statement_cache_capacity: None,
29        }
30    }
31
32    #[must_use]
33    pub fn from_path(db_path: impl Into<PathBuf>) -> Self {
34        Self {
35            db_path: db_path.into(),
36            translate_placeholders: false,
37            pool_options: MiddlewarePoolOptions::default(),
38            statement_cache_mode: StatementCacheMode::Cached,
39            statement_cache_capacity: None,
40        }
41    }
42
43    #[must_use]
44    pub fn with_translation(mut self, translate_placeholders: bool) -> Self {
45        self.translate_placeholders = translate_placeholders;
46        self
47    }
48
49    #[must_use]
50    pub fn with_pool_options(mut self, pool_options: MiddlewarePoolOptions) -> Self {
51        self.pool_options = pool_options;
52        self
53    }
54
55    #[must_use]
56    pub fn with_statement_cache(mut self, statement_cache_mode: StatementCacheMode) -> Self {
57        self.statement_cache_mode = statement_cache_mode;
58        self
59    }
60
61    #[must_use]
62    pub fn with_statement_cache_capacity(mut self, capacity: usize) -> Self {
63        self.statement_cache_capacity = Some(capacity);
64        self
65    }
66
67    #[must_use]
68    pub fn with_test_on_check_out(mut self, test_on_check_out: bool) -> Self {
69        self.pool_options.test_on_check_out = test_on_check_out;
70        self
71    }
72}
73
74/// Fluent builder for `SQLite` options.
75#[derive(Debug, Clone)]
76pub struct SqliteOptionsBuilder {
77    opts: SqliteOptions,
78}
79
80impl SqliteOptionsBuilder {
81    #[must_use]
82    pub fn new(db_path: String) -> Self {
83        Self {
84            opts: SqliteOptions::new(db_path),
85        }
86    }
87
88    #[must_use]
89    pub fn from_path(db_path: impl Into<PathBuf>) -> Self {
90        Self {
91            opts: SqliteOptions::from_path(db_path),
92        }
93    }
94
95    #[must_use]
96    pub fn translation(mut self, translate_placeholders: bool) -> Self {
97        self.opts.translate_placeholders = translate_placeholders;
98        self
99    }
100
101    #[must_use]
102    pub fn pool_options(mut self, pool_options: MiddlewarePoolOptions) -> Self {
103        self.opts.pool_options = pool_options;
104        self
105    }
106
107    #[must_use]
108    pub fn statement_cache(mut self, statement_cache_mode: StatementCacheMode) -> Self {
109        self.opts.statement_cache_mode = statement_cache_mode;
110        self
111    }
112
113    #[must_use]
114    pub fn statement_cache_capacity(mut self, capacity: usize) -> Self {
115        self.opts.statement_cache_capacity = Some(capacity);
116        self
117    }
118
119    #[must_use]
120    pub fn test_on_check_out(mut self, test_on_check_out: bool) -> Self {
121        self.opts.pool_options.test_on_check_out = test_on_check_out;
122        self
123    }
124
125    #[must_use]
126    pub fn finish(self) -> SqliteOptions {
127        self.opts
128    }
129
130    /// Build a `ConfigAndPool` for `SQLite`.
131    ///
132    /// # Errors
133    ///
134    /// Returns `SqlMiddlewareDbError` if pool creation or the initial smoke test fails.
135    pub async fn build(self) -> Result<ConfigAndPool, SqlMiddlewareDbError> {
136        ConfigAndPool::new_sqlite(self.finish()).await
137    }
138}
139
140impl ConfigAndPool {
141    #[must_use]
142    pub fn sqlite_builder(db_path: String) -> SqliteOptionsBuilder {
143        SqliteOptionsBuilder::new(db_path)
144    }
145
146    #[must_use]
147    pub fn sqlite_path_builder(db_path: impl Into<PathBuf>) -> SqliteOptionsBuilder {
148        SqliteOptionsBuilder::from_path(db_path)
149    }
150
151    /// Asynchronous initializer for `ConfigAndPool` with Sqlite using a bb8-backed pool.
152    ///
153    /// # Errors
154    /// Returns `SqlMiddlewareDbError::ConnectionError` if pool creation or connection test fails.
155    pub async fn new_sqlite(opts: SqliteOptions) -> Result<Self, SqlMiddlewareDbError> {
156        let pool_options = opts.pool_options;
157        let manager = SqliteManager::from_path(opts.db_path.clone())
158            .with_pool_options(pool_options)
159            .with_statement_cache_capacity(opts.statement_cache_capacity);
160        let pool = manager.build_pool().await?;
161
162        {
163            let mut conn = pool.get_owned().await.map_err(|e| {
164                SqlMiddlewareDbError::ConnectionError(format!("Failed to create SQLite pool: {e}"))
165            })?;
166
167            crate::sqlite::apply_wal_pragmas(&mut conn).await?;
168        }
169
170        Ok(ConfigAndPool {
171            pool: MiddlewarePool::Sqlite(pool),
172            db_type: DatabaseType::Sqlite,
173            translate_placeholders: opts.translate_placeholders,
174            statement_cache_mode: opts.statement_cache_mode,
175        })
176    }
177}