A bit of a lifetime issue in a trait

⚓ Rust    📅 2025-07-13    👤 surdeus    👁️ 2      

surdeus

Greetings, I'm trying to have a trait that can be implemented in any sqlx executor. I'm using Postgres, so in my case these would be &PgPool and &mut PgConnection. The use case here is that I want to be able to have certain methods work on both a &PgPool and a &mut PgTransaction instance, where the latter implements Deref + DerefMut<Target = PgConnection>.

This is how I'm trying to approach this:

Cargo.toml:

[dependencies.sqlx]
version = "0.8.6"
features = [
    "bigdecimal",
    "chrono",
    "json",
    "postgres",
    "runtime-tokio",
    "tls-native-tls",
]
use sqlx::{Error, PgConnection, PgExecutor, PgPool};

trait Schema: Clone + Send + Sync + 'static
where
    for<'a> &'a mut Self::Connection: DbInteraction<'a>,
    for<'a> &'a Self: DbInteraction<'a>,
{
    type Connection;
    type Transaction: Deref + DerefMut<Target = Self::Connection>;

    async fn begin_transaction(&self) -> Result<Self::Transaction, Error>;
}

impl Schema for PgPool {
    type Connection = PgConnection;

    type Transaction = sqlx::Transaction<'static, sqlx::Postgres>;

    async fn begin_transaction(&self) -> Result<Self::Transaction, Error> {
        Ok(self.begin().await?)
    }
}

async fn use_schema<P: Schema>(pool: P) -> Result<(), Error> {
    // let mut txn = pool.begin_transaction().await?;
    // let res = pool.get_an_integer().await?;
    Ok(())
}

trait DbInteraction<'a> {
    async fn get_an_integer(self) -> Result<i64, Error>;
}

impl<'a, E: PgExecutor<'a>> DbInteraction<'a> for E {
    async fn get_an_integer(self) -> Result<i64, Error> {
        let res: i64 = sqlx::query_scalar("SELECT scalar FROM some_table")
            .fetch_one(self)
            .await?;

        Ok(res)
    }
}

This does not work, I'm getting the following error: the trait bound `for<'a> &'a mut <P as Schema>::Connection: Executor<'_>` is not satisfied.

To me, this indicates that the trait resolver does not tie together the lifetime of PgExecutor and DbInteraction, which I think it should, based on the following: impl<'a, E: PgExecutor<'a>> DbInteraction<'a> for E.

It's also strange that impl Schema for PgPool in itself is not a problem, it only reports an error when I try to use the trait.

I'm grateful for any comments and ideas, you can tell me if what I want to do does not make sense in the first place, etc.

1 post - 1 participant

Read full topic

🏷️ rust_feed