如果我有一个简单的结构,其中一个属性包含一个简单的枚举,那么如何最好地在rusqlite数据库中存储这个结构的示例及其枚举呢?类似于:
use rusqlite::{params, Connection, Result};
enum Sex{
Unknown,
Male,
Female,
}
struct Person{
name: String,
sex: Sex
}
fn main() -> Result<()> {
let conn = Connection::open_in_memory()?;
conn.execute(
"CREATE TABLE people(
name TEXT NOT NULL,
sex TEXT NOT NULL
)",
(), // empty list of parameters.
)?;
let person_01 = Person{
name: String::from("Adam"),
sex: Sex::Male
};
conn.execute(
"INSERT INTO people (name, sex) VALUES (?1, ?2)",
(&person_01.name, &person_01.sex),
)?;
Ok(())
}问题是sqlite只允许受限制类型的数据(NULL、整型、实值、文本),试图在这里使用文本进行枚举会产生以下错误:
error[E0277]: the trait bound `Sex: ToSql` is not satisfied
--> src/main.rs:33:9
|
31 | conn.execute(
| ------- required by a bound introduced by this call
32 | "INSERT INTO tasklist (name, sex) VALUES (?1, ?2)",
33 | (&person_01.name, &person_01.sex),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToSql` is not implemented for `Sex`这个错误是有意义的,但是实现这个错误的最好方法是什么呢?把enum投给int?我读过这里,这是“消除了值总是表示枚举的变体的保证”,我同意这一点。把绳子配起来会更好。
我尝试使用女贞来完成这项工作,它允许我将to_str & from_str添加到枚举中,允许将其添加到数据库中,如下所示:
#[derive(strum_macros::Display, strum_macros::EnumString, Debug)]
enum Sex{
Unknown,
Male,
Female,
}
...
conn.execute(
"INSERT INTO people (name, sex) VALUES (?1, ?2)",
(&person_01.name, &person_01.sex.to_string())
)?;并像这样检索到:
let mut stmt = conn.prepare("SELECT name, sex FROM people")?;
let person_itr = stmt.query_map([], |row|{
Ok(
Person{
name: row.get(0)?,
sex: Sex::from_str(String::as_str(&row.get(1)?)).unwrap(),
}
)
});但这感觉很混乱。有更好的方法吗?
我见过这里人员手动为枚举实现FromSqlRow,但是有更好(更快)的方法吗?
发布于 2022-07-21 17:36:18
正确的处理方法是直接在枚举上实现ToSql和FromSql。这将使它的使用更符合人体工程学,而且可能更有效率,因为您不必首先转换为带有分配的类型,比如String。
它还意味着对字符串的转换不会“影响”与数据库的每一次交互;转换将自动进行。因此,尽管有更多的样板,但每次您将这种类型与数据库一起使用时,它都会得到回报。
impl ToSql for Sex {
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
Ok(self.to_string().into())
}
}
impl FromSql for Sex {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str()?.parse()
.map_err(|e| FromSqlError::Other(Box::new(e)))
}
}现在,您可以在转换为Person时执行此操作。
sex: row.get(1)?,请注意,FromSqlRow是postgres客户端特有的一个特征;rusqlite没有这样的特性。如果您愿意,可以在Person上创建一个工厂方法,该方法是从一个Row构造的。那随你的便。
https://stackoverflow.com/questions/73068721
复制相似问题