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