具有定制包装类型的柴油

Posted

技术标签:

【中文标题】具有定制包装类型的柴油【英文标题】:Diesel with custom wrapper types 【发布时间】:2020-10-26 00:22:42 【问题描述】:

我有自定义类型,可用作 Diesel 中安全使用的其他类型的包装器:

use uuid::Uuid;

pub schema Post 
  id: PostId,
  title: String,
  body: String


pub schema PostId value: Uuid

我无法将这些自定义包装器与 Diesel 一起使用。我得到的错误信息如下:

#[derive(Insertable)]
the trait `diesel::Expression` is not implemented for `models::PostId`

我试图寻找有关转换自定义类型的示例,到目前为止,我看到的两种方法是实现 AsExpression 特征或 FromSqlToSql 特征,但是我的示例'到目前为止看到的是枚举类型,我无法推断这两种方法之间的区别是什么,除了前者似乎是一种较旧的方式,也不知道这些特征的预期实现是什么。

【问题讨论】:

不幸的是,柴油(以及我尝试过的其他生锈剂)中的自定义类型非常痛苦。我最近写了一个post 一个更简单的案例,希望它可以帮助。 很难回答您的问题,因为它不包含minimal reproducible example。我们无法分辨代码中存在哪些 crate(及其版本)、类型、特征、字段等。如果您尝试在Rust Playground 上重现您的错误,如果可能的话,这将使我们更容易为您提供帮助,否则在全新的 Cargo 项目中,然后在edit 您的问题中包含附加信息。您可以使用Rust-specific MRE tips 来减少您在此处发布的原始代码。谢谢! 感谢 Shepmaster 的编辑!我添加了一些可能解释问题的额外信息,但感谢 Weiznich 的回答,我终于解决了问题! 【参考方案1】:

您需要实现上述三个特征 + 更多特征。 AsExpression + FromSqlRow 由相应的派生实现。 FromSqlToSql 需要手动实现。

use diesel::deserialize::self, FromSql;
use diesel::pg::Pg;
use diesel::serialize::self, ToSql;
use std::io::Write;

#[derive(AsExpression, FromSqlRow)]
#[sql_type = "diesel::sql_types::Uuid"]
pub schema PostId 
    value: uuid::Uuid,


impl FromSql<diesel::sql_types::Uuid, Pg> for PostId 
    fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> 
        <uuid::Uuid as FromSql<diesel::sql_types::Uuid, Pg>>::from_sql(bytes)
            .map(|value| PostId  value )
    


impl ToSql<diesel::sql_types::Uuid, Pg> for PostId 
    fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> serialize::Result 
        <uuid::Uuid as ToSql<diesel::sql_types::Uuid, Pg>>::to_sql(&self.0, out)
    

【讨论】:

感谢您的回答@weiznich!我不得不稍微修改一下,但所有功劳都归你所有!【参考方案2】:

根据 weiznich 的回答,我想出了以下用于序列化/反序列化我的自定义包装器类型的解决方案:

use uuid::Uuid;
use super::schema::posts;
use diesel::serialize::self, IsNull, Output, ToSql;
use std::io::Write;
use diesel::deserialize::self, FromSql;
use diesel::backend::Backend;
use diesel::pg::Pg;

#[derive(Queryable, Debug)]
pub struct Post 
    pub id: PostId,
    pub body: String,
    pub title: String


#[derive(Insertable)]
#[table_name="posts"]
pub struct NewPost<'a> 
    pub id: PostId,
    pub body: &'a str,
    pub title: &'a str


#[derive(AsExpression, FromSqlRow, Debug)]
#[sql_type = "diesel::sql_types::Uuid"]
pub struct PostIdpub value: Uuid

impl<DB: Backend<RawValue=[u8]>> FromSql<diesel::sql_types::Uuid, DB> for PostId 
  fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> 
    <uuid::Uuid as FromSql<diesel::sql_types::Uuid, Pg>>::from_sql(bytes).map(|value| PostId value )
  


impl ToSql<diesel::sql_types::Uuid, Pg> for PostId 
  fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result 
    <uuid::Uuid as ToSql<diesel::sql_types::Uuid, Pg>>::to_sql(&self.value, out)
  

【讨论】:

以上是关于具有定制包装类型的柴油的主要内容,如果未能解决你的问题,请参考以下文章

包装和授权

动态添加的控件最终包装在通用类型中? [关闭]

面向对象进阶2:二次加工标准类型(包装)

如何解决 sbt 中具有不同包装 ivy 类型的依赖项?

java包装器类型

11.基本包装类型