Closed dave42w closed 3 months ago
Tx
is designed as an extractor, whose only constructor is from_request_parts
.
I'd suggest you update your db functions to take a Transaction<'_, Postgres>
and when you call them you can pass &mut *tx
to invoke DerefMut
, which will give you a Transaction<'_, _>
.
async fn insert(
tx: &mut Transaction<'_, Postgres>,
user_name: &str,
display_name: &str,
is_admin: bool,
email: &str,
mobile_phone: &str,
) -> Result<(), Error> {
#[sqlx::test]
async fn insert_duplicate_check(pool: PgPool) -> sqlx::Result<(), sqlx::Error> {
let mut t = pool.begin().await.unwrap;
// should be able to insert a user but not insert a duplicate user
assert_eq!(insert(&mut t, "Dave", "Dave Warnock", true, "dwarnock@test.com", "01234567891").await.is_ok(), true);
assert_eq!(insert(&mut t, "Dave", "Dave Warnock", true, "dwarnock@test.com", "01234567891").await.is_err(), true);
Ok(())
}
// some handler
async function handler(mut tx: Tx) -> impl IntoResponse {
let result = insert(&mut *tx, /* ... */).await;
// ...
}
I've just started writing a crate axum-tenancy which uses axum-sql-tx
However, I'm not sure how my test code gets a Tx to pass to my db functions that I call with a Tx from my handlers. My naive pool.begin doesn't compile:
For info all my db functions take a Tx argument eg
that means I can safely combine them in multiple ways from handlers (eg from a single handler call the insert functions for user, tenant and user-tenant).
By always using a Tx my functions can be simpler, they don't need to worry about different types of Executor (pool, connection, transaction) which also reduces testing (I only need to test them with a transaction).