premix_core/
test_utils.rs

1use std::future::Future;
2use std::pin::Pin;
3
4use sqlx::Database;
5
6/// Run an async test block inside a transaction that is always rolled back.
7pub async fn with_test_transaction<DB, F, T>(pool: &sqlx::Pool<DB>, f: F) -> Result<T, sqlx::Error>
8where
9    DB: Database,
10    for<'c> &'c mut <DB as Database>::Connection: sqlx::Executor<'c, Database = DB>,
11    F: for<'c> FnOnce(
12        &'c mut <DB as Database>::Connection,
13    ) -> Pin<Box<dyn Future<Output = Result<T, sqlx::Error>> + 'c>>,
14{
15    let mut tx = pool.begin().await?;
16    let result = f(tx.as_mut()).await;
17    let rollback_result = tx.rollback().await;
18
19    match (result, rollback_result) {
20        (Ok(value), Ok(_)) => Ok(value),
21        (Err(err), _) => Err(err),
22        (Ok(_), Err(err)) => Err(err),
23    }
24}
25
26/// Lightweight test helper for constructing a dedicated pool.
27pub struct MockDatabase<DB: Database> {
28    pool: sqlx::Pool<DB>,
29}
30
31impl<DB: Database> MockDatabase<DB> {
32    pub fn pool(&self) -> &sqlx::Pool<DB> {
33        &self.pool
34    }
35
36    pub fn into_pool(self) -> sqlx::Pool<DB> {
37        self.pool
38    }
39}
40
41#[cfg(feature = "sqlite")]
42impl MockDatabase<sqlx::Sqlite> {
43    pub async fn new_sqlite() -> Result<Self, sqlx::Error> {
44        let pool = sqlx::sqlite::SqlitePoolOptions::new()
45            .max_connections(1)
46            .connect("sqlite::memory:")
47            .await?;
48        Ok(Self { pool })
49    }
50}