ThirteenthWolf
ThirteenthWolf

Reputation: 346

Trouble & Confusion with Diesel and Rust Traits

I'm trying to use the Diesel crate (version 2.0.2; rustc 1.63.0) for an application and have some code that goes like this:

src/models.rs

use uuid::Uuid;
use diesel::prelude::*;

use crate::schema::entities::dsl::entities;

type DB = diesel::pg::Pg;

#[derive(Queryable, PartialEq, Debug)]
#[diesel(table_name = entities)]
pub struct Entity {
    pub id: u16,
    pub uuid: Uuid,
    pub username: Option<String>
}

impl Entity {
    pub fn get_all(connection: &mut PgConnection) -> QueryResult<Vec<Entity>> {
        entities.load::<Entity>(connection)
    }
}

src/schema.rs

// @generated automatically by Diesel CLI.

diesel::table! {
    entities (id) {
        id -> Int4,
        uuid -> Uuid,
        username -> Nullable<Text>,
    }
}

diesel::allow_tables_to_appear_in_same_query!(
    entities,
);

However, this will not compile. The following errors are thrown when I try:

error[E0277]: the trait bound `(Integer, diesel::sql_types::Uuid, diesel::sql_types::Nullable<diesel::sql_types::Text>): load_dsl::private::CompatibleType<Entity, _>` is not satisfied
    --> src/models.rs:20:18
     |
20   |         entities.load::<Entity>(connection)
     |                  ^^^^ the trait `load_dsl::private::CompatibleType<Entity, _>` is not implemented for `(Integer, diesel::sql_types::Uuid, diesel::sql_types::Nullable<diesel::sql_types::Text>)`
     |
     = help: the following other types implement trait `load_dsl::private::CompatibleType<U, DB>`:
               (ST0, ST1)
               (ST0, ST1, ST2)
               (ST0, ST1, ST2, ST3)
               (ST0, ST1, ST2, ST3, ST4)
               (ST0, ST1, ST2, ST3, ST4, ST5)
               (ST0, ST1, ST2, ST3, ST4, ST5, ST6)
               (ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7)
               (ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7, ST8)
             and 24 others
     = note: required because of the requirements on the impl of `LoadQuery<'_, _, Entity>` for `entities::table`
note: required by a bound in `diesel::RunQueryDsl::load`
    --> /home/username/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-2.0.2/src/query_dsl/mod.rs:1499:15
     |
1499 |         Self: LoadQuery<'query, Conn, U>,
     |               ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::RunQueryDsl::load`

error[E0277]: the trait bound `Entity: FromSqlRow<_, _>` is not satisfied
    --> src/models.rs:20:18
     |
20   |         entities.load::<Entity>(connection)
     |                  ^^^^ the trait `FromSqlRow<_, _>` is not implemented for `Entity`
     |
     = help: the following other types implement trait `FromSqlRow<ST, DB>`:
               <(T1, T0) as FromSqlRow<(ST1, Untyped), __DB>>
               <(T1, T2, T0) as FromSqlRow<(ST1, ST2, Untyped), __DB>>
               <(T1, T2, T3, T0) as FromSqlRow<(ST1, ST2, ST3, Untyped), __DB>>
               <(T1, T2, T3, T4, T0) as FromSqlRow<(ST1, ST2, ST3, ST4, Untyped), __DB>>
               <(T1, T2, T3, T4, T5, T0) as FromSqlRow<(ST1, ST2, ST3, ST4, ST5, Untyped), __DB>>
               <(T1, T2, T3, T4, T5, T6, T0) as FromSqlRow<(ST1, ST2, ST3, ST4, ST5, ST6, Untyped), __DB>>
               <(T1, T2, T3, T4, T5, T6, T7, T0) as FromSqlRow<(ST1, ST2, ST3, ST4, ST5, ST6, ST7, Untyped), __DB>>
               <(T1, T2, T3, T4, T5, T6, T7, T8, T0) as FromSqlRow<(ST1, ST2, ST3, ST4, ST5, ST6, ST7, ST8, Untyped), __DB>>
             and 23 others
     = note: required because of the requirements on the impl of `LoadQuery<'_, _, Entity>` for `entities::table`
note: required by a bound in `diesel::RunQueryDsl::load`
    --> /home/username/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-2.0.2/src/query_dsl/mod.rs:1499:15
     |
