diesel-rs / diesel

A safe, extensible ORM and Query Builder for Rust
https://diesel.rs
Apache License 2.0
12.55k stars 1.05k forks source link

The trait bound `chrono::NaiveDateTime: diesel::Expression` is not satisfied #968

Closed elliotekj closed 7 years ago

elliotekj commented 7 years ago
diesel = { version = "0.13", features = ["postgres", "chrono"] }
diesel_codegen = { version = "0.13", features = ["postgres"] }
chrono = { version = "0.4", features = ["serde"] }
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"

Trying to upgrade from Diesel 0.11, Serde 0.9 and Chrono 0.3 to the above versions.

I'm seeing the following for each AsChangeset that uses chrono::NaiveDateTime:

error[E0277]: the trait bound `chrono::NaiveDateTime: diesel::Expression` is not satisfied
  --> src/models/emails.rs:37:10
   |
37 | #[derive(AsChangeset, Clone, Debug)]
   |          ^^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `chrono::NaiveDateTime`
   |
   = note: required because of the requirements on the impl of `diesel::Expression` for `&chrono::NaiveDateTime`
   = note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::types::Timestamp>` for `&chrono::NaiveDateTime`
   = note: this error originates in a macro outside of the current crate

I think this should be reproducible with the above versions of Chrono and Diesel by having a table that has a column of type chrono::NaiveDateTime, then having an AsChangeset struct that tries to update said NaiveDateTime column.

I'm using NaiveDateTime in Rust for Postgres' TIMESTAMP:

updated_at TIMESTAMP NOT NULL default now()

I've been going round in circles with this, but if it isn't actually a Diesel issue then I apologise in advance. Thanks for all the work on Diesel, it's excellent! :)

killercup commented 7 years ago

Very nice issue description! (We should steal this and make it a template!)

I think your problem stems from chrono recently yanking its 0.3.1 version and releasing 0.4 with serde 1.0 support instead (this was a breaking change in 0.3.1!). Diesel 0.13.0 does not support chrono 0.4. Which means two versions of chrono will be built, and they are not compatible to each other.

Can you try using diesel master instead?

diesel = { git = "https://github.com/diesel-rs/diesel", features = ["postgres", "chrono"] }
killercup commented 7 years ago

I've been going round in circles with this, but if it isn't actually a Diesel issue then I apologise in advance. Thanks for all the work on Diesel, it's excellent! :)

Thanks :) If it turns out this is a problem with two chrono versions, you can use cargo-tree to see this more easily.

elliotekj commented 7 years ago

Diesel 0.13.0 does not support chrono 0.4

Ah, that's probably what the problem is then! I saw this line and assumed it did.

Can you try using diesel master instead?

I wasn't expecting such a quick reply, I'll try it out as soon as I'm back at my work machine and let you know.

Very nice issue description! (We should steal this and make it a template!)

Thanks! I can't take credit for it though, I just filled in the details you ask for :)

killercup commented 7 years ago

Thanks! I can't take credit for it though, I just filled in the details you ask for :)

lol 😅

elliotekj commented 7 years ago

Right. So Diesel's master gets me past the original issue but I now have a different "this error originates in a macro outside of the current crate" error:

error[E0277]: the trait bound `diesel::pg::PgConnection: diesel::connection::Connection` is not satisfied
  --> src/database.rs:6:1
   |
6  | / lazy_static! {
7  | |     static ref CONNECTION: r2d2::Pool<ConnectionManager<PgConnection>> = {
8  | |         let config = r2d2::Config::default();
9  | |         let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
...  |
12 | |     };
13 | | }
   | |_^ the trait `diesel::connection::Connection` is not implemented for `diesel::pg::PgConnection`
   |
   = note: required because of the requirements on the impl of `r2d2::ManageConnection` for `r2d2_diesel::ConnectionManager<diesel::pg::PgConnection>`
   = note: required by `r2d2::Pool`
   = note: this error originates in a macro outside of the current crate

Things I've tried:

database.rs:

use diesel::pg::PgConnection;
use r2d2;
use r2d2_diesel::ConnectionManager;
use std::env;

lazy_static! {
    static ref CONNECTION: r2d2::Pool<ConnectionManager<PgConnection>> = {
        let config = r2d2::Config::default();
        let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
        let manager = ConnectionManager::<PgConnection>::new(database_url);
        r2d2::Pool::new(config, manager).expect("Failed to create pool.")
    };
}

pub fn connection() -> r2d2::Pool<ConnectionManager<PgConnection>> {
    CONNECTION.clone()
}

Feel free to close this when it gets too off topic from the original issue / becomes too specific to just how I'm using it.

killercup commented 7 years ago

Does cargo tree give you two diesel versions? I'd assume so, because r2d2-diesel uses the latest diesel, not its master branch.

Maybe a better way to get this going is to not specify diesel master, but 0.13.0 and adding

[replace]
"diesel:0.13.0" = { git = "https://github.com/diesel-rs/diesel" }

This replace every occurrence of diesel 0.13 in your dependency graph. (You might need to add the same lines for tje other diesel-* crates.)

elliotekj commented 7 years ago

@killercup You're a gentleman and a scholar! Thanks so much for taking the time to help!


For anyone else who finds themselves here:

Add Diesel and co. as you would usually:

diesel = { version = "0.13.0", features = ["postgres", "chrono"] }
diesel_codegen = { version = "0.13.0", features = ["postgres"] }
r2d2 = "0.7"
r2d2-diesel = "0.13.0"

As @killercup said, replace the version of Diesel you're using like so:

[replace]
"diesel:0.13.0" = { git = "https://github.com/diesel-rs/diesel" }

Run cargo update to make sure r2d2-diesel is using the latest version of Diesel it can.

Build.


Thanks again @killercup 😄

killercup commented 7 years ago

Thank you! I'm glad this works for you. With the next release of Diesel, 0.14, you should only need to increment the diesel and r2d2 version, remove the [replace], and it should all just work™ :)

elliotekj commented 7 years ago

Just confirming that Diesel 0.14 does indeed resolve the above issues. Good work folks 👍

sgrif commented 7 years ago

Thanks for confirming. :heart:

iddm commented 7 years ago

@sgrif Actually, I use 0.14 and 0.14.1 now and I have these errors:

error[E0277]: the trait bound `chrono::NaiveDateTime: phone::_IMPL_DESERIALIZE_FOR_PhoneInfo::_serde::Serialize` is not satisfied
 --> src/models.rs:9:88
  |
9 | #[derive(Debug, Clone, Queryable, Identifiable, Insertable, Associations, AsChangeset, Serialize, Deserialize)]
  |                                                                                        ^^^^^^^^^ the trait `phone::_IMPL_DESERIALIZE_FOR_PhoneInfo::_serde::Serialize` is not implemented for `chrono::NaiveDateTime`
  |
  = note: required by `phone::_IMPL_DESERIALIZE_FOR_PhoneInfo::_serde::ser::SerializeStruct::serialize_field`

error[E0277]: the trait bound `chrono::NaiveDateTime: phone::_IMPL_DESERIALIZE_FOR_PhoneInfo::_serde::Deserialize` is not satisfied
 --> src/models.rs:9:99
  |
9 | #[derive(Debug, Clone, Queryable, Identifiable, Insertable, Associations, AsChangeset, Serialize, Deserialize)]
  |                                                                                                   ^^^^^^^^^^^ the trait `phone::_IMPL_DESERIALIZE_FOR_PhoneInfo::_serde::Deserialize` is not implemented for `chrono::NaiveDateTime`
  |
  = note: required by `phone::_IMPL_DESERIALIZE_FOR_PhoneInfo::_serde::de::SeqVisitor::visit`

error[E0277]: the trait bound `chrono::NaiveDateTime: phone::_IMPL_DESERIALIZE_FOR_PhoneInfo::_serde::Deserialize` is not satisfied
 --> src/models.rs:9:99
  |
9 | #[derive(Debug, Clone, Queryable, Identifiable, Insertable, Associations, AsChangeset, Serialize, Deserialize)]
  |                                                                                                   ^^^^^^^^^^^ the trait `phone::_IMPL_DESERIALIZE_FOR_PhoneInfo::_serde::Deserialize` is not implemented for `chrono::NaiveDateTime`
  |
  = note: required by `phone::_IMPL_DESERIALIZE_FOR_PhoneInfo::_serde::de::MapVisitor::visit_value`

error: aborting due to 3 previous errors

error: Could not compile `omp-mdm-server`.

To learn more, run the command again with --verbose.
#[derive(Debug, Clone, Queryable, Identifiable, Insertable, Associations, AsChangeset, Serialize, Deserialize)]
#[table_name = "phones"]
#[primary_key(imei)]
#[belongs_to(User)]
pub struct Phone {
    pub imei: i64,
    pub model: String,
    pub vendor: String,
    pub manufacturer: String,
    pub last_sync: NaiveDateTime, // In UTC
    pub user_id: i32,
}
[dependencies]
rocket = "0.2.8"
rocket_codegen = "0.2.8"
rocket_contrib = "0.2.8"
serde = "0.9"
serde_derive = "0.9"
serde_json = "0.9"
r2d2 = "0.7.2"
r2d2-diesel = "0.14"
chrono = { version = "0.4", features = ["serde"] }

[dependencies.diesel]
version = "0.14"
default-features = false
features = ["sqlite", "chrono"]

[dependencies.diesel_codegen]
version = "0.14"
default-features = false
features = ["sqlite"]
killercup commented 7 years ago

@vityafx these look like serde issues—most likely because you are using serde 0.9 and chrono requires 1.0.

iddm commented 7 years ago

@killercup oh well, yes, totally forgot about that but I did knew that! :-D Just rocket uses old serde, this is the problem, I guess, but I can't change it :( Thanks.

killercup commented 7 years ago

Rocket 0.3 will include it: https://github.com/SergioBenitez/Rocket/issues/273#issuecomment-301339550

Maybe you can use rocket's master branch until then?

iddm commented 7 years ago

@killercup a very good notice, I have just found this information too (about it's master branch), but thanks for such a nice help here anyway!

greenpdx commented 6 years ago

I have read this and I still do not understand the fix. I am tried both diesel 0.16.0 and master c5fa99574673e09e6e5029cda517802a82f66933

I have a postgress table with a TIMESTAMP column.

error[E0277]: the trait bound models::chrono::NaiveDateTime: diesel::types::FromSqlRow<diesel::types::Nullable<diesel::types::Timestamp>, diesel::pg::Pg> is not satisfied --> src/main.rs:98:10 98 .get_result(conn) ^^^^^^^^^^ the trait diesel::types::FromSqlRow<diesel::types::Nullable<diesel::types::Timestamp>, diesel::pg::Pg> is not implemented for models::chrono::NaiveDateTime

= help: the following implementations were found: <models::chrono::NaiveDateTime as diesel::types::FromSqlRow<diesel::types::Timestamp, DB>> <models::chrono::NaiveDateTime as diesel::types::FromSqlRow<diesel::types::Timestamptz, DB>> = note: required because of the requirements on the impl of diesel::types::FromSqlRow<(diesel::types::Integer, diesel::types::Nullable<diesel::types::Timestamp>, diesel::types::Text), diesel::pg::Pg> for (i32, models::chrono::NaiveDateTime, std::string::String) = note: required because of the requirements on the impl of diesel::Queryable<(diesel::types::Integer, diesel::types::Nullable<diesel::types::Timestamp>, diesel::types::Text), diesel::pg::Pg> for models::Tst1 = note: required because of the requirements on the impl of diesel::LoadQuery<diesel::PgConnection, models::Tst1> for diesel::query_builder::insert_statement::InsertStatement<schema::__diesel_infer_schema::infer_tst1::tst1::table, (diesel::insertable::ColumnInsertValue<schema::__diesel_infer_schema::infer_tst1::tst1::columns::methd, diesel::expression::bound::Bound<diesel::types::Text, &std::string::String>>,)>

error: aborting due to previous error

weiznich commented 6 years ago

@greenpdx Your issue is slightly different than that one described here. You are trying to load a nullable sql type (Nullable<Timestamp>) into a not nullable rust type (NaiveDateTime). Diesel does not support such mappings to prevent errors. Instead try to change the rust type into Option<NaiveDateTime>.

GopherJ commented 5 years ago

I know It's a closed issue but I encountered another similiar error: *const str: diesel::deserialize::FromSql<diesel::sql_types::Timestamp, diesel::pg::Pg, anyone knows how to fix it?

weiznich commented 5 years ago

@GopherJ That error message indicates that you trying to load a Timestamp into a string which is not supported. You need to enable the chrono feature and use chrono::NaiveDateTime for this.

dosterthebernese commented 5 years ago

I get this issue still, using chrono etc.

use super::schema::trades; use chrono;

[derive(Queryable,Debug)]

pub struct Trade { pub id: i32, pub cusip: Option, pub sedol: Option, pub isin: Option, pub ticker: Option, pub trade_date: chrono::NaiveDateTime, pub published: bool, }

[derive(Insertable,Debug)]

[table_name = "trades"]

pub struct NewTrade<'a> { pub cusip: &'a str, pub sedol: &'a str, pub isin: &'a str, pub ticker: &'a str, pub trade_date: chrono::NaiveDateTime,

}

dosterthebernese commented 5 years ago
error[E0277]: the trait bound chrono::NaiveDateTime: diesel::Expression is not satisfied --> src/models.rs:32:10 32 #[derive(Insertable,Debug)] ^^^^^^^^^^ the trait diesel::Expression is not implemented for chrono::NaiveDateTime

= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Timestamp> for chrono::NaiveDateTime

error[E0277]: the trait bound chrono::NaiveDateTime: diesel::Expression is not satisfied --> src/models.rs:32:10 32 #[derive(Insertable,Debug)] ^^^^^^^^^^ the trait diesel::Expression is not implemented for chrono::NaiveDateTime

= note: required because of the requirements on the impl of diesel::Expression for &chrono::NaiveDateTime = note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Timestamp> for &chrono::NaiveDateTime

error[E0277]: the trait bound chrono::NaiveDateTime: diesel::Expression is not satisfied --> src/models.rs:32:10 32 #[derive(Insertable,Debug)] ^^^^^^^^^^ the trait diesel::Expression is not implemented for chrono::NaiveDateTime

= note: required because of the requirements on the impl of diesel::Expression for &'insert chrono::NaiveDateTime = note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Timestamp> for &'insert chrono::NaiveDateTime

error: aborting due to 3 previous errors

weiznich commented 5 years ago

@dosterthebernese Our issue tracker is used to track bugs and feature request. For asking questions please use our gitter channel