From 9825c202cdcbea7cce67855455d9761473859f69 Mon Sep 17 00:00:00 2001 From: Randolf Jung Date: Mon, 13 Apr 2026 02:59:54 -0700 Subject: [PATCH] feat: support PoolConnection and other executor types via AsExecutor trait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the `for<'c> &'c mut E: sqlx::Executor<'c, Database = Postgres>` bound on `Queries` with a generated `AsExecutor` trait. The new trait has impls for `PgPool`, `&PgPool`, `PgConnection`, `Transaction`, `PoolConnection`, and `&mut T` — fixing the gap where `PoolConnection` deref'd executors previously required a manual `&mut *conn` at call sites, and also the cases `&PgPool`, `&mut PgConnection`, and `&mut Transaction` which the README claimed worked but didn't type-check. Co-Authored-By: Claude Opus 4.6 (1M context) --- Cargo.lock | 2 + README.md | 10 +- examples/advanced-types/src/queries.rs | 79 ++++++++-- examples/basic/src/queries.rs | 75 ++++++++-- examples/batch/Cargo.toml | 2 + examples/batch/src/main.rs | 12 +- examples/batch/src/queries.rs | 139 ++++++++++++++---- examples/enums/src/main.rs | 11 +- examples/enums/src/queries.rs | 95 +++++++++--- src/codegen/batch.rs | 18 +-- src/codegen/copyfrom.rs | 2 +- src/codegen/mod.rs | 42 +++++- src/codegen/query.rs | 24 +-- .../codegen__batch_dynamic_slice_param.snap | 47 +++++- tests/snapshots/codegen__batchexec.snap | 50 ++++++- tests/snapshots/codegen__batchmany.snap | 47 +++++- tests/snapshots/codegen__batchone.snap | 47 +++++- tests/snapshots/codegen__composite_types.snap | 40 +++++ tests/snapshots/codegen__copyfrom.snap | 51 ++++++- .../codegen__dynamic_slice_param.snap | 47 +++++- tests/snapshots/codegen__embed.snap | 47 +++++- tests/snapshots/codegen__enum_types.snap | 47 +++++- tests/snapshots/codegen__exec.snap | 47 +++++- tests/snapshots/codegen__execlastid.snap | 47 +++++- tests/snapshots/codegen__execresult.snap | 47 +++++- tests/snapshots/codegen__execrows.snap | 47 +++++- tests/snapshots/codegen__many.snap | 49 +++++- ...codegen__multidimensional_array_types.snap | 47 +++++- tests/snapshots/codegen__named_params.snap | 47 +++++- .../codegen__nullable_named_param.snap | 47 +++++- tests/snapshots/codegen__one.snap | 47 +++++- tests/snapshots/codegen__range_types.snap | 47 +++++- tests/snapshots/codegen__slice_param.snap | 47 +++++- 33 files changed, 1248 insertions(+), 205 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9239de7..b4b53f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,6 +187,8 @@ dependencies = [ name = "batch" version = "0.1.0" dependencies = [ + "futures-core", + "futures-util", "sqlx", "tokio", ] diff --git a/README.md b/README.md index 3e7c30b..51e7a89 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,18 @@ For each SQL query annotated with a sqlc command, the plugin emits: - An optional params struct (`QueryNameParams`) when a query has 2+ parameters. - A `&mut self` method on `pub struct Queries` that executes the query. -`Queries` wraps an executor once at construction. Pass `&pool` for pool usage or `&mut tx` for transactions: +`Queries` wraps anything implementing the generated `AsExecutor` trait. `AsExecutor` is implemented for `PgPool`, `&PgPool`, `PgConnection`, `Transaction<'_, Postgres>`, `PoolConnection`, and `&mut T` of each: ```rust +// From a pool: let mut q = Queries::new(&pool); let author = q.get_author(1).await?; +// Borrowed or owned pool connection: +let mut conn = pool.acquire().await?; +let mut q = Queries::new(&mut conn); +// ...or Queries::new(conn) to take ownership. + // Transactions: let mut tx = pool.begin().await?; let mut q = Queries::new(&mut tx); @@ -126,7 +132,7 @@ Array types (`type[]`) become `Vec`. Nullable columns become `Option`. | `:batchmany` | `impl Stream, sqlx::Error>>` | Lazily fetch all rows per item | | `:copyfrom` | `Result` | Chunked bulk insert from any `IntoIterator` | -All functions are `&mut self` methods on `Queries`. The bound `for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>` is satisfied by `&PgPool`, `&mut PgConnection`, and `&mut Transaction<'_, Postgres>`. +All functions are `&mut self` methods on `Queries`. The bound is `E: AsExecutor`, where `AsExecutor` is the trait emitted in each generated file. Impls cover `PgPool`, `&PgPool`, `PgConnection`, `Transaction<'_, Postgres>`, `PoolConnection`, and `&mut T` of each. Batch methods generate `Stream`-returning APIs and reference `futures_core` and `futures_util` directly. Consumer crates should include those dependencies alongside `sqlx`. diff --git a/examples/advanced-types/src/queries.rs b/examples/advanced-types/src/queries.rs index cd12904..8dab9f8 100644 --- a/examples/advanced-types/src/queries.rs +++ b/examples/advanced-types/src/queries.rs @@ -1,4 +1,5 @@ -// Code generated by sqlc-gen-sqlx. DO NOT EDIT. +// Code generated by sqlc-gen-sqlx v0.1.0. DO NOT EDIT. +// sqlc version: v1.30.0 #![allow( dead_code, @@ -6,7 +7,6 @@ )] const GET_EVENT: &str = "SELECT id, name, flags, event_window FROM events WHERE id = $1"; - #[derive(Debug, Clone, sqlx::FromRow)] pub struct GetEventRow { pub id: i64, @@ -14,9 +14,7 @@ pub struct GetEventRow { pub flags: bit_vec::BitVec, pub event_window: sqlx::postgres::types::PgRange>, } - const LIST_EVENTS: &str = "SELECT id, name, flags, event_window FROM events"; - #[derive(Debug, Clone, sqlx::FromRow)] pub struct ListEventsRow { pub id: i64, @@ -24,31 +22,84 @@ pub struct ListEventsRow { pub flags: bit_vec::BitVec, pub event_window: sqlx::postgres::types::PgRange>, } - +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> + = &'c sqlx::PgPool + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> + = &'c sqlx::PgPool + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> + = T::Exec<'c> + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } - impl Queries { pub fn new(db: E) -> Self { Self { db } } } - -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn get_event(&mut self, id: i64) -> Result { sqlx::query_as::<_, GetEventRow>(GET_EVENT) .bind(id) - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await } - pub async fn list_events(&mut self) -> Result, sqlx::Error> { sqlx::query_as::<_, ListEventsRow>(LIST_EVENTS) - .fetch_all(&mut self.db) + .fetch_all(self.db.as_executor()) .await } } diff --git a/examples/basic/src/queries.rs b/examples/basic/src/queries.rs index ff071b1..a377bcb 100644 --- a/examples/basic/src/queries.rs +++ b/examples/basic/src/queries.rs @@ -35,6 +35,66 @@ pub struct CreateAuthorRow { } const DELETE_AUTHOR: &str = "DELETE FROM authors WHERE id = $1"; const DELETE_AUTHOR_ROWS: &str = "DELETE FROM authors WHERE id = $1"; +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> + = &'c sqlx::PgPool + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> + = &'c sqlx::PgPool + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> + = T::Exec<'c> + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -43,19 +103,16 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn get_author(&mut self, id: i64) -> Result { sqlx::query_as::<_, GetAuthorRow>(GET_AUTHOR) .bind(id) - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await } pub async fn list_authors(&mut self) -> Result, sqlx::Error> { sqlx::query_as::<_, ListAuthorsRow>(LIST_AUTHORS) - .fetch_all(&mut self.db) + .fetch_all(self.db.as_executor()) .await } pub async fn create_author( @@ -65,20 +122,20 @@ where sqlx::query_as::<_, CreateAuthorRow>(CREATE_AUTHOR) .bind(arg.name) .bind(arg.bio) - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await } pub async fn delete_author(&mut self, id: i64) -> Result<(), sqlx::Error> { sqlx::query(DELETE_AUTHOR) .bind(id) - .execute(&mut self.db) + .execute(self.db.as_executor()) .await?; Ok(()) } pub async fn delete_author_rows(&mut self, id: i64) -> Result { let result = sqlx::query(DELETE_AUTHOR_ROWS) .bind(id) - .execute(&mut self.db) + .execute(self.db.as_executor()) .await?; Ok(result.rows_affected()) } diff --git a/examples/batch/Cargo.toml b/examples/batch/Cargo.toml index 055482b..2451d14 100644 --- a/examples/batch/Cargo.toml +++ b/examples/batch/Cargo.toml @@ -6,3 +6,5 @@ edition = "2024" [dependencies] sqlx = { workspace = true } tokio = { workspace = true } +futures-core = "0.3" +futures-util = "0.3" diff --git a/examples/batch/src/main.rs b/examples/batch/src/main.rs index 33f0be5..d608ef2 100644 --- a/examples/batch/src/main.rs +++ b/examples/batch/src/main.rs @@ -2,6 +2,8 @@ #[path = "queries.rs"] mod queries; #[cfg(test)] +use futures_util::TryStreamExt; +#[cfg(test)] use queries::Queries; #[cfg(test)] use sqlx::{Connection as _, PgConnection}; @@ -34,12 +36,18 @@ async fn test_batch_roundtrip() { let mut q = Queries::new(conn); - let authors = q.batch_get_author(vec![1, 2]).await.expect("batch get"); + let authors: Vec<_> = q + .batch_get_author(vec![1, 2]) + .try_collect() + .await + .expect("batch get"); assert_eq!(authors.len(), 2); assert_eq!(authors[0].name, "Alice"); assert_eq!(authors[1].name, "Bob"); - q.batch_delete_author(vec![1, 2]) + let _: Vec<()> = q + .batch_delete_author(vec![1, 2]) + .try_collect() .await .expect("batch delete"); diff --git a/examples/batch/src/queries.rs b/examples/batch/src/queries.rs index c720d9c..c279940 100644 --- a/examples/batch/src/queries.rs +++ b/examples/batch/src/queries.rs @@ -1,4 +1,5 @@ -// Code generated by sqlc-gen-sqlx. DO NOT EDIT. +// Code generated by sqlc-gen-sqlx v0.1.0. DO NOT EDIT. +// sqlc version: v1.30.0 #![allow( dead_code, @@ -6,52 +7,126 @@ )] const BATCH_GET_AUTHOR: &str = "SELECT id, name, bio FROM authors WHERE id = $1"; - #[derive(Debug, Clone, sqlx::FromRow)] pub struct BatchGetAuthorRow { pub id: i64, pub name: String, pub bio: Option, } - const BATCH_DELETE_AUTHOR: &str = "DELETE FROM authors WHERE id = $1"; - +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> + = &'c sqlx::PgPool + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> + = &'c sqlx::PgPool + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> + = T::Exec<'c> + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } - impl Queries { pub fn new(db: E) -> Self { Self { db } } } - -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ - pub async fn batch_get_author( - &mut self, - items: Vec, - ) -> Result, sqlx::Error> { - let mut results = Vec::with_capacity(items.len()); - for item in items { - let row = sqlx::query_as::<_, BatchGetAuthorRow>(BATCH_GET_AUTHOR) - .bind(item) - .fetch_one(&mut self.db) - .await?; - results.push(row); - } - Ok(results) +impl Queries { + pub fn batch_get_author<'a, I>( + &'a mut self, + items: I, + ) -> impl futures_core::stream::Stream> + 'a + where + I: IntoIterator + 'a, + I::IntoIter: 'a, + E: 'a, + { + futures_util::stream::try_unfold( + (&mut self.db, items.into_iter()), + |(db, mut items)| async move { + let Some(item) = items.next() else { + return Ok(None); + }; + let row = sqlx::query_as::<_, BatchGetAuthorRow>(BATCH_GET_AUTHOR) + .bind(item) + .fetch_one(db.as_executor()) + .await?; + Ok(Some((row, (db, items)))) + }, + ) } - - pub async fn batch_delete_author(&mut self, items: Vec) -> Result<(), sqlx::Error> { - for item in items { - sqlx::query(BATCH_DELETE_AUTHOR) - .bind(item) - .execute(&mut self.db) - .await?; - } - Ok(()) + pub fn batch_delete_author<'a, I>( + &'a mut self, + items: I, + ) -> impl futures_core::stream::Stream> + 'a + where + I: IntoIterator + 'a, + I::IntoIter: 'a, + E: 'a, + { + futures_util::stream::try_unfold( + (&mut self.db, items.into_iter()), + |(db, mut items)| async move { + let Some(item) = items.next() else { + return Ok(None); + }; + sqlx::query(BATCH_DELETE_AUTHOR) + .bind(item) + .execute(db.as_executor()) + .await?; + Ok(Some(((), (db, items)))) + }, + ) } } diff --git a/examples/enums/src/main.rs b/examples/enums/src/main.rs index d728bb0..65290c2 100644 --- a/examples/enums/src/main.rs +++ b/examples/enums/src/main.rs @@ -2,7 +2,7 @@ #[cfg(test)] mod queries; #[cfg(test)] -use queries::{Queries, Status}; +use queries::{CreateUserParams, Queries, Status}; #[cfg(test)] use sqlx::{Connection as _, PgConnection}; @@ -42,9 +42,12 @@ async fn test_enum_roundtrip() { let mut q = Queries::new(conn); - q.create_user("Alice".to_string(), Status::Active) - .await - .expect("create"); + q.create_user(CreateUserParams { + name: "Alice".to_string(), + status: Status::Active, + }) + .await + .expect("create"); let user = q.get_user(1).await.expect("get"); assert_eq!(user.name, "Alice"); diff --git a/examples/enums/src/queries.rs b/examples/enums/src/queries.rs index 85ba7fc..ec01ea3 100644 --- a/examples/enums/src/queries.rs +++ b/examples/enums/src/queries.rs @@ -1,4 +1,5 @@ -// Code generated by sqlc-gen-sqlx. DO NOT EDIT. +// Code generated by sqlc-gen-sqlx v0.1.0. DO NOT EDIT. +// sqlc version: v1.30.0 #![allow( dead_code, @@ -15,63 +16,115 @@ pub enum Status { #[sqlx(rename = "pending")] Pending, } - const GET_USER: &str = "SELECT id, name, status FROM users WHERE id = $1"; - #[derive(Debug, Clone, sqlx::FromRow)] pub struct GetUserRow { pub id: i64, pub name: String, pub status: Status, } - const LIST_USERS_BY_STATUS: &str = "SELECT id, name, status FROM users WHERE status = $1"; - #[derive(Debug, Clone, sqlx::FromRow)] pub struct ListUsersByStatusRow { pub id: i64, pub name: String, pub status: Status, } - +#[derive(Debug, Clone)] +pub struct CreateUserParams { + pub name: String, + pub status: Status, +} const CREATE_USER: &str = "INSERT INTO users (name, status) VALUES ($1, $2)"; - +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> + = &'c sqlx::PgPool + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> + = &'c sqlx::PgPool + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> + = &'c mut sqlx::PgConnection + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> + = T::Exec<'c> + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } - impl Queries { pub fn new(db: E) -> Self { Self { db } } } - -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn get_user(&mut self, id: i64) -> Result { sqlx::query_as::<_, GetUserRow>(GET_USER) .bind(id) - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await } - pub async fn list_users_by_status( &mut self, status: Status, ) -> Result, sqlx::Error> { sqlx::query_as::<_, ListUsersByStatusRow>(LIST_USERS_BY_STATUS) .bind(status) - .fetch_all(&mut self.db) + .fetch_all(self.db.as_executor()) .await } - - pub async fn create_user(&mut self, name: String, status: Status) -> Result<(), sqlx::Error> { + pub async fn create_user(&mut self, arg: CreateUserParams) -> Result<(), sqlx::Error> { sqlx::query(CREATE_USER) - .bind(name) - .bind(status) - .execute(&mut self.db) + .bind(arg.name) + .bind(arg.status) + .execute(self.db.as_executor()) .await?; Ok(()) } diff --git a/src/codegen/batch.rs b/src/codegen/batch.rs index 4a527b2..5ed2ea9 100644 --- a/src/codegen/batch.rs +++ b/src/codegen/batch.rs @@ -100,7 +100,7 @@ pub fn gen_batchexec( #sql_setup let mut query = sqlx::query(&sql); #bind_setup - query.execute(&mut *db).await?; + query.execute(db.as_executor()).await?; Ok(Some(((), (db, items)))) } } else if params.len() >= 2 { @@ -109,7 +109,7 @@ pub fn gen_batchexec( quote! { sqlx::query(#const_name) #binds - .execute(&mut *db) + .execute(db.as_executor()) .await?; Ok(Some(((), (db, items)))) } @@ -117,7 +117,7 @@ pub fn gen_batchexec( quote! { sqlx::query(#const_name) .bind(item) - .execute(&mut *db) + .execute(db.as_executor()) .await?; Ok(Some(((), (db, items)))) } @@ -160,7 +160,7 @@ pub fn gen_batchone( #sql_setup let mut query = sqlx::query_as::<_, #row_name>(&sql); #bind_setup - let row = query.fetch_one(&mut *db).await?; + let row = query.fetch_one(db.as_executor()).await?; Ok(Some((row, (db, items)))) } } else if params.len() >= 2 { @@ -169,7 +169,7 @@ pub fn gen_batchone( quote! { let row = sqlx::query_as::<_, #row_name>(#const_name) #binds - .fetch_one(&mut *db) + .fetch_one(db.as_executor()) .await?; Ok(Some((row, (db, items)))) } @@ -177,7 +177,7 @@ pub fn gen_batchone( quote! { let row = sqlx::query_as::<_, #row_name>(#const_name) .bind(item) - .fetch_one(&mut *db) + .fetch_one(db.as_executor()) .await?; Ok(Some((row, (db, items)))) } @@ -220,7 +220,7 @@ pub fn gen_batchmany( #sql_setup let mut query = sqlx::query_as::<_, #row_name>(&sql); #bind_setup - let rows = query.fetch_all(&mut *db).await?; + let rows = query.fetch_all(db.as_executor()).await?; Ok(Some((rows, (db, items)))) } } else if params.len() >= 2 { @@ -229,7 +229,7 @@ pub fn gen_batchmany( quote! { let rows = sqlx::query_as::<_, #row_name>(#const_name) #binds - .fetch_all(&mut *db) + .fetch_all(db.as_executor()) .await?; Ok(Some((rows, (db, items)))) } @@ -237,7 +237,7 @@ pub fn gen_batchmany( quote! { let rows = sqlx::query_as::<_, #row_name>(#const_name) .bind(item) - .fetch_all(&mut *db) + .fetch_all(db.as_executor()) .await?; Ok(Some((rows, (db, items)))) } diff --git a/src/codegen/copyfrom.rs b/src/codegen/copyfrom.rs index 4381a36..d87c0ca 100644 --- a/src/codegen/copyfrom.rs +++ b/src/codegen/copyfrom.rs @@ -68,7 +68,7 @@ pub fn gen_copyfrom( #builder_binds }); - rows_affected += query_builder.build().execute(&mut self.db).await?.rows_affected(); + rows_affected += query_builder.build().execute(self.db.as_executor()).await?.rows_affected(); } Ok(rows_affected) diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index d23e975..ffa0f92 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -52,6 +52,43 @@ pub fn generate(request: &GenerateRequestView<'_>, config: &Config) -> Result: sqlx::Executor<'c, Database = sqlx::Postgres> + where + Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; + } + + impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { &*self } + } + + impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { *self } + } + + impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { self } + } + + impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { &mut **self } + } + + impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { &mut **self } + } + + impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { (**self).as_executor() } + } + pub struct Queries { db: E, } @@ -65,10 +102,7 @@ pub fn generate(request: &GenerateRequestView<'_>, config: &Config) -> Result Queries - where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, - { + impl Queries { #(#impl_fns)* } }); diff --git a/src/codegen/query.rs b/src/codegen/query.rs index 6223b6e..be0b027 100644 --- a/src/codegen/query.rs +++ b/src/codegen/query.rs @@ -447,7 +447,7 @@ pub fn gen_one( #sql_setup let mut query = sqlx::query_as::<_, #row_name>(&sql); #bind_setup - query.fetch_one(&mut self.db).await + query.fetch_one(self.db.as_executor()).await } } } else { @@ -455,7 +455,7 @@ pub fn gen_one( pub async fn #fn_name(&mut self, #fn_params) -> Result<#row_name, sqlx::Error> { sqlx::query_as::<_, #row_name>(#const_name) #binds - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await } } @@ -498,7 +498,7 @@ pub fn gen_many( #sql_setup let mut query = sqlx::query_as::<_, #row_name>(&sql); #bind_setup - query.fetch_all(&mut self.db).await + query.fetch_all(self.db.as_executor()).await } } } else { @@ -506,7 +506,7 @@ pub fn gen_many( pub async fn #fn_name(&mut self, #fn_params) -> Result, sqlx::Error> { sqlx::query_as::<_, #row_name>(#const_name) #binds - .fetch_all(&mut self.db) + .fetch_all(self.db.as_executor()) .await } } @@ -543,7 +543,7 @@ pub fn gen_execrows( #sql_setup let mut query = sqlx::query(&sql); #bind_setup - let result = query.execute(&mut self.db).await?; + let result = query.execute(self.db.as_executor()).await?; Ok(result.rows_affected()) } } @@ -552,7 +552,7 @@ pub fn gen_execrows( pub async fn #fn_name(&mut self, #fn_params) -> Result { let result = sqlx::query(#const_name) #binds - .execute(&mut self.db) + .execute(self.db.as_executor()) .await?; Ok(result.rows_affected()) } @@ -583,7 +583,7 @@ pub fn gen_execresult( #sql_setup let mut query = sqlx::query(&sql); #bind_setup - query.execute(&mut self.db).await + query.execute(self.db.as_executor()).await } } } else { @@ -591,7 +591,7 @@ pub fn gen_execresult( pub async fn #fn_name(&mut self, #fn_params) -> Result { sqlx::query(#const_name) #binds - .execute(&mut self.db) + .execute(self.db.as_executor()) .await } } @@ -625,7 +625,7 @@ pub fn gen_exec( #sql_setup let mut query = sqlx::query(&sql); #bind_setup - query.execute(&mut self.db).await?; + query.execute(self.db.as_executor()).await?; Ok(()) } } @@ -634,7 +634,7 @@ pub fn gen_exec( pub async fn #fn_name(&mut self, #fn_params) -> Result<(), sqlx::Error> { sqlx::query(#const_name) #binds - .execute(&mut self.db) + .execute(self.db.as_executor()) .await?; Ok(()) } @@ -686,7 +686,7 @@ pub fn gen_execlastid( #sql_setup let mut query = sqlx::query_as(&sql); #bind_setup - let (_row,): (#ret_ty,) = query.fetch_one(&mut self.db).await?; + let (_row,): (#ret_ty,) = query.fetch_one(self.db.as_executor()).await?; Ok(_row) } } @@ -695,7 +695,7 @@ pub fn gen_execlastid( pub async fn #fn_name(&mut self, #fn_params) -> Result<#ret_ty, sqlx::Error> { let (_row,): (#ret_ty,) = sqlx::query_as(#const_name) #binds - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await?; Ok(_row) } diff --git a/tests/snapshots/codegen__batch_dynamic_slice_param.snap b/tests/snapshots/codegen__batch_dynamic_slice_param.snap index 380dcdf..64b563f 100644 --- a/tests/snapshots/codegen__batch_dynamic_slice_param.snap +++ b/tests/snapshots/codegen__batch_dynamic_slice_param.snap @@ -14,6 +14,46 @@ pub struct BatchListAuthorsByDynamicIdsRow { pub name: String, pub bio: Option, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -22,10 +62,7 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub fn batch_list_authors_by_dynamic_ids<'a, I>( &'a mut self, items: I, @@ -73,7 +110,7 @@ where for value in ids { query = query.bind(value); } - let rows = query.fetch_all(&mut *db).await?; + let rows = query.fetch_all(db.as_executor()).await?; Ok(Some((rows, (db, items)))) }, ) diff --git a/tests/snapshots/codegen__batchexec.snap b/tests/snapshots/codegen__batchexec.snap index d902d7b..8e1fcf7 100644 --- a/tests/snapshots/codegen__batchexec.snap +++ b/tests/snapshots/codegen__batchexec.snap @@ -8,6 +8,46 @@ expression: code #![allow(dead_code, reason = "generated queries may expose items a caller does not use")] const BATCH_DELETE_AUTHOR: &str = "DELETE FROM authors WHERE id = $1"; +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -16,10 +56,7 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub fn batch_delete_author<'a, I>( &'a mut self, items: I, @@ -35,7 +72,10 @@ where let Some(item) = items.next() else { return Ok(None); }; - sqlx::query(BATCH_DELETE_AUTHOR).bind(item).execute(&mut *db).await?; + sqlx::query(BATCH_DELETE_AUTHOR) + .bind(item) + .execute(db.as_executor()) + .await?; Ok(Some(((), (db, items)))) }, ) diff --git a/tests/snapshots/codegen__batchmany.snap b/tests/snapshots/codegen__batchmany.snap index 687adc5..e08e914 100644 --- a/tests/snapshots/codegen__batchmany.snap +++ b/tests/snapshots/codegen__batchmany.snap @@ -14,6 +14,46 @@ pub struct BatchListAuthorsRow { pub name: String, pub bio: Option, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -22,10 +62,7 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub fn batch_list_authors<'a, I>( &'a mut self, items: I, @@ -45,7 +82,7 @@ where }; let rows = sqlx::query_as::<_, BatchListAuthorsRow>(BATCH_LIST_AUTHORS) .bind(item) - .fetch_all(&mut *db) + .fetch_all(db.as_executor()) .await?; Ok(Some((rows, (db, items)))) }, diff --git a/tests/snapshots/codegen__batchone.snap b/tests/snapshots/codegen__batchone.snap index e1923fd..2124071 100644 --- a/tests/snapshots/codegen__batchone.snap +++ b/tests/snapshots/codegen__batchone.snap @@ -14,6 +14,46 @@ pub struct BatchGetAuthorRow { pub name: String, pub bio: Option, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -22,10 +62,7 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub fn batch_get_author<'a, I>( &'a mut self, items: I, @@ -45,7 +82,7 @@ where }; let row = sqlx::query_as::<_, BatchGetAuthorRow>(BATCH_GET_AUTHOR) .bind(item) - .fetch_one(&mut *db) + .fetch_one(db.as_executor()) .await?; Ok(Some((row, (db, items)))) }, diff --git a/tests/snapshots/codegen__composite_types.snap b/tests/snapshots/codegen__composite_types.snap index a293337..016b242 100644 --- a/tests/snapshots/codegen__composite_types.snap +++ b/tests/snapshots/codegen__composite_types.snap @@ -14,6 +14,46 @@ pub struct Address { pub city: Option, pub zip: Option, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } diff --git a/tests/snapshots/codegen__copyfrom.snap b/tests/snapshots/codegen__copyfrom.snap index f3492af..a03b2ab 100644 --- a/tests/snapshots/codegen__copyfrom.snap +++ b/tests/snapshots/codegen__copyfrom.snap @@ -14,6 +14,46 @@ pub struct CopyAuthorsParams { } const COPY_AUTHORS: &str = "INSERT INTO authors (name, bio) "; const COPY_AUTHORS_BATCH_SIZE: usize = 32767usize; +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -22,10 +62,7 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn copy_authors(&mut self, items: I) -> Result where I: IntoIterator, @@ -49,7 +86,11 @@ where }, ); rows_affected - += query_builder.build().execute(&mut self.db).await?.rows_affected(); + += query_builder + .build() + .execute(self.db.as_executor()) + .await? + .rows_affected(); } Ok(rows_affected) } diff --git a/tests/snapshots/codegen__dynamic_slice_param.snap b/tests/snapshots/codegen__dynamic_slice_param.snap index 8500044..e117f52 100644 --- a/tests/snapshots/codegen__dynamic_slice_param.snap +++ b/tests/snapshots/codegen__dynamic_slice_param.snap @@ -14,6 +14,46 @@ pub struct ListAuthorsByDynamicIdsRow { pub name: String, pub bio: Option, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -22,10 +62,7 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn list_authors_by_dynamic_ids( &mut self, ids: Vec, @@ -56,6 +93,6 @@ where for value in ids { query = query.bind(value); } - query.fetch_all(&mut self.db).await + query.fetch_all(self.db.as_executor()).await } } diff --git a/tests/snapshots/codegen__embed.snap b/tests/snapshots/codegen__embed.snap index 4a85538..2715509 100644 --- a/tests/snapshots/codegen__embed.snap +++ b/tests/snapshots/codegen__embed.snap @@ -19,6 +19,46 @@ pub struct GetAuthorEmbedRow { #[sqlx(flatten)] pub authors: AuthorsEmbed, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -27,17 +67,14 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn get_author_embed( &mut self, id: i64, ) -> Result { sqlx::query_as::<_, GetAuthorEmbedRow>(GET_AUTHOR_EMBED) .bind(id) - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await } } diff --git a/tests/snapshots/codegen__enum_types.snap b/tests/snapshots/codegen__enum_types.snap index 6394c0c..c58369b 100644 --- a/tests/snapshots/codegen__enum_types.snap +++ b/tests/snapshots/codegen__enum_types.snap @@ -22,6 +22,46 @@ const GET_USER_STATUS: &str = "SELECT status FROM users WHERE id = $1"; pub struct GetUserStatusRow { pub status: Status, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -30,17 +70,14 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn get_user_status( &mut self, id: i64, ) -> Result { sqlx::query_as::<_, GetUserStatusRow>(GET_USER_STATUS) .bind(id) - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await } } diff --git a/tests/snapshots/codegen__exec.snap b/tests/snapshots/codegen__exec.snap index 590afea..19d3fd9 100644 --- a/tests/snapshots/codegen__exec.snap +++ b/tests/snapshots/codegen__exec.snap @@ -8,6 +8,46 @@ expression: code #![allow(dead_code, reason = "generated queries may expose items a caller does not use")] const DELETE_AUTHOR: &str = "DELETE FROM authors WHERE id = $1"; +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -16,12 +56,9 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn delete_author(&mut self, id: i64) -> Result<(), sqlx::Error> { - sqlx::query(DELETE_AUTHOR).bind(id).execute(&mut self.db).await?; + sqlx::query(DELETE_AUTHOR).bind(id).execute(self.db.as_executor()).await?; Ok(()) } } diff --git a/tests/snapshots/codegen__execlastid.snap b/tests/snapshots/codegen__execlastid.snap index 4f91a73..1b883a1 100644 --- a/tests/snapshots/codegen__execlastid.snap +++ b/tests/snapshots/codegen__execlastid.snap @@ -8,6 +8,46 @@ expression: code #![allow(dead_code, reason = "generated queries may expose items a caller does not use")] const CREATE_AUTHOR: &str = "INSERT INTO authors (name) VALUES ($1) RETURNING id"; +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -16,14 +56,11 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn create_author(&mut self, name: String) -> Result { let (_row,): (i64,) = sqlx::query_as(CREATE_AUTHOR) .bind(name) - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await?; Ok(_row) } diff --git a/tests/snapshots/codegen__execresult.snap b/tests/snapshots/codegen__execresult.snap index aa0ec93..0adc30c 100644 --- a/tests/snapshots/codegen__execresult.snap +++ b/tests/snapshots/codegen__execresult.snap @@ -8,6 +8,46 @@ expression: code #![allow(dead_code, reason = "generated queries may expose items a caller does not use")] const DELETE_AUTHOR_RESULT: &str = "DELETE FROM authors WHERE id = $1"; +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -16,14 +56,11 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn delete_author_result( &mut self, id: i64, ) -> Result { - sqlx::query(DELETE_AUTHOR_RESULT).bind(id).execute(&mut self.db).await + sqlx::query(DELETE_AUTHOR_RESULT).bind(id).execute(self.db.as_executor()).await } } diff --git a/tests/snapshots/codegen__execrows.snap b/tests/snapshots/codegen__execrows.snap index 09d60dc..f633a37 100644 --- a/tests/snapshots/codegen__execrows.snap +++ b/tests/snapshots/codegen__execrows.snap @@ -8,6 +8,46 @@ expression: code #![allow(dead_code, reason = "generated queries may expose items a caller does not use")] const DELETE_AUTHOR_ROWS: &str = "DELETE FROM authors WHERE id = $1"; +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -16,14 +56,11 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn delete_author_rows(&mut self, id: i64) -> Result { let result = sqlx::query(DELETE_AUTHOR_ROWS) .bind(id) - .execute(&mut self.db) + .execute(self.db.as_executor()) .await?; Ok(result.rows_affected()) } diff --git a/tests/snapshots/codegen__many.snap b/tests/snapshots/codegen__many.snap index 1db59fd..8321a1a 100644 --- a/tests/snapshots/codegen__many.snap +++ b/tests/snapshots/codegen__many.snap @@ -14,6 +14,46 @@ pub struct ListAuthorsRow { pub name: String, pub bio: Option, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -22,11 +62,10 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn list_authors(&mut self) -> Result, sqlx::Error> { - sqlx::query_as::<_, ListAuthorsRow>(LIST_AUTHORS).fetch_all(&mut self.db).await + sqlx::query_as::<_, ListAuthorsRow>(LIST_AUTHORS) + .fetch_all(self.db.as_executor()) + .await } } diff --git a/tests/snapshots/codegen__multidimensional_array_types.snap b/tests/snapshots/codegen__multidimensional_array_types.snap index 326e1ce..958c93a 100644 --- a/tests/snapshots/codegen__multidimensional_array_types.snap +++ b/tests/snapshots/codegen__multidimensional_array_types.snap @@ -12,6 +12,46 @@ const GET_MATRIX: &str = "SELECT matrix FROM tensors WHERE id = $1"; pub struct GetMatrixRow { pub matrix: Vec>, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -20,17 +60,14 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn get_matrix( &mut self, matrix: Vec>, ) -> Result { sqlx::query_as::<_, GetMatrixRow>(GET_MATRIX) .bind(matrix) - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await } } diff --git a/tests/snapshots/codegen__named_params.snap b/tests/snapshots/codegen__named_params.snap index 84b5896..c24ff54 100644 --- a/tests/snapshots/codegen__named_params.snap +++ b/tests/snapshots/codegen__named_params.snap @@ -13,6 +13,46 @@ pub struct UpdateAuthorNamedParamsParams { pub author_id: i64, } const UPDATE_AUTHOR_NAMED_PARAMS: &str = "UPDATE authors SET name = $1 WHERE id = $2"; +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -21,10 +61,7 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn update_author_named_params( &mut self, arg: UpdateAuthorNamedParamsParams, @@ -32,7 +69,7 @@ where sqlx::query(UPDATE_AUTHOR_NAMED_PARAMS) .bind(arg.set_name) .bind(arg.author_id) - .execute(&mut self.db) + .execute(self.db.as_executor()) .await?; Ok(()) } diff --git a/tests/snapshots/codegen__nullable_named_param.snap b/tests/snapshots/codegen__nullable_named_param.snap index c562105..c1ea472 100644 --- a/tests/snapshots/codegen__nullable_named_param.snap +++ b/tests/snapshots/codegen__nullable_named_param.snap @@ -14,6 +14,46 @@ pub struct ListAuthorsByOptionalBioRow { pub name: String, pub bio: Option, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -22,17 +62,14 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn list_authors_by_optional_bio( &mut self, bio: Option, ) -> Result, sqlx::Error> { sqlx::query_as::<_, ListAuthorsByOptionalBioRow>(LIST_AUTHORS_BY_OPTIONAL_BIO) .bind(bio) - .fetch_all(&mut self.db) + .fetch_all(self.db.as_executor()) .await } } diff --git a/tests/snapshots/codegen__one.snap b/tests/snapshots/codegen__one.snap index 7b77add..f63aa4c 100644 --- a/tests/snapshots/codegen__one.snap +++ b/tests/snapshots/codegen__one.snap @@ -14,6 +14,46 @@ pub struct GetAuthorRow { pub name: String, pub bio: Option, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -22,14 +62,11 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn get_author(&mut self, id: i64) -> Result { sqlx::query_as::<_, GetAuthorRow>(GET_AUTHOR) .bind(id) - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await } } diff --git a/tests/snapshots/codegen__range_types.snap b/tests/snapshots/codegen__range_types.snap index c0b23a8..d10e124 100644 --- a/tests/snapshots/codegen__range_types.snap +++ b/tests/snapshots/codegen__range_types.snap @@ -14,6 +14,46 @@ pub struct GetEventWindowRow { pub window: sqlx::postgres::types::PgRange>, pub flags: bit_vec::BitVec, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -22,17 +62,14 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn get_event_window( &mut self, id: i64, ) -> Result { sqlx::query_as::<_, GetEventWindowRow>(GET_EVENT_WINDOW) .bind(id) - .fetch_one(&mut self.db) + .fetch_one(self.db.as_executor()) .await } } diff --git a/tests/snapshots/codegen__slice_param.snap b/tests/snapshots/codegen__slice_param.snap index 531bda3..c24482d 100644 --- a/tests/snapshots/codegen__slice_param.snap +++ b/tests/snapshots/codegen__slice_param.snap @@ -14,6 +14,46 @@ pub struct ListAuthorsByIdsRow { pub name: String, pub bio: Option, } +pub trait AsExecutor { + type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Postgres> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_>; +} +impl AsExecutor for sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &*self + } +} +impl AsExecutor for &sqlx::PgPool { + type Exec<'c> = &'c sqlx::PgPool where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + *self + } +} +impl AsExecutor for sqlx::PgConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + self + } +} +impl AsExecutor for sqlx::Transaction<'_, sqlx::Postgres> { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for sqlx::pool::PoolConnection { + type Exec<'c> = &'c mut sqlx::PgConnection where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + &mut **self + } +} +impl AsExecutor for &mut T { + type Exec<'c> = T::Exec<'c> where Self: 'c; + fn as_executor(&mut self) -> Self::Exec<'_> { + (**self).as_executor() + } +} pub struct Queries { db: E, } @@ -22,17 +62,14 @@ impl Queries { Self { db } } } -impl Queries -where - for<'c> &'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres>, -{ +impl Queries { pub async fn list_authors_by_ids( &mut self, id: Vec, ) -> Result, sqlx::Error> { sqlx::query_as::<_, ListAuthorsByIdsRow>(LIST_AUTHORS_BY_IDS) .bind(id) - .fetch_all(&mut self.db) + .fetch_all(self.db.as_executor()) .await } }