rsdbc_sqlite/options/mod.rs
1// From SQLx - https://github.com/launchbadge/sqlx/blob/master/sqlx-core/src/sqlite/options/mod.rs
2
3mod auto_vacuum;
4mod journal_mode;
5mod locking_mode;
6mod synchronous;
7mod parse;
8mod mode;
9
10// TODO: add log settings
11// use crate::connection::LogSettings;
12pub use auto_vacuum::SqliteAutoVacuum;
13pub use journal_mode::SqliteJournalMode;
14pub use locking_mode::SqliteLockingMode;
15pub use synchronous::SqliteSynchronous;
16
17use std::{borrow::Cow, time::Duration};
18use std::future::Future;
19use std::path::Path;
20use std::pin::Pin;
21use crate::{SqliteConnection, to_rsdbc_err};
22use crate::Result;
23use futures::future::BoxFuture;
24use rusqlite::{Connection, OpenFlags};
25use std::sync::{Arc, Mutex};
26use rusqlite::params;
27use std::rc::Rc;
28use rsdbc_core::connection::{ConnectionFactory, ConnectionFactoryMetadata, ConnectionFactoryOptions};
29use rsdbc_core::error::RsdbcErrors;
30
31// // TODO:
32// // - ^ the trait `From<rusqlite::Error>` is not implemented for `rsdbc::Error`
33// impl From<RusqliteError> for Error {
34// fn from(err: rusqlite::Error) -> Self {
35// Error::General(err.to_string())
36// }
37// }
38
39
40// TODO: rename to SqliteConnectionConfiguration?
41#[derive(Clone, Debug)]
42pub struct SqliteConnectOptions {
43 pub(crate) filename: Cow<'static, Path>,
44 pub(crate) in_memory: bool,
45 pub(crate) read_only: bool,
46 pub(crate) create_if_missing: bool,
47 pub(crate) journal_mode: SqliteJournalMode,
48 pub(crate) locking_mode: SqliteLockingMode,
49 pub(crate) foreign_keys: bool,
50 pub(crate) shared_cache: bool,
51 pub(crate) statement_cache_capacity: usize,
52 pub(crate) busy_timeout: Duration,
53 // pub(crate) log_settings: LogSettings,
54 pub(crate) synchronous: SqliteSynchronous,
55 pub(crate) auto_vacuum: SqliteAutoVacuum,
56}
57
58// TODO: document...see new
59impl Default for SqliteConnectOptions {
60 fn default() -> Self {
61 Self::new()
62 }
63}
64
65impl SqliteConnectOptions {
66
67 // TODO: document these options
68 pub fn new() -> Self {
69 Self {
70 filename: Cow::Borrowed(Path::new(":memory:")),
71 in_memory: false,
72 read_only: false,
73 create_if_missing: false,
74 foreign_keys: true,
75 shared_cache: false,
76 statement_cache_capacity: 100,
77 journal_mode: Default::default(),
78 locking_mode: Default::default(),
79 busy_timeout: Duration::from_secs(5),
80 // log_settings: Default::default(),
81 synchronous: Default::default(),
82 auto_vacuum: Default::default(),
83 }
84 }
85
86 /// Sets the name of the database file.
87 pub fn filename(mut self, filename: impl AsRef<Path>) -> Self {
88 self.filename = Cow::Owned(filename.as_ref().to_owned());
89 self
90 }
91
92 /// Set the enforcement of [foreign key constraints](https://www.sqlite.org/pragma.html#pragma_foreign_keys).
93 ///
94 /// By default, this is enabled.
95 pub fn foreign_keys(mut self, on: bool) -> Self {
96 self.foreign_keys = on;
97 self
98 }
99
100 /// Sets the [journal mode](https://www.sqlite.org/pragma.html#pragma_journal_mode) for the database connection.
101 ///
102 /// The default journal mode is WAL. For most use cases this can be significantly faster but
103 /// there are [disadvantages](https://www.sqlite.org/wal.html).
104 pub fn journal_mode(mut self, mode: SqliteJournalMode) -> Self {
105 self.journal_mode = mode;
106 self
107 }
108
109 /// Sets the [locking mode](https://www.sqlite.org/pragma.html#pragma_locking_mode) for the database connection.
110 ///
111 /// The default locking mode is NORMAL.
112 pub fn locking_mode(mut self, mode: SqliteLockingMode) -> Self {
113 self.locking_mode = mode;
114 self
115 }
116
117 /// Sets the [access mode](https://www.sqlite.org/c3ref/open.html) to open the database
118 /// for read-only access.
119 pub fn read_only(mut self, read_only: bool) -> Self {
120 self.read_only = read_only;
121 self
122 }
123
124 /// Sets the [access mode](https://www.sqlite.org/c3ref/open.html) to create the database file
125 /// if the file does not exist.
126 ///
127 /// By default, a new file **will not be** created if one is not found.
128 pub fn create_if_missing(mut self, create: bool) -> Self {
129 self.create_if_missing = create;
130 self
131 }
132
133 /// Sets the capacity of the connection's statement cache in a number of stored
134 /// distinct statements. Caching is handled using LRU, meaning when the
135 /// amount of queries hits the defined limit, the oldest statement will get
136 /// dropped.
137 ///
138 /// The default cache capacity is 100 statements.
139 pub fn statement_cache_capacity(mut self, capacity: usize) -> Self {
140 self.statement_cache_capacity = capacity;
141 self
142 }
143
144 /// Sets a timeout value to wait when the database is locked, before
145 /// returning a busy timeout error.
146 ///
147 /// The default busy timeout is 5 seconds.
148 pub fn busy_timeout(mut self, timeout: Duration) -> Self {
149 self.busy_timeout = timeout;
150 self
151 }
152
153 /// Sets the [synchronous](https://www.sqlite.org/pragma.html#pragma_synchronous) setting for
154 /// the database connection.
155 ///
156 /// The default synchronous settings is FULL. However, if durability is not a concern,
157 /// then NORMAL is normally all one needs in WAL mode.
158 pub fn synchronous(mut self, synchronous: SqliteSynchronous) -> Self {
159 self.synchronous = synchronous;
160 self
161 }
162
163 /// Sets the [auto_vacuum](https://www.sqlite.org/pragma.html#pragma_auto_vacuum) setting for
164 /// the database connection.
165 ///
166 /// The default auto_vacuum setting is NONE.
167 pub fn auto_vacuum(mut self, auto_vacuum: SqliteAutoVacuum) -> Self {
168 self.auto_vacuum = auto_vacuum;
169 self
170 }
171
172 /// Set the [`SQLITE_OPEN_SHAREDCACHE` flag](https://sqlite.org/sharedcache.html).
173 ///
174 /// By default, this is disabled.
175 pub fn shared_cache(mut self, on: bool) -> Self {
176 self.shared_cache = on;
177 self
178 }
179}
180
181impl ConnectionFactory for SqliteConnectOptions {
182 // fn connect(&self) -> BoxFuture<'_, Result<Box<SqliteConnection>>>
183 fn connect(&self) -> Pin<Box<dyn Future<Output = Result<Box<(dyn rsdbc_core::connection::Connection + 'static)>>> + Send>>
184 {
185 todo!()
186 // Box::pin(async move {
187 // let mut flags = OpenFlags::SQLITE_OPEN_NO_MUTEX;
188 //
189 // flags |= if self.read_only {
190 // OpenFlags::SQLITE_OPEN_READ_ONLY
191 // } else if self.create_if_missing {
192 // OpenFlags::SQLITE_OPEN_CREATE | OpenFlags::SQLITE_OPEN_READ_WRITE
193 // } else {
194 // OpenFlags::SQLITE_OPEN_READ_WRITE
195 // };
196 //
197 // if self.in_memory {
198 // flags |= OpenFlags::SQLITE_OPEN_MEMORY;
199 // }
200 //
201 // flags |= if self.shared_cache {
202 // OpenFlags::SQLITE_OPEN_SHARED_CACHE
203 // } else {
204 // OpenFlags::SQLITE_OPEN_PRIVATE_CACHE
205 // };
206 //
207 // let conn =
208 // rusqlite::Connection::open_with_flags(self.filename.to_path_buf(), flags)
209 // .map_err(to_rsdbc_err)?;
210 //
211 // conn.busy_timeout(self.busy_timeout);
212 //
213 // // execute pragma
214 // let init = format!(
215 // "PRAGMA locking_mode = {}; PRAGMA journal_mode = {}; PRAGMA foreign_keys = {}; PRAGMA synchronous = {}; PRAGMA auto_vacuum = {}",
216 // self.locking_mode.as_str(),
217 // self.journal_mode.as_str(),
218 // if self.foreign_keys { "ON" } else { "OFF" },
219 // self.synchronous.as_str(),
220 // self.auto_vacuum.as_str(),
221 // );
222 // conn.execute(init.as_str(), params![]).map_err(to_rsdbc_err)?;
223 //
224 // // // TODO: make this better
225 // // Ok(Box::new(SqliteConnection {
226 // // // conn: Mutex::new(Some(&conn)),
227 // // conn: Some(Arc::new(Mutex::new(conn))),
228 // // }) as Box<(dyn rsdbc_core::connection::Connection + 'static)>)
229 //
230 // todo!()
231 //
232 //
233 // // let mut conn = establish(self).await?;
234 // //
235 // // // send an initial sql statement comprised of options
236 // // //
237 // // // Note that locking_mode should be set before journal_mode; see
238 // // // https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory .
239 // // let init = format!(
240 // // "PRAGMA locking_mode = {}; PRAGMA journal_mode = {}; PRAGMA foreign_keys = {}; PRAGMA synchronous = {}; PRAGMA auto_vacuum = {}",
241 // // self.locking_mode.as_str(),
242 // // self.journal_mode.as_str(),
243 // // if self.foreign_keys { "ON" } else { "OFF" },
244 // // self.synchronous.as_str(),
245 // // self.auto_vacuum.as_str(),
246 // // );
247 // //
248 // // conn.execute(&*init).await?;
249 // //
250 // // Ok(conn)
251 // })
252 }
253
254 // TODO: use SQLite Connection Factory Metadata?
255 fn get_metadata(&self) -> Box<dyn ConnectionFactoryMetadata> {
256 todo!()
257 }
258}