Skip to content

Unable to abstract over Pool and Transaction #1441

@Wopple

Description

@Wopple

I've been fighting with this for some time now, and I've only been able to manage partial solutions. I have not reached a full solution for what should logically be possible.

I understand there is a fundamental difference between a pool and a transaction. A pool can spawn multiple connections which would be reasonable to schedule as separate async blocks running in parallel. A transaction is a single connection which cannot support parallel execution. However, given the common pattern of async and then immediately await before the next async, it should be able possible to use a transaction the same as a pool in that scenario.

What I've found that works is:

pub async fn foo(conn: &mut PgConnection) -> Result<i32, sqlx::Error> {
    sqlx::query("SELECT 1 AS v")
        .map(|row: PgRow| row.get("v"))
        .fetch_one(conn)
        .await
}

let pool: PgPool;
let pool_conn = &mut *pool.acquire().await?;
let mut tx = pool.begin().await?;

foo(pool_conn).await();
foo(pool_conn).await();

foo(&mut tx).await();
foo(&mut tx).await();

Despite being able to call the foo function multiple times, the limitation here is the &mut PgConnection inside foo can only be used once. When you call fetch_one, it gets derefed and moved internally. There's an idea where you can abstract over Acquire<Connection = Connection<Postgres>> so you can pass in something that can acquire a connection, but pools implement Acquire for PoolConnection which is different from Connection. I have not found a way to smooth over that discrepancy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions