Reputation: 8214
I am using newtypes like struct GuildId(i64);
for the columns in my diesel model structs. Currently I am implementing these traits:
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize)]
pub struct $name(pub i64);
impl AsExpression<BigInt> for $name { /* delegate to <i64 as AsExpression<BigInt> */ */ }
impl<ST, DB: Backend> Queryable<ST, DB> for $name
where i64: FromSql<ST, DB> { /* also delegate to i64 */
However, when I try to use this type in the following model structs:
#[derive(Associations, Identifiable, Queryable)]
#[belongs_to(Guild)]
struct Channel {
guild_id: GuildId,
// other fields
}
#[derive(Identifiable, Queryable)]
struct Guild {
id: GuildId,
// other fields
}
Channel
still does not implement BelongingToDsl
. When I try to cast it to the trait, it fails to compile with the following message:
error[E0277]: the trait bound `diesel::query_builder::select_statement::SelectStatement<webcord_schema::schema::channels::table>: diesel::query_dsl::filter_dsl::FilterDsl<diesel::expression::operators::Eq<webcord_schema::schema::channels::columns::guild_id, &webcord_schema::models::GuildId>>` is not satisfied
--> src/index/guild.rs:23:32
|
23 | let channels = <models::Channel as BelongingToDsl<&models::Guild>>::belonging_to(&guild)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::query_dsl::filter_dsl::FilterDsl<diesel::expression::operators::Eq<webcord_schema::schema::channels::columns::guild_id, &webcord_schema::models::GuildId>>` is not implemented for `diesel::query_builder::select_statement::SelectStatement<webcord_schema::schema::channels::table>`
|
= help: the following implementations were found:
<diesel::query_builder::select_statement::SelectStatement<F, S, D, W, O, L, Of, G, LC> as diesel::query_dsl::filter_dsl::FilterDsl<Predicate>>
= note: required because of the requirements on the impl of `diesel::query_dsl::filter_dsl::FilterDsl<diesel::expression::operators::Eq<webcord_schema::schema::channels::columns::guild_id, &webcord_schema::models::GuildId>>` for `webcord_schema::schema::channels::table`
error[E0277]: the trait bound `webcord_schema::models::GuildId: diesel::expression::Expression` is not satisfied
--> src/index/guild.rs:23:32
|
23 | let channels = <models::Channel as BelongingToDsl<&models::Guild>>::belonging_to(&guild)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::expression::Expression` is not implemented for `webcord_schema::models::GuildId`
|
= note: required because of the requirements on the impl of `diesel::expression::Expression` for `&webcord_schema::models::GuildId`
= note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::sql_types::BigInt>` for `&webcord_schema::models::GuildId`
= note: required because of the requirements on the impl of `diesel::query_dsl::belonging_to_dsl::BelongingToDsl<&webcord_schema::models::Guild>` for `webcord_schema::models::Channel`
What traits am I missing?
Upvotes: 2
Views: 1240
Reputation: 3435
That error is not related to BelongingToDsl
, but to the incomplete implementation of the custom new type wrapper.
As the error message indicates you are missing a trait impl for your new type wrapper:
error[E0277]: the trait bound `webcord_schema::models::GuildId: diesel::expression::Expression` is not satisfied
--> src/index/guild.rs:23:32
|
23 | let channels = <models::Channel as BelongingToDsl<&models::Guild>>::belonging_to(&guild)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::expression::Expression` is not implemented for `webcord_schema::models::GuildId`
|
= note: required because of the requirements on the impl of `diesel::expression::Expression` for `&webcord_schema::models::GuildId`
= note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::sql_types::BigInt>` for `&webcord_schema::models::GuildId`
= note: required because of the requirements on the impl of `diesel::query_dsl::belonging_to_dsl::BelongingToDsl<&webcord_schema::models::Guild>` for `webcord_schema::models::Channel`
The interesting line is the second line in = note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::BigInt> for '&webcord_schema::models::GuildId
. This means you need to add at least an AsExpression<_>
impl for a reference to your new type wrapper.
So now general speaking: There is this test case showing how to implement custom types in general. You will see that the custom type on rust side uses two custom derives (AsExpression
and FromSqlRow
) that are basically implementing the traits you've already implemented manually and additionally the missing ones. Additionally a ToSql
/FromSql
impl is required to describe how the type should be translated into/from a sql type.
Summing that up your type definition should probably look like:
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, AsExpression, FromSqlRow)]
#[sql_type = "diesel::sql_types::BigInt")]
pub struct $name(pub i64);
impl<DB> ToSql<diesel::sql_types::BigInt, DB> for $name
where DB: Backend,
i64: ToSql<diesel::sql_types::BigInt, DB>,
{
fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> serialize::Result {
<i64 as ToSql<diesel::sql_types::BigInt, DB>>::to_sql(&self.0, out)
}
}
impl<DB> FromSql<diesel::sql_types::BigInt, DB> for $name
where DB: Backend,
i64: FromSql<diesel::sql_types::BigInt, DB>
{
fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> {
<i64 as FromSql<diesel::sql_types::BigInt, DB>>::from_sql(bytes).map($name)
}
}
Upvotes: 3