在柴油塔中使用新类型

时间:2019-12-22 13:53:30

标签: rust newtype rust-diesel

我为柴油模型结构中的列使用了struct GuildId(i64);之类的新类型。目前,我正在实现以下特征:

#[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 */

但是,当我尝试在以下模型结构中使用此类型时:

#[derive(Associations, Identifiable, Queryable)]
#[belongs_to(Guild)]
struct Channel {
    guild_id: GuildId,
    // other fields
}

#[derive(Identifiable, Queryable)]
struct Guild {
    id: GuildId,
    // other fields
}

Channel仍未实现BelongingToDsl。当我尝试将其转换为特征时,它无法通过以下消息进行编译:

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`

我缺少什么特征?

1 个答案:

答案 0 :(得分:1)

该错误与BelongingToDsl无关,但与自定义新类型包装程序的不完全实现有关。

错误消息表明您缺少新包装的特征暗示:

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`

有趣的行是= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::BigInt> for '&webcord_schema::models::GuildId中的第二行。这意味着您需要至少添加一个AsExpression<_>隐式引用,以引用您的新类型包装器。

所以现在一般来说:this test case显示了一般如何实现自定义类型。您将看到,锈侧的自定义类型使用了两个自定义派生(AsExpressionFromSqlRow),它们基本上实现了您已经手动实现的特征,另外还实现了缺失的特征。另外,还需要ToSql / FromSql隐含形式来描述应如何将类型转换为sql类型或从中转换为sql类型。

总结您的类型定义可能看起来像:

#[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)
    }
}