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