在Diesel+Sqlite环境下,如何通过FromSql trait实现Rust枚举的字节转换?
问题:Diesel+Sqlite下Rust枚举与Text类型转换编译错误
我正在使用Diesel库和Sqlite数据库,尝试创建以diesel::sql_types::Text类型存储到数据库的Rust枚举,但参考示例代码后仍无法正常运行,出现编译错误。
我的代码如下:
#[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<'_, '_, '_>`
解决方法
问题根源
Diesel的SqliteValue类型API在版本迭代中发生了变化,旧版本的as_bytes()方法已被移除,需要使用read()方法来读取字节内容。
修正后的FromSql实现
use diesel::deserialize::{self, FromSql}; use diesel::sqlite::Sqlite; use diesel::sql_types::Text; use diesel::sqlite::SqliteValue; impl FromSql<Text, Sqlite> for InspectionType { fn from_sql(value: SqliteValue) -> deserialize::Result<Self> { let bytes = value.read::<&[u8]>()?; match bytes { b"RUNWAY" => Ok(InspectionType::Runway), b"PAPI" => Ok(InspectionType::Papi), _ => Err("Unrecognized InspectionType variant".into()), } } }
简化ToSql实现的可选方案
如果希望避免手动匹配枚举值和字符串,可以利用serde的序列化结果来简化实现(注意要去除serde自动添加的引号):
use diesel::serialize::{self, ToSql, Output, IsNull}; use diesel::sqlite::Sqlite; use diesel::sql_types::Text; impl ToSql<Text, Sqlite> for InspectionType { fn to_sql(&self, out: &mut Output<Sqlite>) -> serialize::Result { let serialized = serde_json::to_string(self)?; let raw_str = serialized.trim_matches('"'); out.write_all(raw_str.as_bytes())?; Ok(IsNull::No) } }
如果不需要依赖serde的重命名逻辑,也可以直接手动映射字符串:
impl ToSql<Text, Sqlite> for InspectionType { fn to_sql(&self, out: &mut Output<Sqlite>) -> serialize::Result { let value_str = match self { InspectionType::Runway => "RUNWAY", InspectionType::Papi => "PAPI", }; out.write_all(value_str.as_bytes())?; Ok(IsNull::No) } }
内容的提问来源于stack exchange,提问作者Kacper Ledwosiński
相关产品推荐
相关产品推荐

