Hi,
I'm creating a simple application to interact with a database using the SQLx library. Currently, I'm trying to reuse a transaction acquired from a pool with pool.begin()
. However, I'm running into problems with re reuse of the transaction. The function truncate
should deletes all entries from tables given in the config object. The config object looks like:
struct Config {
locations: Vec<ConfigItem>,
}
struct ConfigItem {
table_name: String,
dir_path: String,
upload_url: String,
}
Since the function should return the affected rows, I wanted to use fold to accumulate the affected rows of all the deleted tables. Because SQLx is async, I need to await the result so I decided to convert the config.locations
into a stream. This is the Code I'm having issues with:
async fn truncate(config: &Config, tx: &mut Transaction<'_, MySql>) -> Result<u64> {
let stream = stream::iter(&config.locations);
let rows_affected = stream.fold(0, |acc, item| async move {
let query = format!("DELETE FROM {}", item.table_name);
acc + sqlx::query(&query)
.execute(tx)
.await
.unwrap()
.rows_affected()
});
Ok(rows_affected)
}
The Error is:
error[E0507]: cannot move out of `tx`, a captured variable in an `FnMut` closure
--> src/main.rs:103:63
|
84 | async fn truncate(config: &Config, tx: &mut Transaction<'_, MySql>) -> Result<u64> {
| -- captured outer variable
...
103 | let rows_affected = stream.fold(0, |acc, item| async move {
| ________________________________________-----------____________^
| | |
| | captured by this `FnMut` closure
104 | | let query = format!("DELETE FROM {}", item.table_name);
105 | | acc + sqlx::query(&query)
106 | | .execute(tx)
| | --
| | |
| | variable moved due to use in generator
| | move occurs because `tx` has type `&mut Transaction<'_, MySql>`, which does not implement the `Copy` trait
... |
109 | | .rows_affected()
110 | | });
| |_____^ move out of `tx` occurs here
I get that the issue comes from async move
which forces the closure to take ownership of the transaction. I tried to remove the move
which gives me the following error:
async fn truncate(config: &Config, tx: &mut Transaction<'_, MySql>) -> Result<u64> {
| -- captured outer variable
...
103 | let rows_affected = stream.fold(0, |acc, item| async {
| ________________________________________-----------_______^
| | |
| | captured by this `FnMut` closure
104 | | let query = format!("DELETE FROM {}", item.table_name);
105 | | acc + sqlx::query(&query)
106 | | .execute(tx)
| | --
| | |
| | variable moved due to use in generator
| | move occurs because `tx` has type `&mut Transaction<'_, MySql>`, which does not implement the `Copy` trait
... |
109 | | .rows_affected()
110 | | });
error[E0373]: async block may outlive the current function, but it borrows `acc`, which is owned by the current function
--> src/main.rs:103:58
|
103 | let rows_affected = stream.fold(0, |acc, item| async {
| __________________________________________________________^
104 | | let query = format!("DELETE FROM {}", item.table_name);
105 | | acc + sqlx::query(&query)
| | --- `acc` is borrowed here
106 | | .execute(tx)
... |
109 | | .rows_affected()
110 | | });
| |_____^ may outlive borrowed value `acc`
I don't really understand this error. I thought about cloning the tx
since it's a RC Reference, but clone is not implemented for tx
. I want to use the same tx
in other functions later on which change some other stuff in the database and then commit it all at once.
How can I achieve the functionality of counting all the affected rows of a query with fold and use the transaction later on to do more work and commit eventually?