sqlx
sqlx copied to clipboard
From sqlx 0.7 this code is not working anymore
Hi people! Your work on sqlx
is amazing! Congratulations and thank you very much! ♥
A few months ago - coming from Golang - I was looking for a way to use both direct queries and queries in transactions (I'm also using a clean code architecture, so I cannot call sqlx
methods directly).
A very nice person on the rust Discord channel helped me put this code together and it works great: https://github.com/frederikhors/iss-sqlx-0.7.
This allows me to use code like this:
let mut tx = repo.start_transaction().await?;
let available_seats = tx.search_for_available_seats(stadium_id).await?;
let confirmed_seat = tx.confirm_seat(available_seats[0]).await?;
tx.commit().await?;
in addition to this:
let example = repo.clone_boxed().search_for_available_seats(stadium_id).await?;
Everything works perfectly with sqlx 0.6.3
, but now with sqlx 0.7
I'm having this error:
error[E0277]: the trait bound `&'this mut Transaction<'static, Postgres>: sqlx::Executor<'this>` is not satisfied
--> src\main.rs:99:28
|
99 | type Executor<'this> = &'this mut Self;
| ^^^^^^^^^^^^^^^ the trait `sqlx::Executor<'this>` is not implemented for `&'this mut Transaction<'static, Postgres>`
|
= help: the following other types implement trait `sqlx::Executor<'c>`:
<&'c mut PgConnection as sqlx::Executor<'c>>
<&'c mut PgListener as sqlx::Executor<'c>>
<&Pool<DB> as sqlx::Executor<'p>>
= note: required for `<Transaction<'static, Postgres> as Executor>::Executor<'this>` to implement `PgExecutor<'this>`
note: required by a bound in `Executor::Executor`
--> src\main.rs:78:41
|
78 | type Executor<'this>: Send + Sync + sqlx::PgExecutor<'this>;
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Executor::Executor`
For more information about this error, try `rustc --explain E0277`.
I saw the note in CHANGELOG about Executor
trait but I don't know how to fix it in this case.
Could you suggest me a way to fix it?
Can you think of an alternative way to use instead of this Executor
trait?
The custom trait
pub trait Executor: Send + Sync {
type Executor<'this>: Send + Sync + sqlx::PgExecutor<'this>;
// From https://users.rust-lang.org/t/why-does-this-impl-executor-does-not-live-long-enough/94241
fn _disable_lint(e: Self::Executor<'_>) -> Self::Executor<'_>;
fn as_executor(&mut self) -> Self::Executor<'_>;
}
impl Executor for sqlx::PgPool {
type Executor<'this> = &'this Self;
fn _disable_lint(e: Self::Executor<'_>) -> Self::Executor<'_> {
e
}
fn as_executor(&mut self) -> Self::Executor<'_> {
self
}
}
impl Executor for sqlx::Transaction<'static, sqlx::Postgres> {
type Executor<'this> = &'this mut Self;
fn _disable_lint(e: Self::Executor<'_>) -> Self::Executor<'_> {
e
}
fn as_executor(&mut self) -> Self::Executor<'_> {
self
}
}
Just ran into this issue a minute ago. You need to add an extra deref to get the "concrete" PgConnection
type that has Executor implemented.
From the change notes:
To fix this breakage, simply add a dereference where an impl Executor is expected, as they both dereference to the inner connection type which will still implement it:
&mut transaction
->&mut *transaction
&mut connection
->&mut *connection
You're going to need to change:
impl Executor for sqlx::Transaction<'static, sqlx::Postgres> {
type Executor<'this> = &'this mut Self;
fn _disable_lint(e: Self::Executor<'_>) -> Self::Executor<'_> {
e
}
fn as_executor(&mut self) -> Self::Executor<'_> {
self
}
}
to something like,
impl Executor for sqlx::Transaction<'static, sqlx::Postgres> {
type Executor<'this> = &'this mut PgConnection;
fn _disable_lint(e: Self::Executor<'_>) -> Self::Executor<'_> {
e
}
fn as_executor(&mut self) -> Self::Executor<'_> {
&mut *self
}
}
Or if you really want to, you could tell it to the use type that it derefs to, but I think this is less obvious that really you're turning it into a PgConnection
.
use std::ops::Deref;
impl Executor for sqlx::Transaction<'static, sqlx::Postgres> {
type Executor<'this> = &'this mut <Self as Deref>::Target;
...
}
As an aside, since this might be helpful, I also had a lot of functions that had a tx
argument:
async fn foo(tx: &mut Transaction<'tx, Postgres>) -> sqlx::Result<()> {
sqlx::query!( ... ).execute(tx).await
}
This becomes either,
sqlx::query!( ... ).execute(&mut **tx).await
Or what seems a bit cleaner to me,
use std::ops::DerefMut;
sqlx::query!( ... ).execute(tx.deref_mut()).await
@jaxrtech, amazing! Thank you very much!
Just one question: why are you using:
fn as_executor(&mut self) -> Self::Executor<'_> {
&mut *self
}
instead of a simpler:
fn as_executor(&mut self) -> Self::Executor<'_> {
self
}
The latter is working for me.
Hi people! Your work on
sqlx
is amazing! Congratulations and thank you very much! ♥A few months ago - coming from Golang - I was looking for a way to use both direct queries and queries in transactions (I'm also using a clean code architecture, so I cannot call
sqlx
methods directly).A very nice person on the rust Discord channel helped me put this code together and it works great: https://github.com/frederikhors/iss-sqlx-0.7.
This allows me to use code like this:
let mut tx = repo.start_transaction().await?; let available_seats = tx.search_for_available_seats(stadium_id).await?; let confirmed_seat = tx.confirm_seat(available_seats[0]).await?; tx.commit().await?;
in addition to this:
let example = repo.clone_boxed().search_for_available_seats(stadium_id).await?;
Everything works perfectly with
sqlx 0.6.3
, but now withsqlx 0.7
I'm having this error:error[E0277]: the trait bound `&'this mut Transaction<'static, Postgres>: sqlx::Executor<'this>` is not satisfied --> src\main.rs:99:28 | 99 | type Executor<'this> = &'this mut Self; | ^^^^^^^^^^^^^^^ the trait `sqlx::Executor<'this>` is not implemented for `&'this mut Transaction<'static, Postgres>` | = help: the following other types implement trait `sqlx::Executor<'c>`: <&'c mut PgConnection as sqlx::Executor<'c>> <&'c mut PgListener as sqlx::Executor<'c>> <&Pool<DB> as sqlx::Executor<'p>> = note: required for `<Transaction<'static, Postgres> as Executor>::Executor<'this>` to implement `PgExecutor<'this>` note: required by a bound in `Executor::Executor` --> src\main.rs:78:41 | 78 | type Executor<'this>: Send + Sync + sqlx::PgExecutor<'this>; | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Executor::Executor` For more information about this error, try `rustc --explain E0277`.
I saw the note in CHANGELOG about
Executor
trait but I don't know how to fix it in this case.Could you suggest me a way to fix it?
Can you think of an alternative way to use instead of this
Executor
trait?The custom trait
pub trait Executor: Send + Sync { type Executor<'this>: Send + Sync + sqlx::PgExecutor<'this>; // From https://users.rust-lang.org/t/why-does-this-impl-executor-does-not-live-long-enough/94241 fn _disable_lint(e: Self::Executor<'_>) -> Self::Executor<'_>; fn as_executor(&mut self) -> Self::Executor<'_>; } impl Executor for sqlx::PgPool { type Executor<'this> = &'this Self; fn _disable_lint(e: Self::Executor<'_>) -> Self::Executor<'_> { e } fn as_executor(&mut self) -> Self::Executor<'_> { self } } impl Executor for sqlx::Transaction<'static, sqlx::Postgres> { type Executor<'this> = &'this mut Self; fn _disable_lint(e: Self::Executor<'_>) -> Self::Executor<'_> { e } fn as_executor(&mut self) -> Self::Executor<'_> { self } }
my code:
let sql = r#"insert into users (name,age,id_card,last_update) value(?,?,?,?)"#;
let mut conn = pool.begin().await?;
let affect_rows = sqlx::query(sql)
.bind("daheige")
.bind(32)
.bind("abc")
.bind(chrono::NaiveDate::from_ymd(2022, 04, 13))
.execute(&mut conn)
.await?;
conn.commit().await?;
let id = affect_rows.last_insert_id();
println!("id = {}", id);
hi, I have this fatal problem too. 7.0.x version of the transaction operation, for mysql will not be compiled, error is as follows:
error[E0277]: the trait bound `&mut Transaction<'_, MySql>: Executor<'_>` is not satisfied
--> src/main.rs:148:18
|
148 | .execute(&mut conn)
| ------- ^^^^^^^^^ the trait `Executor<'_>` is not implemented for `&mut Transaction<'_, MySql>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `Executor<'c>`:
<&'c mut MySqlConnection as Executor<'c>>
<&'c mut AnyConnection as Executor<'c>>
<&Pool<DB> as Executor<'p>>
note: required by a bound in `Query::<'q, DB, A>::execute`
--> /Users/heige/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-core-0.7.4/src/query.rs:155:12
|
151 | pub async fn execute<'e, 'c: 'e, E>(self, executor: E) -> Result<DB::QueryResult, Error>
| ------- required by a bound in this associated function
...
155 | E: Executor<'c, Database = DB>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Query::<'q, DB, A>::execute`
For more information about this error, try `rustc --explain E0277`.
I sincerely hope that sqlx developers can fix this bug.
I corrected it in the following way fix my code, cargo check is normal.
let sql = r#"insert into users (name,age,id_card,last_update) value(?,?,?,?)"#;
let mut tx = pool.begin().await?;
let conn = &mut tx;
// https://github.com/launchbadge/sqlx/blob/main/examples/postgres/transaction/src/main.rs#L14
let affect_rows = sqlx::query(sql)
.bind("daheige")
.bind(32)
.bind("abc")
.bind(chrono::NaiveDate::from_ymd(2022, 04, 13))
// In 0.7, `Transaction` can no longer implement `Executor` directly,
// so it must be dereferenced to the internal connection type.
.execute(&mut **conn)
.await?;
tx.commit().await?;
let id = affect_rows.last_insert_id();
println!("id = {}", id);
or
let sql = r#"insert into users (name,age,id_card,last_update) value(?,?,?,?)"#;
let mut tx = pool.begin().await?;
// https://github.com/launchbadge/sqlx/blob/main/examples/postgres/transaction/src/main.rs#L14
let affect_rows = sqlx::query(sql)
.bind("daheige")
.bind(32)
.bind("abc")
.bind(chrono::NaiveDate::from_ymd(2022, 04, 13))
// by calling the deref_mut method, the mutable reference inside tx is obtained after dereferencing mut tx.
.execute(tx.deref_mut())
.await?;
tx.commit().await?;
let id = affect_rows.last_insert_id();
println!("id = {}", id);
The second method through deref_mut is relatively more readable. The second method is recommended. It is possible to run cargo check.