Skip to main content

datasources_sqlite/
lib.rs

1mod alter_table_statement_renderer;
2mod command;
3mod connection;
4mod connection_string;
5mod converters;
6mod create_table_statement_renderer;
7mod create_trigger_statement_renderer;
8mod driver;
9mod reader;
10mod select_inserted_id_statement_text_renderer;
11mod sqlite_path;
12mod default_value_converter;
13mod default_value_options;
14mod sql_generate;
15mod sql_seed_statement_renderer;
16mod type_map;
17mod quoted_renderers;
18mod statement_renderer;
19mod transaction;
20
21pub use driver::SqliteDriver;
22
23#[cfg(test)]
24pub(crate) fn env_lock() -> std::sync::MutexGuard<'static, ()> {
25    static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
26    let guard = LOCK.lock().unwrap_or_else(|error| error.into_inner());
27    std::env::remove_var("INSTALLED_PROVIDERS");
28    std::env::remove_var("DATASOURCE_URL");
29    std::env::set_var("PROVIDER", "sqlite");
30    datasources::reset();
31    datasources::register("sqlite", std::sync::Arc::new(crate::SqliteDriver));
32    guard
33}
34
35#[cfg(test)]
36#[path = "../tests/command.rs"]
37mod command_tests;
38#[cfg(test)]
39#[path = "../tests/contacts.rs"]
40mod contacts;
41#[cfg(test)]
42#[path = "../tests/create_from_driver.rs"]
43mod create_from_driver;
44#[cfg(test)]
45#[path = "../tests/datasource_plural.rs"]
46mod datasource_plural;
47#[cfg(test)]
48#[path = "../tests/integration.rs"]
49mod integration;
50#[cfg(test)]
51#[path = "../tests/null_write.rs"]
52mod null_write;
53#[cfg(test)]
54#[path = "../tests/read_pipeline.rs"]
55mod read_pipeline;
56#[cfg(test)]
57#[path = "../tests/readonly_repository.rs"]
58mod readonly_repository;
59#[cfg(test)]
60#[path = "../tests/repository_spec.rs"]
61mod repository_spec;
62#[cfg(test)]
63#[path = "../tests/foreign_key_type.rs"]
64mod foreign_key_type;
65#[cfg(test)]
66#[path = "../tests/generate_sql.rs"]
67mod generate_sql;
68#[cfg(test)]
69#[path = "../tests/typed_list_enrichment.rs"]
70mod typed_list_enrichment;
71
72#[cfg(test)]
73mod tests {
74    use crate::command::SqliteCommand;
75    use crate::connection::SqliteConnection;
76    use crate::transaction::SqliteTransaction;
77    use datasources::{
78        Row, create, downcast_connection, register, reset, BuiltDatasource, Command,
79        Connection, Datasource, Driver, IsolationLevel, Transaction,
80    };
81    use std::collections::HashMap;
82    use std::sync::Arc;
83
84    struct With(Option<String>);
85
86    impl Driver for With {
87        fn connection(&self, _: Option<&HashMap<String, String>>) -> Arc<dyn Connection> {
88            Arc::new(SqliteConnection::new(self.0.clone()))
89        }
90
91        fn command(&self, connection: Arc<dyn Connection>) -> Arc<dyn Command> {
92            connection.create_command()
93        }
94
95        fn transaction(
96            &self,
97            connection: Arc<dyn Connection>,
98            isolation: IsolationLevel,
99        ) -> Arc<dyn Transaction> {
100            let conn = downcast_connection::<SqliteConnection>(connection).expect("sqlite");
101            Arc::new(SqliteTransaction::new(conn.share(), isolation))
102        }
103
104        fn row_type_converters(
105            &self,
106        ) -> HashMap<
107            String,
108            Box<
109                dyn datasources::TypeConverter<datasources::Value, datasources::Value>
110                    + Send
111                    + Sync,
112            >,
113        > {
114            crate::converters::row_type_converters()
115        }
116    }
117
118    #[tokio::test]
119    async fn sqlite_command_and_repository() {
120        let conn = Arc::new(SqliteConnection::new(Some(":memory:".into())));
121        conn.open().await.unwrap();
122        let command = SqliteCommand::new(conn.clone());
123        command
124            .execute_native(&datasources::Native::new(""), None)
125            .await
126            .unwrap();
127        command
128            .execute_native(
129                &datasources::Native::new("CREATE TABLE t (id INTEGER)"),
130                None,
131            )
132            .await
133            .unwrap();
134        command
135            .execute_native(
136                &datasources::Native::new("INSERT INTO t (id) VALUES (1) RETURNING id"),
137                None,
138            )
139            .await
140            .unwrap();
141        command
142            .execute_reader_native(&datasources::Native::new("SELECT 1"), None)
143            .await
144            .unwrap();
145        let sets = command
146            .execute_reader_native(
147                &datasources::Native::new("SELECT 1 AS id; SELECT 2 AS id"),
148                None,
149            )
150            .await
151            .unwrap();
152        let mut first = Vec::new();
153        while sets.next().await.unwrap() {
154            first.push(sets.current());
155        }
156        let moved = sets.next_result().await.unwrap();
157        let mut second = Vec::new();
158        while sets.next().await.unwrap() {
159            second.push(sets.current());
160        }
161        assert!(moved);
162        assert_eq!(
163            first[0].as_ref().unwrap().get("id"),
164            Some(&datasources::Value::Int(1))
165        );
166        assert_eq!(
167            second[0].as_ref().unwrap().get("id"),
168            Some(&datasources::Value::Int(2))
169        );
170        assert!(!sets.next_result().await.unwrap());
171        drop(sets);
172        command
173            .execute_reader_native(&datasources::Native::new(""), None)
174            .await
175            .unwrap();
176        let txn = conn.start_transaction(None).await.unwrap();
177        assert_eq!(
178            datasources::Transaction::isolation(&*txn),
179            IsolationLevel::ReadCommitted
180        );
181        txn.commit().await.unwrap();
182        let txn = conn
183            .start_transaction(Some(IsolationLevel::ReadUncommitted))
184            .await
185            .unwrap();
186        assert_eq!(
187            datasources::Transaction::isolation(&*txn),
188            IsolationLevel::ReadUncommitted
189        );
190        txn.abort().await.unwrap();
191        conn.close().await.unwrap();
192        assert!(conn.ensure_open().is_err());
193        assert!(conn.start_transaction(None).await.is_err());
194
195        let shared = Arc::new(SqliteConnection::new(Some(
196            "file:iso?mode=memory&cache=shared".into(),
197        )));
198        shared.open().await.unwrap();
199        let read_committed = shared
200            .start_transaction(Some(IsolationLevel::ReadCommitted))
201            .await
202            .unwrap();
203        assert_eq!(
204            datasources::Transaction::isolation(&*read_committed),
205            IsolationLevel::ReadCommitted
206        );
207        read_committed.abort().await.unwrap();
208        shared.close().await.unwrap();
209
210        let defaulted = SqliteConnection::new(None);
211        assert_eq!(defaulted.filename, ":memory:");
212        reset();
213        register("sqlite", Arc::new(With(Some(":memory:".into()))));
214        let ds = create(Some(&HashMap::from([("PROVIDER".into(), "sqlite".into())]))).unwrap();
215        assert_eq!(ds.provider(), "sqlite");
216        ds.create_connection().await.unwrap();
217        let command = ds.create_command(None).await.unwrap();
218        assert!(command.execute("DELETE FROM items", None).await.is_err());
219        command
220            .execute_reader_native(&datasources::Native::new("SELECT 1"), None)
221            .await
222            .unwrap();
223        ds.create_repository::<Row>(None, None);
224        let factory = BuiltDatasource::new("sqlite", Arc::new(With(None)), None);
225        factory.create_connection().await.unwrap();
226        let bound = factory
227            .create_command(Some(factory.create_connection().await.unwrap()))
228            .await
229            .unwrap();
230        assert!(bound.execute("DELETE FROM items", None).await.is_err());
231        assert!(bound
232            .execute_reader_native(&datasources::Native::new("SELECT 1"), None)
233            .await
234            .is_err());
235        (&factory as &dyn Datasource)
236            .create_repository::<Row>(Some(factory.create_connection().await.unwrap()), None);
237
238        let closed = Arc::new(SqliteConnection::new(None));
239        assert!(SqliteCommand::new(closed)
240            .execute_native(&datasources::Native::new("x"), None)
241            .await
242            .is_err());
243    }
244
245    #[tokio::test]
246    async fn return_statement_selects_scalar() {
247        use datasources::{Parameter, ReturnStatement};
248        let conn = Arc::new(SqliteConnection::new(Some(":memory:".into())));
249        conn.open().await.unwrap();
250        let command = SqliteCommand::new(conn);
251        let parameters = [Parameter::new("x", -3_i64)];
252        let response = command
253            .execute_statement(&ReturnStatement::new("abs", &parameters), Some(&parameters))
254            .await
255            .unwrap();
256        assert_eq!(response.result, datasources::Value::Int(3));
257    }
258}