【问题标题】:implement Diesel's Insertable实施 Diesel 的可插入
【发布时间】:2020-11-27 22:54:14
【问题描述】:

我正在构建一个由 Rust 的 Diesel ORM 支持的(喘气的)博客。我希望帖子的 URL 包含其标题的“slug”。因此,帖子应该可以通过 slug 查询。因此,我希望使用 slugify crate 从标题生成 slug,然后将 slug 存储在数据库中帖子表的相应列中。

因为帖子也会有一个由数据库生成的数字 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)}
    }
}

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

尝试手动实现Insertable 是完全错误的方法吗?还是在这样做时我错过了一些非常容易的东西?看起来这种事情在经济上应该是可行的。

【问题讨论】:

    标签: rust insert rust-diesel


    【解决方案1】:

    这里可能最好的方法是不要有一个独特的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(())
    }
    
    

    【讨论】:

      猜你喜欢
      • 2018-05-17
      • 2023-04-04
      • 2021-10-31
      • 1970-01-01
      • 1970-01-01
      • 2016-11-05
      • 2011-03-20
      • 2019-04-18
      • 2020-02-28
      相关资源
      最近更新 更多