I need to wrap Sqlx connection and Transaction
types into my corresponding opaque types that will implement domain-specific data access methods. Trying to achieve that I'm struggling to support spawning of transactions. Here is my simplified code:
use sqlx::{
Connection, Database, Sqlite, SqliteConnection as SqlxSqliteConnection,
Transaction as SqlxTransaction,
};
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("unknown error")]
Unknown,
}
pub type Result<T> = std::result::Result<T, Error>;
pub type Future<'a, T> = Pin<Box<dyn std::future::Future<Output = T> + Send + 'a>>;
pub struct Transaction<'c, DB: Database>(SqlxTransaction<'c, DB>);
pub trait DataConn<'c, DB: Database>
where
&'c mut Transaction<'c, DB>: DataTx<'c, DB>,
{
fn begin(self) -> Future<'c, Result<Transaction<'c, DB>>>;
}
pub trait DataTx<'c, DB: Database>
where
&'c mut Transaction<'c, DB>: DataTx<'c, DB>,
{
fn begin(self) -> Future<'c, Result<Transaction<'c, DB>>>;
}
pub struct SqliteConnection(SqlxSqliteConnection);
impl<'c> DataConn<'c, Sqlite> for &'c mut SqliteConnection {
fn begin(self) -> Future<'c, Result<Transaction<'c, Sqlite>>> {
Box::pin(async move {
Ok(Transaction(Connection::begin(&mut self.0).await?))
})
}
}
impl<'c> DataTx<'c, Sqlite> for &'c mut Transaction<'c, Sqlite> {
fn begin(self) -> Future<'c, Result<Transaction<'c, Sqlite>>> {
Box::pin(async move { Ok(Transaction(self.0.begin().await?)) })
}
}
#[cfg(test)]
mod test {
use super::*;
async fn test_transactions<'c, DB, Conn>(conn: Conn)
where
DB: Database,
Conn: DataConn<'c, DB>,
&'c mut Transaction<'c, DB>: DataTx<'c, DB>,
{
let mut tx = conn.begin().await.unwrap();
let tx2 = tx.begin().await.unwrap(); // fails here
}
}
As a result I get the following error details:
error[E0597]: `tx` does not live long enough
--> src/data2/mod.rs:54:19
|
47 | async fn test_transactions<'c, DB, Conn>(conn: Conn)
| -- lifetime `'c` defined here
...
54 | let tx2 = tx.begin().await.unwrap();
| ^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `tx` is borrowed for `'c`
...
57 | }
| - `tx` dropped here while still borrowed
For more information about this error, try `rustc --explain E0597`.
Can you explain why tx2
does outlive tx
in the test function below and how I can fix that?