I'm trying to make functions work with both PgPool
and PgTransaction
. The PgExecutor
seems to be meant for this. But I can't understand how to pass it around. It's implemented for PgPool
, which is Clone
and PgConnection
which isn't, so I can't just add the Clone
bound.
Here's a runnable example:
use sqlx::{PgExecutor, PgPool};
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = PgPool::connect("postgres:///").await?;
let mut tx = pool.begin().await?;
outer(&mut *tx).await?;
tx.commit().await
}
async fn outer(db: impl PgExecutor<'_>) -> sqlx::Result<()> {
dbg!(inner(db, "first").await?);
// The second invocation doesn't compile:
// use of moved value: `db` value used here after move
dbg!(inner(db, "second").await?);
Ok(())
}
async fn inner(db: impl PgExecutor<'_>, name: &str) -> sqlx::Result<String> {
sqlx::query_scalar!(r#"SELECT $1 as "name!""#, name)
.fetch_one(db)
.await
}
Jofas from the Rust Forum found the solution that allows both outer
and inner
be compatible with the PgPool
and PgConnection
:
use sqlx::{Acquire, PgExecutor, PgPool, Postgres};
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = PgPool::connect("postgres:///").await?;
let mut tx = pool.begin().await?;
outer(&mut *tx).await?;
tx.commit().await
}
async fn outer(db: impl Acquire<'_, Database = Postgres>) -> sqlx::Result<()> {
let mut connection = db.acquire().await?;
dbg!(inner(&mut *connection, "first").await?);
dbg!(inner(&mut *connection, "second").await?);
Ok(())
}
async fn inner(db: impl PgExecutor<'_>, name: &str) -> sqlx::Result<String> {
sqlx::query_scalar!(r#"SELECT $1 as "name!""#, name)
.fetch_one(db)
.await
}
Though in complicated scenarios, there's a lifetime issue with the Acquire approach, forcing you to resort to the Connection-based approach:
implementation of `sqlx::Acquire` is not general enough
= note: `sqlx::Acquire<'_>` would have to be implemented for the type `&mut PgConnection`
= note: ...but `sqlx::Acquire<'0>` is actually implemented for the type `&'0 mut PgConnection`, for some specific lifetime `'0`