8

I'm trying to develop an app server in Rust using SQLX for back-end storage. It's for a primitive CMS with some idiosyncratic default behavior, to wit: if the page is not found, generate it automatically with some blank content. I want to be able to re-use the functions that invoke the SQL, so I want them to take types implementing the sqlx::Executor trait, including &mut sqlx::Connection, &mut sqlx::pool::PoolConnection, and &mut sqlx::Transaction.

Every function with a single call to the database works great!

However, it seems like I can't re-use an executor. This function is called after I've determined the page does not exist; I create a transaction and call it with an &mut Transaction as the e argument:

async fn create_page_for_title(e: impl Executor<'_, Database = Sqlite>, title: &str) -> SqlResult<RawPage> {
    let newcontent_id = insert_new_root_content(e).await?;
    let newpage = insert_new_page(e, title, newcontent_id).await?;
    Ok(newpage)
}

And this is what Rust (1.46) says:

Error[E0382]: use of moved value: `e`
   --> src/store.rs:239:30
    |
230 | async fn create_page_for_title(e: impl Executor<'_, Database = Sqlite>, title: &str) -> SqlResult<RawPage>
    |                                - move occurs because `e` has type `impl Executor<'_, Database = Sqlite>`, which does not implement the `Copy` trait
...
238 |     let newcontent_id = insert_new_root_content(e).await?;
    |                                                 - value moved here
239 |     let newpage = insert_new_page(e, title, newcontent_id).await?;
    |                                   ^ value used here after move

I know e is a reference, and references are Copy. But I seem to be unable to convince Rust of this, and I'm not sure why. This is the only function where I use an impl Executor twice in the same scope, but I'm sure I'll discover more as time goes on. Please help?

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Elf Sternberg
  • 16,129
  • 6
  • 60
  • 68
  • Would the `Acquire` trait work? It lets you begin a transaction to receive a concrete `Transaction` object, which you can then use to execute multiple queries. – apetranzilla Oct 09 '20 at 02:54
  • 4
    Also, only immutable references are `Copy`. If you're OK with this restriction you can add a bound to your signature, such that `e: impl Executor<...> + Copy`. – apetranzilla Oct 09 '20 at 03:02
  • 1
    @apetranzilla That's the insight I was missing, that it has to be immutable. Thanks. By streamlining the function calls for generating the content object, the unique slug (not shown here), and then the page object, I was able to craft a function that wasn't nearly as ugly, using the `&mut tx` object in the caller. – Elf Sternberg Oct 09 '20 at 17:03
  • 6
    Can you post your resulting code please? I am wondering what is the answer here. – gyzerok Nov 03 '21 at 14:45
  • Any news in v0.6.0 – Suge Jul 05 '22 at 03:02

0 Answers0