实现柴油的可插入

时间:2020-08-07 15:13:01

标签: rust insert rust-diesel

我正在建立一个由Rust的Diesel ORM支持的(令人讨厌的)博客。我希望帖子的网址包含其标题的“ slug”。因此,帖子应该可以被子弹查询。因此,我希望使用slugify板条箱从标题生成条块,然后将条块存储在数据库中posts表的相应列中。

由于帖子还将具有一个由数据库生成的数字ID,因此我希望将传入的帖子解析为另一个结构NewPost。然后NewPost应该实现Diesel的Insertable,以便在数据库中记录新帖子,只需调用生成的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)}
    }
}

这只能用于我的有限目的。但是,直接在Insertable上实现NewPost方法似乎更优雅。我尝试遵循this answer的建议,但失败了,因为我不理解宏扩展生成的代码(例如,取消引用id中的values条目的结果是什么元组?)。

尝试手动实现Insertable是否完全是错误的方法?还是我这样做很容易错过?看来这种事情在经济上应该是可行的。

1 个答案:

答案 0 :(得分:2)

这里最好的方法是不要使用不同的SluggedNewPost。柴油#[derive(Insertable)]用于在已有结构的情况下使用,因此您可以将derive放在这里,然后一切正常。对于某些其他计算(例如,创建密码哈希或计算您的子弹)的情况,首选基于直接元组的insert变体。您甚至可以混合使用两种变体,在这种情况下,这似乎是个好主意。因此,您生成的代码可能看起来像


#[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(())
}