Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to insert when passing value by reference to another function #7

Closed
heroin-moose opened this issue Jan 18, 2022 · 6 comments
Closed

Comments

@heroin-moose
Copy link

Code:

use ormlite::Model;
use ormlite::model::*;
use sqlx::FromRow;
use sqlx::SqlitePool;

#[derive(Model, FromRow)]
struct Example {
    #[ormlite(primary_key)]
    id: i64
}

async fn insert(e: &Example, pool: &SqlitePool) -> ormlite::Result<Example> {
    e.insert(pool).await
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let pool = SqlitePool::connect("/tmp/database").await?;
    let e1 = Example { id: 20 };

    insert(&e1, &pool).await?;

    Ok(())
}

Error:

   Compiling ormlite-issue v0.1.0 (/tmp/ormlite-issue)
error[E0507]: cannot move out of `*e` which is behind a shared reference
  --> src/main.rs:13:5
   |
13 |     e.insert(pool).await
   |     ^^^^^^^^^^^^^^ move occurs because `*e` has type `Example`, which does not implement the `Copy` trait

For more information about this error, try `rustc --explain E0507`.
error: could not compile `ormlite-issue` due to previous error
@heroin-moose
Copy link
Author

heroin-moose commented Jan 18, 2022

However, this works (given e implements Clone):

e.clone().insert(pool).await

@kurtbuilds
Copy link
Owner

kurtbuilds commented Jan 18, 2022

I believe this is working as designed.

The query depends on the Example because it needs to populate the query parameters. Since you're only borrowing it, the compiler can't guarantee that the &Example lives as long as the query.

You can solve this by moving example into your insert, or cloneing e, as you did.

@heroin-moose
Copy link
Author

You mean the query has the lifetime of pool?

@heroin-moose
Copy link
Author

Because raw query works, e.g. this compiles ok:

async fn explicit_insert(e: &Example, pool: &SqlitePool) -> sqlx::Result<()> {
    sqlx::query("INSERT INTO example (id) VALUES ($1)")
        .bind(&e.id)
        .execute(pool)
        .await?;
    Ok(())
}

I still pass the id by reference but compiler is happy. Am I missing something obvious?

@kurtbuilds
Copy link
Owner

You mean the query has the lifetime of pool?

Not exactly. In your function, e and pool have different (unspecified) lifetimes.

ormlite::Model.insert creates a ::sqlx::QueryAs which takes the model's fields as borrowed arguments. Importantly, the binding happens asynchronously, because it happens inside the Model.insert function. Which is why the compiler complains about &Example. If you move it fn insert(e: Example, ...), or clone it, this issue should go away.

In your second post, you manually do the binding, thus the binding happens synchronously, and the problem goes away.

@heroin-moose
Copy link
Author

Thanks for the details!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants