rdbc_sqlite/
lib.rs

1//! SQLite RDBC Driver
2//!
3//! This crate implements an RDBC Driver for the `rusqlite` crate.
4//!
5//! The RDBC (Rust DataBase Connectivity) API is loosely based on the ODBC and JDBC standards.
6//!
7//! ```rust
8//! use std::sync::Arc;
9//! use rdbc::{self, Value};
10//! use rdbc_sqlite::SqliteDriver;
11//! let driver: Arc<dyn rdbc::Driver> = Arc::new(SqliteDriver::new());
12//! let conn = driver.connect("").unwrap();
13//! let mut conn = conn.borrow_mut();
14//! let stmt = conn.prepare("CREATE TABLE test (a INT NOT NULL)").unwrap().borrow_mut().execute_update(&vec![]).unwrap();
15//! let stmt = conn.prepare("INSERT INTO test (a) VALUES (?)").unwrap().borrow_mut().execute_update(&vec![rdbc::Value::Int32(123)]).unwrap();
16//! let stmt = conn.prepare("SELECT a FROM test").unwrap();
17//! let mut stmt = stmt.borrow_mut();
18//! let rs = stmt.execute_query(&vec![]).unwrap();
19//! assert!(rs.as_ref().borrow_mut().next());
20//! assert_eq!(Some(123), rs.as_ref().borrow_mut().get_i32(0).unwrap());
21//! ```
22
23use std::cell::RefCell;
24use std::rc::Rc;
25
26use fallible_streaming_iterator::FallibleStreamingIterator;
27use rdbc;
28use rusqlite::Rows;
29
30/// Convert a Sqlite error into an RDBC error
31fn to_rdbc_err(e: &rusqlite::Error) -> rdbc::Error {
32    rdbc::Error::General(format!("{:?}", e))
33}
34
35pub struct SqliteDriver {}
36
37impl SqliteDriver {
38    pub fn new() -> Self {
39        SqliteDriver {}
40    }
41}
42
43impl rdbc::Driver for SqliteDriver {
44    fn connect(&self, _url: &str) -> rdbc::Result<Rc<RefCell<dyn rdbc::Connection + 'static>>> {
45        rusqlite::Connection::open_in_memory()
46            .map_err(|e| to_rdbc_err(&e))
47            .map(|c| {
48                Ok(Rc::new(RefCell::new(SConnection::new(c))) as Rc<RefCell<dyn rdbc::Connection>>)
49            })?
50    }
51}
52
53struct SConnection {
54    conn: rusqlite::Connection,
55}
56
57impl SConnection {
58    pub fn new(conn: rusqlite::Connection) -> Self {
59        Self { conn }
60    }
61}
62
63impl rdbc::Connection for SConnection {
64    fn create(&mut self, sql: &str) -> rdbc::Result<Rc<RefCell<dyn rdbc::Statement + '_>>> {
65        self.prepare(sql)
66    }
67
68    fn prepare(&mut self, sql: &str) -> rdbc::Result<Rc<RefCell<dyn rdbc::Statement + '_>>> {
69        let stmt = self.conn.prepare(sql).map_err(|e| to_rdbc_err(&e))?;
70        Ok(Rc::new(RefCell::new(SStatement { stmt })) as Rc<RefCell<dyn rdbc::Statement>>)
71    }
72}
73
74struct SStatement<'a> {
75    stmt: rusqlite::Statement<'a>,
76}
77
78impl<'a> rdbc::Statement for SStatement<'a> {
79    fn execute_query(
80        &mut self,
81        params: &[rdbc::Value],
82    ) -> rdbc::Result<Rc<RefCell<dyn rdbc::ResultSet + '_>>> {
83        let params = to_sqlite_value(params);
84        let params: Vec<&dyn rusqlite::types::ToSql> = params.iter().map(|v| v.as_ref()).collect();
85        let rows = self.stmt.query(&params).map_err(|e| to_rdbc_err(&e))?;
86        return Ok(Rc::new(RefCell::new(SResultSet { rows })) as Rc<RefCell<dyn rdbc::ResultSet>>);
87    }
88
89    fn execute_update(&mut self, params: &[rdbc::Value]) -> rdbc::Result<u64> {
90        let params = to_sqlite_value(params);
91        let params: Vec<&dyn rusqlite::types::ToSql> = params.iter().map(|v| v.as_ref()).collect();
92        return self
93            .stmt
94            .execute(&params)
95            .map_err(|e| to_rdbc_err(&e))
96            .map(|n| n as u64);
97    }
98}
99
100struct SResultSet<'stmt> {
101    rows: Rows<'stmt>,
102}
103
104impl<'stmt> rdbc::ResultSet for SResultSet<'stmt> {
105    fn meta_data(&self) -> rdbc::Result<Rc<dyn rdbc::ResultSetMetaData>> {
106        let meta: Vec<rdbc::Column> = self
107            .rows
108            .columns()
109            .unwrap()
110            .iter()
111            .map(|c| rdbc::Column::new(c.name(), to_rdbc_type(c.decl_type())))
112            .collect();
113        Ok(Rc::new(meta))
114    }
115
116    fn next(&mut self) -> bool {
117        self.rows.next().unwrap().is_some()
118    }
119
120    fn get_i8(&self, i: u64) -> rdbc::Result<Option<i8>> {
121        self.rows
122            .get()
123            .unwrap()
124            .get(i as usize)
125            .map_err(|e| to_rdbc_err(&e))
126    }
127
128    fn get_i16(&self, i: u64) -> rdbc::Result<Option<i16>> {
129        self.rows
130            .get()
131            .unwrap()
132            .get(i as usize)
133            .map_err(|e| to_rdbc_err(&e))
134    }
135
136    fn get_i32(&self, i: u64) -> rdbc::Result<Option<i32>> {
137        self.rows
138            .get()
139            .unwrap()
140            .get(i as usize)
141            .map_err(|e| to_rdbc_err(&e))
142    }
143
144    fn get_i64(&self, i: u64) -> rdbc::Result<Option<i64>> {
145        self.rows
146            .get()
147            .unwrap()
148            .get(i as usize)
149            .map_err(|e| to_rdbc_err(&e))
150    }
151
152    fn get_f32(&self, _i: u64) -> rdbc::Result<Option<f32>> {
153        Err(rdbc::Error::General("f32 not supported".to_owned()))
154    }
155
156    fn get_f64(&self, i: u64) -> rdbc::Result<Option<f64>> {
157        self.rows
158            .get()
159            .unwrap()
160            .get(i as usize)
161            .map_err(|e| to_rdbc_err(&e))
162    }
163
164    fn get_string(&self, i: u64) -> rdbc::Result<Option<String>> {
165        self.rows
166            .get()
167            .unwrap()
168            .get(i as usize)
169            .map_err(|e| to_rdbc_err(&e))
170    }
171
172    fn get_bytes(&self, i: u64) -> rdbc::Result<Option<Vec<u8>>> {
173        self.rows
174            .get()
175            .unwrap()
176            .get(i as usize)
177            .map_err(|e| to_rdbc_err(&e))
178    }
179}
180
181fn to_rdbc_type(t: Option<&str>) -> rdbc::DataType {
182    //TODO implement for real
183    match t {
184        Some("INT") => rdbc::DataType::Integer,
185        _ => rdbc::DataType::Utf8,
186    }
187}
188
189fn to_sqlite_value(values: &[rdbc::Value]) -> Vec<Box<dyn rusqlite::types::ToSql>> {
190    values
191        .iter()
192        .map(|v| match v {
193            rdbc::Value::String(s) => Box::new(s.clone()) as Box<dyn rusqlite::types::ToSql>,
194            rdbc::Value::Int32(n) => Box::new(*n) as Box<dyn rusqlite::types::ToSql>,
195            rdbc::Value::UInt32(n) => Box::new(*n) as Box<dyn rusqlite::types::ToSql>,
196        })
197        .collect()
198}
199#[cfg(test)]
200mod tests {
201    use super::*;
202    use rdbc::{Connection, DataType};
203    use std::sync::Arc;
204
205    #[test]
206    fn execute_query() -> rdbc::Result<()> {
207        let driver: Arc<dyn rdbc::Driver> = Arc::new(SqliteDriver::new());
208        let url = "";
209        let mut conn = driver.connect(url)?;
210        execute(&mut conn, "DROP TABLE IF EXISTS test", &vec![])?;
211        execute(&mut conn, "CREATE TABLE test (a INT NOT NULL)", &vec![])?;
212        execute(
213            &mut conn,
214            "INSERT INTO test (a) VALUES (?)",
215            &vec![rdbc::Value::Int32(123)],
216        )?;
217
218        let mut conn = conn.as_ref().borrow_mut();
219        let stmt = conn.prepare("SELECT a FROM test")?;
220        let mut stmt = stmt.borrow_mut();
221        let rs = stmt.execute_query(&vec![])?;
222
223        let mut rs = rs.as_ref().borrow_mut();
224
225        let meta = rs.meta_data()?;
226        assert_eq!(1, meta.num_columns());
227        assert_eq!("a".to_owned(), meta.column_name(0));
228        assert_eq!(DataType::Integer, meta.column_type(0));
229
230        assert!(rs.next());
231        assert_eq!(Some(123), rs.get_i32(0)?);
232        assert!(!rs.next());
233
234        Ok(())
235    }
236
237    fn execute(
238        conn: &mut Rc<RefCell<dyn Connection>>,
239        sql: &str,
240        values: &Vec<rdbc::Value>,
241    ) -> rdbc::Result<u64> {
242        println!("Executing '{}' with {} params", sql, values.len());
243        let mut conn = conn.as_ref().borrow_mut();
244        let stmt = conn.prepare(sql)?;
245        let mut stmt = stmt.borrow_mut();
246        stmt.execute_update(values)
247    }
248}