Today I Learned

It was actually last night, but close enough
This commit is contained in:
R Tyler Croy 2020-09-15 17:57:24 -07:00
parent d93cc122b3
commit 07f2fcbc2f
No known key found for this signature in database
GPG Key ID: E5C92681BEF6CEA2
1 changed files with 67 additions and 0 deletions

View File

@ -0,0 +1,67 @@
---
layout: post
title: "Trait not bound errors with Diesel"
tags:
- rust
- diesel
- postgresql
---
Recently I have been exploring using [Diesel](https://diesel.rs) for a
simple Rust web application. I quickly ran into a very confusing `trait
bound` error, listed below when integrating with `chrono`. It took me a
while to understand and fix the error, which I thought I should write down
for later!
The error only started showing up when I queried a specific model:
```
error[E0277]: the trait bound `DateTime<Utc>: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Timestamptz>, Pg>` is not satisfied
--> src/main.rs:85:64
|
85 | let choices: Vec<Choice> = Choice::belonging_to(&poll).get_results(&pgconn).expect("Failed to get relations");
| ^^^^^^^^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Timestamptz>, Pg>` is not implemented for `DateTime<Utc>`
|
= help: the following implementations were found:
<DateTime<Utc> as FromSql<diesel::sql_types::Timestamptz, Pg>>
= note: required because of the requirements on the impl of `Queryable<diesel::sql_types::Nullable<diesel::sql_types::Timestamptz>, Pg>` for `DateTime<Utc>`
= note: required because of the requirements on the impl of `Queryable<(diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Integer, diesel::sql_types::Nullable<diesel::sql_types::Timestamptz>), Pg>` for `(i32, std::string::String, i32, DateTime<Utc>)`
= note: required because of the requirements on the impl of `Queryable<(diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Integer, diesel::sql_types::Nullable<diesel::sql_types::Timestamptz>), Pg>` for `models::Choice`
= note: required because of the requirements on the impl of `LoadQuery<PooledConnection<ConnectionManager<PgConnection>>, models::Choice>` for `diesel::query_builder::SelectStatement<schema::choices::table, query_builder::select_clause::DefaultSelectClause, query_builder::distinct_clause::NoDistinctClause, query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<schema::choices::columns::poll_id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>>`
error: aborting due to previous error; 1 warning emitted
```
I stumbled into [this closed issue](https://github.com/diesel-rs/diesel/issues/2445), which didn't really help me, but it did inspire me to review the `src/schema.rs`:
```rust
table! {
votes (id) {
id -> Int4,
voter -> Text,
choice_id -> Int4,
poll_id -> Int4,
created_at -> Nullable<Timestamptz>,
}
}
```
The `created_at` column is what is causing issues for me, and I noticed that it's wrapped in a `Nullable`. Meanwhile, my struct looks like:
```rust
#[derive(Associations, Debug, Identifiable, Queryable, Serialize)]
#[belongs_to(Poll)]
pub struct Choice {
id: i32,
details: String,
poll_id: i32,
created_at: DateTime<Utc>,
}
```
Turns out the `Nullable` wrapper around the `Timestamptz` SQL type was causing behavior that I didn't want. The underlying problem ended up being that my table definition didn't include a `NOT NULL` despite including a `DEFAULT NOW()`.
Naturally, altering the statement to be `created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()` caused my compilation error to disappear, fun!