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

Invalid deserialization for MySQL's Decimal type #122

Closed
marcustut opened this issue Aug 10, 2022 · 4 comments
Closed

Invalid deserialization for MySQL's Decimal type #122

marcustut opened this issue Aug 10, 2022 · 4 comments

Comments

@marcustut
Copy link

marcustut commented Aug 10, 2022

I'm having a MySQL table as follows:

model expenses {
  id                     Int      @id @default(autoincrement())
  name                   String   @db.VarChar(255)
  amount                 Decimal  @db.Decimal(15, 2)
  date                   DateTime @db.Date
  comment                String?  @db.VarChar(255)
  expenses_categories_id Int?
}

and I'm querying it like this

    let db = prisma::new_client()
        .await
        .expect("failed to connect to database (prisma)");

    let expenses = db.expenses().find_many(vec![]).exec().await.unwrap();
    println!("{:?}", expenses);

however I'm getting an error

    Finished dev [unoptimized + debuginfo] target(s) in 0.68s
     Running `target/debug/marcustutcore`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Deserialize(InvalidType(Str("7.95"), "f64"))', core/src/main.rs:96:65
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

it seems to me that the deserialization failed for the amount field which in MySQL Type is a decimal and in rust it should be returned as a f64. Somehow string type got mixed in and the deserialization failed.

@marcustut
Copy link
Author

Upon further inspection, I found that the data struct in the generated code is

    pub struct Data {
        #[serde(rename = "id")]
        pub id: i32,
        #[serde(rename = "name")]
        pub name: String,
        #[serde(rename = "amount")]
        pub amount: f64,
        #[serde(rename = "date")]
        pub date: chrono::DateTime<chrono::FixedOffset>,
        #[serde(rename = "comment")]
        pub comment: Option<String>,
        #[serde(rename = "incomes_categories_id")]
        pub incomes_categories_id: Option<i32>,
    }

Notice that the amount field is f64. However, to my knowledge the bigdecimal crate internally deserialize into string. Hence, the error Deserialize(InvalidType(Str("7.95"), "f64")), it is because the underlying value is string but serde expects it to be f64.

I manually change the field from pub amount: f64 to pub amount: String, then the error goes away. It's just that the value is returned as a string. However, to solve this I suggest swapping the bigdecimal crate to rust_decimal, this crate allow deserialization to float with the feature flag serde-with-float.

@Brendonovich
Copy link
Owner

Native types like Decimal aren't properly supported yet, and won't be for a while - see #83. If you can get away with using Float then that should deserialize to f64 correctly, but for now I don't have much good news for you 😅

@cameronbraid
Copy link
Contributor

Is there a way to configure the schema so that a decimal field can be deserialized into a string without having to hand edit the generated code ?

@Brendonovich
Copy link
Owner

Not right now, sorry

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

3 participants