rsdbc_sqlite/
lib.rs

1pub mod connection;
2pub mod options;
3pub mod error;
4
5use std::collections::HashMap;
6use std::ops::Deref;
7use rusqlite::{Rows, TransactionBehavior};
8use crate::connection::SqliteConnectionMetadata;
9use rusqlite::Error as RusqliteError;
10use std::sync::{Arc, Mutex};
11use std::rc::Rc;
12use rsdbc_core::connection::{Batch, ConnectionMetadata, IsolationLevel, SQLResult, Statement, ValidationDepth};
13use rsdbc_core::{DatabaseMetadata, Result, ResultSetMetaData};
14
15// https://tedspence.com/investigating-rust-with-sqlite-53d1f9a41112
16// https://www.reddit.com/r/rust/comments/dqa4t3/how_to_put_two_variables_one_borrows_from_other/
17// https://bryce.fisher-fleig.org/strategies-for-returning-references-in-rust/
18
19
20
21/// Convert a Sqlite error into an RSDBC error
22fn to_rsdbc_err(e: rusqlite::Error) -> rsdbc_core::error::RsdbcErrors {
23    rsdbc_core::error::RsdbcErrors::General(format!("{:?}", e))
24}
25
26// #[derive(Debug)]
27// pub enum SqliteError {
28//     General(String),
29//     Unsupported(String),
30// }
31//
32// impl From<RusqliteError> for SqliteError {
33//     fn from(_err: ExecuteReturnedResults) -> Mishap {
34//         General
35//     }
36// }
37
38
39
40// const SQLITE_OPEN_READ_ONLY     = ffi::SQLITE_OPEN_READONLY;
41// /// The database is opened for reading and writing if possible,
42// /// or reading only if the file is write protected by the operating system.
43// /// In either case the database must already exist, otherwise an error is returned.
44// const SQLITE_OPEN_READ_WRITE    = ffi::SQLITE_OPEN_READWRITE;
45// /// The database is created if it does not already exist
46// const SQLITE_OPEN_CREATE        = ffi::SQLITE_OPEN_CREATE;
47// /// The filename can be interpreted as a URI if this flag is set.
48// const SQLITE_OPEN_URI           = 0x0000_0040;
49// /// The database will be opened as an in-memory database.
50// const SQLITE_OPEN_MEMORY        = 0x0000_0080;
51// /// The new database connection will use the "multi-thread" threading mode.
52// const SQLITE_OPEN_NO_MUTEX      = ffi::SQLITE_OPEN_NOMUTEX;
53// /// The new database connection will use the "serialized" threading mode.
54// const SQLITE_OPEN_FULL_MUTEX    = ffi::SQLITE_OPEN_FULLMUTEX;
55// /// The database is opened shared cache enabled.
56// const SQLITE_OPEN_SHARED_CACHE  = 0x0002_0000;
57// /// The database is opened shared cache disabled.
58// const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
59// /// The database filename is not allowed to be a symbolic link.
60// const SQLITE_OPEN_NOFOLLOW = 0x0100_0000;
61
62// these are the default flags
63// OpenFlags::SQLITE_OPEN_READ_WRITE
64// | OpenFlags::SQLITE_OPEN_CREATE
65// | OpenFlags::SQLITE_OPEN_NO_MUTEX
66// | OpenFlags::SQLITE_OPEN_URI
67
68
69// in_memory
70// in_memory with flags
71// path
72// path with flags
73
74pub struct SqliteConnection {
75    // TODO: given Transaction can reference a conn i'm not sure this is feasible
76    // conn: Mutex<Option<&'conn rusqlite::Connection>>,
77    // this needs to be a reference to Rusqlite::Connection otherwise we get an error like
78    // move occurs because `self.conn` has type `Option<rusqlite::Connection>`, which does not implement the `Copy` trait
79    // help: consider borrowing the `Option`'s content: `self.conn.as_ref()`
80    //
81    // because of E0106 it requires a lifetime
82    conn: Option<Arc<Mutex<rusqlite::Connection>>>,
83}
84
85impl SqliteConnection {
86
87    pub fn new(conn: rusqlite::Connection) -> Self {
88        // Self { conn: Mutex::new(Some(conn)), transaction: None }
89        // Self { conn: Some(conn), transaction: None }
90        // Self {
91        //     conn: Some(Rc::new(conn))
92        // }
93        Self {
94            conn: Some(Arc::new(Mutex::new(conn))),
95        }
96    }
97
98    fn drop(&mut self) {
99        // if let Some(transaction) = self.transaction.take() {
100        //     let _ = transaction.rollback();
101        // }
102    }
103}
104
105impl rsdbc_core::connection::Connection for SqliteConnection {
106    // type Statement = SqliteStatement<'conn>;
107
108    // TODO: result?
109    fn begin_transaction(&mut self) -> Result<()> {
110        // TODO: call begin_transaction_with_definition with an empty instance
111        // let mut connection = self.conn.take().unwrap();
112        // let mut connection = self.conn.lock().unwrap().take().unwrap();
113        // connection.transaction().map_err(to_rsdbc_err);
114        // self.transaction = Some(trans);
115        Ok(())
116    }
117
118    // fn begin_transaction_with_definition(&mut self, definition: &dyn TransactionDefinition) {
119    //     // TODO: convert definition to TransactionBehavior
120    //     // let mut connection = self.conn.take().unwrap();
121    //     // let mut connection = self.conn.lock().unwrap().take().unwrap();
122    //     // connection.transaction_with_behavior(TransactionBehavior::Deferred);
123    // }
124
125    // https://www.reddit.com/r/rust/comments/2t8i2s/yet_another_problem_with_mutable_struct_members/
126    // TODO: should return a result
127    fn close(&mut self) -> Result<()> {
128        // let close_result = self.conn.get_mut().unwrap().close();
129
130        // self.conn.lock().unwrap().map(|c| c.close());
131        let mut _c = self.conn.take();
132        // let mut _c = self.conn.get_mut().unwrap().take();
133        _c = None;
134
135        // close_result.map_err(move |e| to_rsdbc_err(e.1))?;
136        Ok(())
137    }
138
139    fn commit_transaction(&mut self) {
140        // if let Some(transaction) = self.transaction.take() {
141        //     let _ = transaction.commit();
142        // }
143    }
144
145    fn create_batch(&mut self) -> Result<Box<dyn Batch>> {
146        todo!()
147    }
148
149    // TODO: return result
150    // UnsupportedOperationException if not supported
151    fn create_savepoint(&mut self, name: &str) {
152        // if self.transaction.is_none() {
153        //     // return error
154        // }
155
156        // let sp = self.conn.savepoint_with_name(name)?;
157        // let savepoint = self.transaction.unwrap().savepoint_with_name(name)?;
158    }
159
160    // fn create_statement(&mut self, sql: &str) -> Result<Box<Self::Statement>> {
161    fn create_statement(&mut self, sql: &str) -> Result<Box<dyn Statement<'_> + '_>> {
162        // let mut c = self.conn.take();
163        // let stmt = c.unwrap()
164        //     .prepare(sql)
165        //     .map_err(to_rsdbc_err)?;
166
167        // let c: &'conn rusqlite::Connection = self.conn.unwrap();
168
169        // let stmt: rusqlite::Statement = self.conn.unwrap()
170        //     .prepare(sql)
171        //     .map_err(to_rsdbc_err)?;
172
173        // let stmt = self.conn.get_mut().unwrap().take().unwrap()
174        //     .prepare(sql)
175        //     .map_err(to_rsdbc_err)?;
176
177        // let stmt = self.conn.lock().unwrap().take().unwrap()
178        //     .prepare(sql)
179        //     .map_err(to_rsdbc_err)?;
180
181        // let stmt = self.conn
182        //     .as_ref()
183        //     .unwrap()
184        //     .clone()
185        //     .deref()
186        //     .lock()
187        //     .unwrap()
188        //     .prepare(sql)
189        //     .map_err(to_rsdbc_err)?;
190        //
191        // Ok(Box::new(SqliteStatement {
192        //     stmt,
193        // }))
194
195        todo!()
196    }
197
198    fn is_auto_commit(&mut self) -> bool {
199        let connection = self.conn.take().unwrap();
200        // let connection = self.conn.lock().unwrap().take().unwrap();
201        connection.clone().deref().lock().unwrap().is_autocommit()
202    }
203
204    fn metadata(&mut self) -> Result<Box<dyn ConnectionMetadata>> {
205        todo!()
206    }
207
208    fn transaction_isolation_level(&mut self) -> IsolationLevel {
209        todo!()
210    }
211
212    fn release_savepoint(&mut self, name: &str) {
213        todo!()
214        // do we need to keep savepoint? I dont see rusqlite giving us an option to get a savepoint
215
216    }
217
218    /// This is equivalent to `Transaction`'s `Drop` implementation, but provides any error
219    /// encountered to the caller.
220    fn rollback_transaction(&mut self) {
221        todo!()
222    }
223
224    fn rollback_transaction_to_savepoint(&mut self, name: String) {
225        todo!()
226    }
227
228    fn auto_commit(&mut self, commit: bool) {
229        todo!()
230        // The sqlite3_get_autocommit() interface returns non-zero or zero if the given database
231        // connection is or is not in autocommit mode, respectively.
232        // Autocommit mode is on by default.
233        // Autocommit mode is disabled by a BEGIN statement. Autocommit mode is re-enabled by a
234        // COMMIT or ROLLBACK.
235    }
236
237    fn set_transaction_isolation_level(&mut self, isolation_level: IsolationLevel) {
238        // Error::Unsupported(String::from(
239        //     "Except in the case of shared cache database connections with PRAGMA read_uncommitted \
240        //     turned on, all transactions in SQLite show \"serializable\" isolation. \
241        //     SQLite implements serializable transactions by actually serializing the writes."
242        // ))
243    }
244
245    fn validate(&mut self, depth: ValidationDepth) -> bool {
246        todo!()
247    }
248}
249
250// impl Drop for SqliteConnection {
251//     fn drop(&mut self) {
252//         let _ = self.close();
253//     }
254// }
255
256// TODO: Do we need this? Can we just use CallableStatement/PreparedStatement
257pub struct SqliteStatement<'a> {
258    stmt: rusqlite::Statement<'a>,
259}
260
261impl rsdbc_core::connection::Statement<'_> for SqliteStatement<'_> {
262    fn add(&mut self) -> &mut Self where Self: Sized {
263        todo!()
264    }
265
266    fn bind_index<T>(&mut self, index: u32, value: T) -> &mut Self where Self: Sized {
267        todo!()
268    }
269
270    fn bind_name<T>(&mut self, name: &str, value: T) -> &mut Self where Self: Sized {
271        todo!()
272    }
273
274    fn bind_null_index(&mut self, index: u32) -> &mut Self where Self: Sized {
275        todo!()
276    }
277
278    fn bind_null_name(&mut self, name: &str) -> &mut Self where Self: Sized {
279        todo!()
280    }
281
282    fn execute<T: SQLResult>(&self) -> Result<T> where Self: Sized {
283        todo!()
284    }
285
286    fn return_generated_values(&mut self, columns: &[&str]) -> &mut Self where Self: Sized {
287        todo!()
288    }
289
290    fn fetch_size(&mut self, rows: u32) -> &mut Self where Self: Sized {
291        todo!()
292    }
293}
294
295struct SqliteResultSet<'stmt> {
296    rows: Rows<'stmt>,
297}
298
299struct SqliteDatabaseMetadata {
300
301}
302
303impl DatabaseMetadata for SqliteDatabaseMetadata {
304
305}
306
307impl<'stmt> rsdbc_core::ResultSet for SqliteResultSet<'stmt> {
308    fn meta_data(&self) -> Result<Box<dyn ResultSetMetaData>> {
309        todo!()
310    }
311
312    fn next(&mut self) -> bool {
313        todo!()
314    }
315
316    fn get_bool(&self, i: u64) -> Result<Option<bool>> {
317        todo!()
318    }
319
320    fn get_i8(&self, i: u64) -> Result<Option<i8>> {
321        todo!()
322    }
323
324    fn get_i16(&self, i: u64) -> Result<Option<i16>> {
325        todo!()
326    }
327
328    fn get_i32(&self, i: u64) -> Result<Option<i32>> {
329        todo!()
330    }
331
332    fn get_i64(&self, i: u64) -> Result<Option<i64>> {
333        todo!()
334    }
335
336    fn get_f32(&self, i: u64) -> Result<Option<f32>> {
337        todo!()
338    }
339
340    fn get_f64(&self, i: u64) -> Result<Option<f64>> {
341        todo!()
342    }
343
344    fn get_string(&self, i: u64) -> Result<Option<String>> {
345        todo!()
346    }
347
348    fn get_bytes(&self, i: u64) -> Result<Option<Vec<u8>>> {
349        todo!()
350    }
351}
352
353fn to_rsdbc_type(t: Option<&str>) -> rsdbc_core::DataType {
354    //TODO implement for real
355    match t {
356        Some("INT") => rsdbc_core::DataType::Integer,
357        _ => rsdbc_core::DataType::Utf8,
358    }
359}
360
361struct Values<'a>(&'a [rsdbc_core::Value]);
362struct ValuesIter<'a>(std::slice::Iter<'a, rsdbc_core::Value>);
363
364impl<'a> IntoIterator for &'a Values<'a> {
365    type Item = &'a dyn rusqlite::types::ToSql;
366    type IntoIter = ValuesIter<'a>;
367
368    fn into_iter(self) -> ValuesIter<'a> {
369        ValuesIter(self.0.iter())
370    }
371}
372impl<'a> Iterator for ValuesIter<'a> {
373    type Item = &'a dyn rusqlite::types::ToSql;
374
375    fn next(&mut self) -> Option<&'a dyn rusqlite::types::ToSql> {
376        self.0.next().map(|v| match v {
377            rsdbc_core::Value::String(ref s) => s as &dyn rusqlite::types::ToSql,
378            rsdbc_core::Value::Int32(ref n) => n as &dyn rusqlite::types::ToSql,
379            rsdbc_core::Value::UInt32(ref n) => n as &dyn rusqlite::types::ToSql,
380        })
381    }
382}
383
384#[cfg(test)]
385mod tests {
386    use super::*;
387    use std::{collections::HashMap, sync::Arc};
388    use crate::options::SqliteConnectOptions;
389
390    // // low-level, Executor trait
391    // conn.execute("BEGIN").await?; // unprepared, simple query
392    // conn.execute(sqlx::query("DELETE FROM table")).await?; // prepared, cached query
393
394    // sqlx::query("DELETE FROM table").execute(&mut conn).await?;
395    // sqlx::query("DELETE FROM table").execute(&pool).await?;
396
397    // let mut rows = sqlx::query("SELECT * FROM users WHERE email = ?")
398    // .bind(email)
399    // .fetch(&mut conn);
400    //
401    // while let Some(row) = rows.try_next().await? {
402    //     // map the row into a user-defined domain type
403    //     let email: &str = row.try_get("email")?;
404    // }
405
406//     let mut stream = sqlx::query("SELECT * FROM users")
407//     .map(|row: PgRow| {
408// // map the row into a user-defined domain type
409// })
410//     .fetch(&mut conn);
411//     #[derive(sqlx::FromRow)]
412//     struct User { name: String, id: i64 }
413//
414//     let mut stream = sqlx::query_as::<_, User>("SELECT * FROM users WHERE email = ? OR name = ?")
415//     .bind(user_email)
416//     .bind(user_name)
417//     .fetch(&mut conn);
418
419
420
421    #[test]
422    fn execute_query() -> rsdbc_core::Result<()> {
423        // let mut connection = SqliteConnectOptions::new().connect().await?;
424        // let stmt = connection.create_statement("SELECT 1").unwrap();
425        // let mut rs = stmt.execute();
426        //
427        // while rs.next() {
428        //     println!("{:?}", rs.get_string(1));
429        // }
430
431        Ok(())
432    }
433
434    // #[test]
435    // fn execute_query() -> rsdbc::Result<()> {
436    //     let driver: Arc<dyn rsdbc::Driver> = Arc::new(SqliteDriver::new());
437    //     let url = "";
438    //     let mut conn = driver.connect(url, HashMap::new())?;
439    //     execute(&mut *conn, "DROP TABLE IF EXISTS test", &vec![])?;
440    //     execute(&mut *conn, "CREATE TABLE test (a INT NOT NULL)", &vec![])?;
441    //     execute(
442    //         &mut *conn,
443    //         "INSERT INTO test (a) VALUES (?)",
444    //         &vec![rsdbc::Value::Int32(123)],
445    //     )?;
446    //
447    //     let mut stmt = conn.prepare("SELECT a FROM test")?;
448    //     let mut rs = stmt.execute_query(&vec![])?;
449    //
450    //     let meta = rs.meta_data()?;
451    //     assert_eq!(1, meta.num_columns());
452    //     assert_eq!("a".to_owned(), meta.column_name(0));
453    //     assert_eq!(DataType::Integer, meta.column_type(0));
454    //
455    //     assert!(rs.next());
456    //     assert_eq!(Some(123), rs.get_i32(0)?);
457    //     assert!(!rs.next());
458    //
459    //     Ok(())
460    // }
461
462    // fn execute(
463    //     conn: &mut dyn Connection,
464    //     sql: &str,
465    //     values: &Vec<rsdbc::Value>,
466    // ) -> rsdbc::Result<u64> {
467    //     println!("Executing '{}' with {} params", sql, values.len());
468    //     let mut stmt = conn.prepare(sql)?;
469    //     stmt.execute_update(values)
470    // }
471}