在 Diesel 中创建自定义类型包装器时出错

Error Creating Custom Type Wrappers in Diesel

我正在尝试围绕 H160 and U256 创建自定义类型,以便我可以将它们与 Diesel 一起使用。

这是我用来创建自定义类型的代码:

use diesel::deserialize::{self, FromSql};
use diesel::pg::Pg;
use diesel::serialize::{self, Output, ToSql};
use diesel::sql_types::*;
use diesel::{backend::Backend, expression::AsExpression};
use ethers::{
    prelude::{Address as EthereumAddress, U256 as Eth256, *},
};
use serde::Serialize;
use std::io;
use std::io::Write;

table! {
    ethbalances (id) {
        id -> Int4,
        account -> Varchar,
        balance -> Int4,
        last_updated -> Text,
        holder -> Bool,
    }
}

#[derive(AsExpression, FromSqlRow, Debug, Copy, Clone, Serialize)]
#[sql_type = "Varchar"]
pub struct Address {
    value: EthereumAddress,
}
// Something to do with incompatible type
// 
// 
// 
// 

impl ToSql<VarChar, Pg> for Address {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        <VarChar as ToSql<VarChar, Pg>>::to_sql(&self.value, out)
    }
}

impl<DB: Backend<RawValue = [u8]>> FromSql<Varchar, DB> for Address {
    fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> {
        <VarChar as FromSql<VarChar, Pg>>::from_sql(bytes).map(|value| Address { value })
    }
}

#[derive(AsExpression, FromSqlRow, Debug, Copy, Clone, Serialize)]
#[sql_type = "Integer"]
pub struct U256 {
    value: Eth256,
}
// Something to do with incompatible type
impl ToSql<Integer, Pg> for U256 {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        <Integer as ToSql<Integer, Pg>>::to_sql(&self.value, out)
    }
}

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

impl<DB: Backend<RawValue = [u8]>> FromSql<Integer, DB> for U256 {
    fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> {
        <Integer as FromSql<Integer, Pg>>::from_sql(bytes).map(|value| U256 { value })
    }
}

#[derive(Queryable, Insertable, Serialize)]
#[table_name = "ethbalances"]
pub struct ETHRioBalance {
    id: i32,
    account: Address,
    balance: U256,
    holder: bool,
}

这是生成 table! 宏的 up.sql 文件

CREATE TABLE ethbalances (
    id SERIAL PRIMARY KEY,
    account  NOT NULL,
    balance INTEGER NOT NULL,
    last_updated TEXT NOT NULL,
    holder BOOLEAN NOT NUll
  )

不幸的是,我收到以下错误

error[E0277]: the trait bound `diesel::sql_types::Text: ToSql<diesel::sql_types::Text, Pg>` is not satisfied
  --> src/schema.rs:48:9
   |
48 |         <VarChar as ToSql<VarChar, Pg>>::to_sql(&self.value, out)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToSql<diesel::sql_types::Text, Pg>` is not implemented for `diesel::sql_types::Text`

error[E0308]: mismatched types
  --> src/schema.rs:48:49
   |
48 |         <VarChar as ToSql<VarChar, Pg>>::to_sql(&self.value, out)
   |                                                 ^^^^^^^^^^^ expected struct `diesel::sql_types::Text`, found struct `H160`
   |
   = note: expected reference `&diesel::sql_types::Text`
              found reference `&H160`

error[E0277]: the trait bound `diesel::sql_types::Text: FromSql<diesel::sql_types::Text, Pg>` is not satisfied
  --> src/schema.rs:54:29
   |
54 |         <VarChar as FromSql<VarChar, Pg>>::from_sql(bytes).map(|value| Address { value })
   |                             ^^^^^^^ the trait `FromSql<diesel::sql_types::Text, Pg>` is not implemented for `diesel::sql_types::Text`

error[E0308]: mismatched types
  --> src/schema.rs:54:82
   |
54 |         <VarChar as FromSql<VarChar, Pg>>::from_sql(bytes).map(|value| Address { value })
   |                                                                                  ^^^^^ expected struct `H160`, found struct `diesel::sql_types::Text`

error[E0277]: the trait bound `diesel::sql_types::Integer: ToSql<diesel::sql_types::Integer, Pg>` is not satisfied
  --> src/schema.rs:66:9
   |
66 |         <Integer as ToSql<Integer, Pg>>::to_sql(&self.value, out)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToSql<diesel::sql_types::Integer, Pg>` is not implemented for `diesel::sql_types::Integer`

error[E0308]: mismatched types
  --> src/schema.rs:66:49
   |
66 |         <Integer as ToSql<Integer, Pg>>::to_sql(&self.value, out)
   |                                                 ^^^^^^^^^^^ expected struct `diesel::sql_types::Integer`, found struct `ethers::prelude::U256`
   |
   = note: expected reference `&diesel::sql_types:x:Integer`
              found reference `&ethers::prelude::U256`

error[E0277]: the trait bound `diesel::sql_types::Integer: FromSql<diesel::sql_types::Integer, Pg>` is not satisfied
  --> src/schema.rs:78:29
   |
78 |         <Integer as FromSql<Integer, Pg>>::from_sql(bytes).map(|value| U256 { value })
   |                             ^^^^^^^ the trait `FromSql<diesel::sql_types::Integer, Pg>` is not implemented for `diesel::sql_types::Integer`

error[E0308]: mismatched types
  --> src/schema.rs:78:79
   |
78 |         <Integer as FromSql<Integer, Pg>>::from_sql(bytes).map(|value| U256 { value })
   |                                                                               ^^^^^ expected struct `ethers::prelude::U256`, found struct `diesel::sql_types::Integer`

对于我做错的任何指导,我将不胜感激。

为自定义类型实现 ToSqlFromSql 的最简单方法是将其简单地转换为 diesel-known 类型并推迟到其实现。这是使用 String 作为中介的 ethers::Address 的工作示例:

#[derive(AsExpression, FromSqlRow, Debug, Copy, Clone, Serialize)]
#[sql_type = "Varchar"]
pub struct Address {
    value: EthereumAddress,
}

impl ToSql<VarChar, Pg> for Address {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        <String as ToSql<VarChar, Pg>>::to_sql(&self.value.to_string(), out)
    }
}

impl<DB: Backend<RawValue = [u8]>> FromSql<Varchar, DB> for Address {
    fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> {
        <String as FromSql<VarChar, Pg>>::from_sql(bytes).map(|s| Address { value: s.parse().unwrap() })
    }
}