kurtbuilds / ormlite

An ORM in Rust for developers that love SQL.
https://crates.io/crates/ormlite
MIT License
216 stars 11 forks source link

`update_partial` not working #29

Closed Amulet9 closed 1 year ago

Amulet9 commented 1 year ago

Hello, So i have this function set_key which is supposed to update a value in the database. The issue? update_partial is not updating the value in the database, even though the struct returned by .update() has the updated value. Which has me confused, as i am not sure why this is happening? Everything other than it being updated in the database works as expected.

#[derive(Model, Debug, Clone)]
pub struct Application {
    #[ormlite(primary_key)]
    pub interface_name: String,
    pub interface: Vec<u8>,
}

    pub async fn set_key(
        &mut self,
        schema_name: impl ToString,
        property_name: impl ToString,
        value: SVariant,
        db: &mut SqliteConnection,
    ) -> Result<()> {
        let mut interface: crate::types::Interface =
            bincode::deserialize(&self.applicaion.interface)?;
        interface.set_key(schema_name, property_name, value).await?;
        let serialized = bincode::serialize(&interface)?;
        let app = self
            .applicaion
            .update_partial()
            .interface(serialized)
            .update(db)
            .await?;
        self.applicaion = app;
        return Ok(());
    }
kurtbuilds commented 1 year ago

Thank you for reporting. On first glance, that code looks right. The update object gets constructed using a “RETURNING ” query fragment, so it’s definitely odd you’re getting the expected value without the database updating.

Here’s a bunch of trouble shooting questions:

Can you create a minimum repo reproducing the issue?

One possibility: can you try making the arguments concrete by calling to_string on them? If it’s compiling, this should be working, but maybe the generics are somehow tripping it up.

Did you try using RUST_LOG=sqlx=info to get the raw SQL that’s being used? Can you post that output?

Are you using constraints of any kind? There was a recent bug already fixed related to DEFERRED constraints in Postgres. I see you’re using SQLite, but the same issue probably would have affected it.

Dumb question, but is there a chance the database file isn’t getting saved for some reason? That would be an obvious explanation.

Amulet9 commented 1 year ago

Hello there, thank you for your comment.

First of all, i did the sqlx env logger step and got this output

[2023-06-20T04:02:12Z INFO  sqlx::query] PRAGMA foreign_keys = ON; …; rows affected: 0, rows returned: 0, elapsed: 53.011µs

    PRAGMA foreign_keys = ON;

[2023-06-20T04:02:12Z INFO  sqlx::query] CREATE TABLE IF NOT …; rows affected: 0, rows returned: 0, elapsed: 210.406µs

    CREATE TABLE IF NOT EXISTS _sqlx_migrations (
      version BIGINT PRIMARY KEY,
      description TEXT NOT NULL,
      installed_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      success BOOLEAN NOT NULL,
      checksum BLOB NOT NULL,
      execution_time BIGINT NOT NULL
    );

[2023-06-20T04:02:12Z INFO  sqlx::query] SELECT version FROM _sqlx_migrations …; rows affected: 0, rows returned: 0, elapsed: 129.918µs

    SELECT
      version
    FROM
      _sqlx_migrations
    WHERE
      success = false
    ORDER BY
      version
    LIMIT
      1

[2023-06-20T04:02:12Z INFO  sqlx::query] SELECT version, checksum FROM …; rows affected: 0, rows returned: 1, elapsed: 81.606µs

    SELECT
      version,
      checksum
    FROM
      _sqlx_migrations
    ORDER BY
      version

[2023-06-20T04:02:12Z INFO  sqlx::query] SELECT * FROM "application" …; rows affected: 0, rows returned: 1, elapsed: 95.042µs

    SELECT
      *
    FROM
      "application"
    WHERE
      interface_name = ?

Which makes it pretty clear the insert query isn't being executed, the results are the same with concrete types.

What i found interesting is a test with the "almost" same code works fine, except one thing.

#[tokio::test]
async fn test_cli() {
    std::env::set_var("RUST_LOG", "sqlx=info");
    env_logger::init();
    let conf = crate::config::Config::setup_config().await.unwrap();
    let mut db = crate::db::setup(&conf).await.unwrap();
    let mut app = crate::model::Interface::fetch_existing_interface("org.assigned.target", &mut db)
        .await
        .unwrap();
    println!(
        "{:#?} {:#?}",
        app.set_key(
            "org.assigned.target.test",
            "test_property_2",
            types::SVariant::Int32(59),
            &mut db
        )
        .await
        .unwrap(),
        app.get_key("org.assigned.target.test", "test_property_2")
            .await
            .unwrap()
    );
}

Now if you run this code, it will work just like the former, no "update" query being executed. but if you add one single line of code to it.

 tokio::time::sleep(Duration::from_secs(56))

It works as expected(see image), So i am guessing the issue here is that the program exits before the update query is even ran. image

Though how the struct returned is updated before the query even happens? No idea.

kurtbuilds commented 1 year ago

Definitely weird. That's a great clue to what's going on. Can you create a minimum reproducible repo or a full code sample?

Amulet9 commented 1 year ago

Here you go, Apologies for the code being awful.

kurtbuilds commented 1 year ago

@Amulet9 I'm not able to reproduce this in the repo you shared.

As you report, the final UPDATE query is not logged, but inspecting the database afterward confirms the query has been run and the data updated. While the logging comes from the underlying sqlx library, I believe what's happening is they get output on "next tick".

I'm going to proactively close this issue, but if you're still encountering this, please let me know with additional information about reproduction steps, and I'll re-open.