user583824
user583824

Reputation:

the trait `diesel::Expression` is not implemented for `bigdecimal::BigDecimal`

I am trying to create a struct that I can use in diesel for insertion. Specifically I am making the struct Insertable. On compile I get this error.

I have a struct that I am trying to make Insertable via the derive attribute. I have a field called Bounty which is supposed to represent money, so I'm using BigDecimal as the type. Upon compilation, I get the error in the title. I've also tried using f64 but that gives the same error.

#[macro_use]
extern crate diesel;
extern crate bigdecimal;

mod schema {
    use bigdecimal::BigDecimal;
    table! {
        Threads (Id) {
            Id -> Int8,
            Views -> Int4,
            Points -> Int4,
            FlagPoints -> Int4,
            IsDisabled -> Bool,
            IsAnswered -> Bool,
            Bounty -> Numeric,
            Title -> Varchar,
            Body -> Text,
            UserId -> Int8,
            CreatedBy -> Varchar,
            CreatedOn -> Timestamptz,
            LastModifiedBy -> Varchar,
            LastModifiedOn -> Timestamptz,
        }
    }

    #[allow(non_snake_case)]
    #[derive(Debug, Insertable)]
    #[table_name = "Threads"]
    pub struct InsertableThread { 
        pub Bounty: BigDecimal,
        pub Title: String,
        pub Body: String,
        pub UserId: i64
    }
}

fn main() {}

I have my struct inside it's own file and this is the entire code. The struct Thread compiles without issue. The error happens on InsertableThread as it is the one using BigDecimal. This is the error that results.

error[E0277]: the trait bound `bigdecimal::BigDecimal: diesel::Expression` is not satisfied
  --> src/main.rs:29:21
   |
29 |     #[derive(Debug, Insertable)]
   |                     ^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `bigdecimal::BigDecimal`
   |
   = note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::sql_types::Numeric>` for `bigdecimal::BigDecimal`

error[E0277]: the trait bound `bigdecimal::BigDecimal: diesel::Expression` is not satisfied
  --> src/main.rs:29:21
   |
29 |     #[derive(Debug, Insertable)]
   |                     ^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `bigdecimal::BigDecimal`
   |
   = note: required because of the requirements on the impl of `diesel::Expression` for `&bigdecimal::BigDecimal`
   = note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::sql_types::Numeric>` for `&bigdecimal::BigDecimal`

error[E0277]: the trait bound `bigdecimal::BigDecimal: diesel::Expression` is not satisfied
  --> src/main.rs:29:21
   |
29 |     #[derive(Debug, Insertable)]
   |                     ^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `bigdecimal::BigDecimal`
   |
   = note: required because of the requirements on the impl of `diesel::Expression` for `&'insert bigdecimal::BigDecimal`
   = note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::sql_types::Numeric>` for `&'insert bigdecimal::BigDecimal`

I am using Rust 1.34, diesel 1.4.2 and Postgres 11.

I am willing to change the types either in the database, Postgres, or in the Rust code. The database uses numeric and in the Rust code I've tried both f64 and BigDecimal. I am also willing to implement the trait directly myself, but I need some guidance on how to do that as I could not find samples.

Upvotes: 20

Views: 10367

Answers (3)

Basemm
Basemm

Reputation: 1253

In addition to adding the "numeric" feature flag. Diesel supports a range of bigdecimal versions:

  • v1.4.8 supports bigdecimal >=0.0.10, <0.2.0
  • v2.0.4 supports bigdecimal >=0.0.13, <0.4.0

However, the version of bigdecimal you use in your crate must be compatible with what Diesel is using as its version of bigdecimal. Otherwise you may get the error above.

You can get the version used by Diesel by using cargo tree. Example command and output:

> cargo tree -p diesel --depth=1
diesel v1.4.8
├── bigdecimal v0.1.2 <-----------------
├── bitflags v1.3.2
├── byteorder v1.4.3
...

Based on that output above, your Cargo.toml should look like so:

[dependencies]
diesel = { version = "1.4.8", features = ["numeric", ...] }
bigdecimal = "0.1.2" # <-----------------

Upvotes: 10

tobias47n9e
tobias47n9e

Reputation: 2231

You might reach this question by searching an error message that is really similar:

the trait `diesel::Expression` is not implemented for `(schema::..., schema::..., schema::...)`

This is just a reminder to count the number of columns you have in the table!{} macro because you might be reaching the default 32 column limit.

According to the Diesel changelog you should use the following features if you use more than the default 32 columns.

64 columns (Cargo.toml)

diesel = { version = "1.4", features = [..., "64-column-tables"] }

128 columns (Cargo.toml):

diesel = { version = "1.4", features = [..., "128-column-tables"] }

Using more columns is not possible and might be a hint that the table design is not ideal (See: https://github.com/diesel-rs/diesel/issues/2312#issuecomment-591623303).

Upvotes: 4

Shepmaster
Shepmaster

Reputation: 431779

Diesel uses Cargo features to opt-in to enhanced functionality.

I haven't found a clear documentation page for these, but they are listed in its Cargo.toml:

[features]
default = ["with-deprecated", "32-column-tables"]
extras = ["chrono", "serde_json", "uuid", "deprecated-time", "network-address", "numeric", "r2d2"]
unstable = ["diesel_derives/nightly"]
large-tables = ["32-column-tables"]
huge-tables = ["64-column-tables"]
x32-column-tables = ["32-column-tables"]
32-column-tables = []
x64-column-tables = ["64-column-tables"]
64-column-tables = ["32-column-tables"]
x128-column-tables = ["128-column-tables"]
128-column-tables = ["64-column-tables"]
postgres = ["pq-sys", "bitflags", "diesel_derives/postgres"]
sqlite = ["libsqlite3-sys", "diesel_derives/sqlite"]
mysql = ["mysqlclient-sys", "url", "diesel_derives/mysql"]
with-deprecated = []
deprecated-time = ["time"]
network-address = ["ipnetwork", "libc"]
numeric = ["num-bigint", "bigdecimal", "num-traits", "num-integer"]

You need to enable the numeric feature and ensure you use a version of bigdecimal that is compatible with Diesel:

[dependencies]
diesel = { version = "1.4.2", features = ["numeric"] }
bigdecimal = "0.0.14"

And the code compiles:

#[macro_use]
extern crate diesel;

use crate::schema::threads;
use bigdecimal::BigDecimal;

mod schema {
    table! {
        threads (id) {
            id -> Int4,
            bounty -> Numeric,
        }
    }
}

#[derive(Debug, Insertable)]
#[table_name = "threads"]
pub struct InsertableThread {
    pub bounty: BigDecimal,
}

See also:

Upvotes: 28

Related Questions