如何使用 Diesel FromSql 特征正确地将字节转换为 Rust 枚举?

问题描述 投票:0回答:1

我正在使用 Diesel 库和 Sqlite 数据库,尝试创建 Rust 枚举,将其保存到数据库中为

diesel::sql_types::Text
,但即使使用示例代码,它也无法正常工作。

这里是示例代码。

我的代码:

#[derive(PartialEq, Eq, AsExpression, FromSqlRow, Serialize, Deserialize, Clone, Debug)]
#[diesel(sql_type = diesel::sql_types::Text)]
pub enum InspectionType {
    #[serde(rename = "RUNWAY")]
    Runway,

    #[serde(rename = "PAPI")]
    Papi,
}

impl serialize::ToSql<Text, Sqlite> for InspectionType {
    fn to_sql(&self, out: &mut serialize::Output<Sqlite>) -> serialize::Result {
        match *self {
            InspectionType::Runway => out.write_all(b"RUNWAY")?,
            InspectionType::Papi => out.write_all(b"PAPI")?,
        }

        Ok(IsNull::No)
    }
}

impl deserialize::FromSql<Text, Sqlite> for InspectionType {
    fn from_sql(bytes: SqliteValue) -> deserialize::Result<Self> {
        match bytes.as_bytes() {
            b"RUNWAY" => Ok(InspectionType::Runway),
            b"PAPI" => Ok(InspectionType::Papi),
            _ => Err("Unrecognized enum variant".into()),
        }
    }
}

编译器错误:

error[E0599]: no method named `as_bytes` found for struct `SqliteValue` in the current scope
  --> src/app_data/inspection.rs:40:21
   |
40 |         match bytes.as_bytes() {
   |                     ^^^^^^^^ method not found in `SqliteValue<'_, '_, '_>`
sqlite rust rust-diesel
1个回答
0
投票

预计为 postgresql 编写的示例不适用于 sqlite,因为这两个后端之间的许多细节有所不同。这里重要的部分是如何将绑定值传递到数据库。对于 postgresql,它们被序列化为字节缓冲区并通过网络发送,对于在二进制文件中运行的 sqlite,值只是传递到数据库。此外,不同的数据库支持不同的类型集。 Postgresql 支持一组开放的类型,这意味着您可以定义自己的类型。对于 sqlite,您只能使用一小部分封闭的类型,并且无法扩展。这意味着您需要将数据序列化为实际已经存在的类型。

这对于您的示例意味着什么?

让我们开始锁定

FromSql
的相关文档。尤其是那部分很重要:

对于 SQLite,

DB::RawValue
的实际类型是私有 API。此特征的所有实现都必须根据现有原语编写。

这意味着编译器没有指出

as_bytes()
方法。您需要在内部使用现有实现之一。在本例中,这就是 String 的那个。这将为您留下类似的实现:

impl deserialize::FromSql<Text, Sqlite> for InspectionType {
    fn from_sql(bytes: SqliteValue) -> deserialize::Result<Self> {
        let value = <String as deserialize::FromSql<Text, Sqlite>>::from_sql(bytes)?;
        match &value as &str {
            "RUNWAY" => Ok(InspectionType::Runway),
            "PAPI" => Ok(InspectionType::Papi),
            _ => Err("Unrecognized enum variant".into()),
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.