1499 |         Self: LoadQuery<'query, Conn, U>,
     |               ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::RunQueryDsl::load`

According to Diesel's documentation (specifically this page), deriving Queryable should be enough to run functions like load on entities.

From the error message, I gather that Diesel's FromSqlRow trait is not being implemented, but whenever I try to include that in the derive (and remove the conflicting Queryable derivation), I am only met by another, very similar, set of errors on compilation. A long walk through Diesel's available documentation hasn't helped me understand what is going on or how I might fix it as the typical documentation seems to be "derive it," and a google search is similarly unfruitful. Am I supposed to be implementing any traits by hand here? If so, what might that look like (I cannot find any examples)? Or is there something else I'm missing? More importantly, can anyone explain exactly what this error message is trying to communicate?

EDIT 1: Provide the relevant schema code; had provided it for a different model accidentally.

EDIT 2: Below update with clarified order of properties

Even when I change models.rs to the below to explicitly declare the order in which properties are selected, a similar error (see edit 4) still appears:

use uuid::Uuid;
use diesel::prelude::*;

use crate::schema::entities;

type DB = diesel::pg::Pg;

#[derive(Queryable, PartialEq, Debug)]
#[diesel(table_name = entities)]
pub struct Entity {
    pub id: u16,
    pub uuid: Uuid,
    pub username: Option<String>
}

impl Entity {
    pub fn get_all(connection: &mut PgConnection) -> QueryResult<Vec<Entity>> {
        entities::dsl::entities
            .select((entities::id, entities::uuid, entities::username))
            .load::<Entity>(connection)
    }
}

I have included the proper feature flags in Cargo.toml.

EDIT 3: Verified that versions are compatible; see changelog for Diesel

EDIT 4: new error that is being thrown on compilation

error[E0277]: the trait bound `(u16, uuid::Uuid, Option<String>): FromStaticSqlRow<(Integer, diesel::sql_types::Uuid, diesel::sql_types::Nullable<diesel::sql_types::Text>), Pg>` is not satisfied
    --> src/models.rs:22:14
     |
22   |             .load(connection)
     |              ^^^^ the trait `FromStaticSqlRow<(Integer, diesel::sql_types::Uuid, diesel::sql_types::Nullable<diesel::sql_types::Text>), Pg>` is not implemented for `(u16, uuid::Uuid, Option<String>)`
     |
     = help: the following other types implement trait `FromStaticSqlRow<ST, DB>`:
               <(T0,) as FromStaticSqlRow<(ST0,), __DB>>
               <(T1, T0) as FromStaticSqlRow<(ST1, ST0), __DB>>
               <(T1, T2, T0) as FromStaticSqlRow<(ST1, ST2, ST0), __DB>>
               <(T1, T2, T3, T0) as FromStaticSqlRow<(ST1, ST2, ST3, ST0), __DB>>
               <(T1, T2, T3, T4, T0) as FromStaticSqlRow<(ST1, ST2, ST3, ST4, ST0), __DB>>
               <(T1, T2, T3, T4, T5, T0) as FromStaticSqlRow<(ST1, ST2, ST3, ST4, ST5, ST0), __DB>>
               <(T1, T2, T3, T4, T5, T6, T0) as FromStaticSqlRow<(ST1, ST2, ST3, ST4, ST5, ST6, ST0), __DB>>
               <(T1, T2, T3, T4, T5, T6, T7, T0) as FromStaticSqlRow<(ST1, ST2, ST3, ST4, ST5, ST6, ST7, ST0), __DB>>
             and 24 others

Upvotes: 6

Views: 1453

Answers (1)

weiznich
weiznich

Reputation: 3435

The linked documentation already gives a pretty strong hint what's wrong in your case:

Note: When this trait is derived, it will assume that all fields on your struct matches all fields in the query, including the order and count. This means that field order is significant if you are using #[derive(Queryable)]. Field name has no effect.

In your case the problem is a mismatch between the type of the id field and the corresponding database type. That's u16 on rust side vs Int4 on database side. According to the diesel documentation of Integer (Int4 is a type alias for this type), these two types are not compatible. You need to use a i32 in that position. They are not considered compatible as not all possible database values of a Int4 field fit into a u16

Upvotes: 5

Related Questions