实施 Diesel 的 Insertable
implement Diesel's Insertable
我正在构建一个由 Rust 的 Diesel ORM. I would like the URL of a post to include the "slug" of its title. So, posts should be queryable by slug. Therefore I wish to generate the slug from the title using the slugify crate 支持的(gasp)博客,然后将 slug 存储在数据库中 posts table 的相应列中。
因为 posts 也将有一个由数据库生成的数字 ID,我希望将传入的 posts 解析为另一个结构,NewPost
。然后 NewPost
应该实现 Diesel 的 Insertable,以便在数据库中记录一个新的 post 足以调用生成的 insert_into
方法。但是,简单地导出Insertable
是行不通的,因为需要先生成slug属性的值。
一个选择是引入中间结构 SluggedNewPost
,并为其实现 From<NewPost>
和 Insertable
特征:
struct NewPost<'a> {
title: &'a str,
content: &'a str,
}
#[derive(Insertable)]
#[table_name="posts"]
struct SluggedNewPost<'a> {
title: &'a str,
content: &'a str,
slug: String,
}
impl <'a> From<NewPost<'a>> for SluggedNewPost<'a> {
fn from(newpost: NewPost<'a> ) -> Self {
SluggedNewPost {title: &'a newpost.title,
content: newpost.content,
slug: slugify(newpost.title)}
}
}
这适用于我的有限目的。但是直接在NewPost
上实现Insertable
方法似乎更优雅。我尝试遵循 的建议,但失败了,因为我不理解宏扩展生成的代码(例如,取消引用 values
中的 id
条目的结果是什么元组?)。
尝试手动实施 Insertable
是完全错误的方法吗?或者在这样做时我是否很容易错过一些东西?看来这种东西在经济上应该是可行的。
这里最好的方法可能是不要有明显的 SluggedNewPost
。 Diesels #[derive(Insertable)]
旨在用于您已经拥有现有结构的情况,这样您就可以将 derive
放在那里并且一切正常。对于一些额外计算的情况,比如创建密码哈希或计算你的 slug,更直接的基于元组的插入变体是首选。您甚至可以混合使用这两种变体,在这种情况下这似乎是个好主意。所以你的结果代码看起来有点像
#[derive(Insertable)]
#[table_name = "posts"]
struct NewPost<'a> {
title: &'a str,
content: &'a str,
}
fn insert_with_slug(new_post: NewPost, conn: &PgConnection) -> QueryResult<()> {
diesel::insert_into(posts::table)
.values((new_post, posts::slug.eq(slugify(new_post.title))
.execute(conn)?;
Ok(())
}
我正在构建一个由 Rust 的 Diesel ORM. I would like the URL of a post to include the "slug" of its title. So, posts should be queryable by slug. Therefore I wish to generate the slug from the title using the slugify crate 支持的(gasp)博客,然后将 slug 存储在数据库中 posts table 的相应列中。
因为 posts 也将有一个由数据库生成的数字 ID,我希望将传入的 posts 解析为另一个结构,NewPost
。然后 NewPost
应该实现 Diesel 的 Insertable,以便在数据库中记录一个新的 post 足以调用生成的 insert_into
方法。但是,简单地导出Insertable
是行不通的,因为需要先生成slug属性的值。
一个选择是引入中间结构 SluggedNewPost
,并为其实现 From<NewPost>
和 Insertable
特征:
struct NewPost<'a> {
title: &'a str,
content: &'a str,
}
#[derive(Insertable)]
#[table_name="posts"]
struct SluggedNewPost<'a> {
title: &'a str,
content: &'a str,
slug: String,
}
impl <'a> From<NewPost<'a>> for SluggedNewPost<'a> {
fn from(newpost: NewPost<'a> ) -> Self {
SluggedNewPost {title: &'a newpost.title,
content: newpost.content,
slug: slugify(newpost.title)}
}
}
这适用于我的有限目的。但是直接在NewPost
上实现Insertable
方法似乎更优雅。我尝试遵循 values
中的 id
条目的结果是什么元组?)。
尝试手动实施 Insertable
是完全错误的方法吗?或者在这样做时我是否很容易错过一些东西?看来这种东西在经济上应该是可行的。
这里最好的方法可能是不要有明显的 SluggedNewPost
。 Diesels #[derive(Insertable)]
旨在用于您已经拥有现有结构的情况,这样您就可以将 derive
放在那里并且一切正常。对于一些额外计算的情况,比如创建密码哈希或计算你的 slug,更直接的基于元组的插入变体是首选。您甚至可以混合使用这两种变体,在这种情况下这似乎是个好主意。所以你的结果代码看起来有点像
#[derive(Insertable)]
#[table_name = "posts"]
struct NewPost<'a> {
title: &'a str,
content: &'a str,
}
fn insert_with_slug(new_post: NewPost, conn: &PgConnection) -> QueryResult<()> {
diesel::insert_into(posts::table)
.values((new_post, posts::slug.eq(slugify(new_post.title))
.execute(conn)?;
Ok(())
}