【问题标题】:Writing Diesel CRUD operations for generic types为泛型类型编写 Diesel CRUD 操作
【发布时间】:2020-02-23 14:33:20
【问题描述】:

我正在尝试编写一个 Rust crate,它在使用 Diesel 创建简单的 CRUD 操作时从用户那里删除一些样板代码

例如,如果您有一台像这样的柴油机Insertable

#[derive(Insertable)]
#[table_name = "users"]
pub struct UserCreate<'a> {
    pub email: String,
    pub hash: &'a [u8],
    pub first_name: Option<String>,
    pub family_name: Option<String>,
}

我希望 crate 用户只写create&lt;UserCreate&gt;(model, pool),将结构字段插入数据库行。

为此,我编写了以下函数签名(例如简化):

fn create<'a, C: 'a>(model: C, pool: DBPool)
where
    C: diesel::Identifiable,
    &'a C: diesel::Insertable<C::Table>,
{
    let conn = pool.get().unwrap();
    diesel::insert_into(C::table())
        .values(&model)
        .execute(&conn);
}

问题是编译器在.execute(&amp;conn) 抱怨C&amp;C 缺少一些特征边界,我不太确定如何将它们放在where 子句中,可能还有一个更简单的我不知道这样做的方式。非常欢迎任何提示!

编译器输出:

error[E0277]: the trait bound `<<C as diesel::associations::HasTable>::Table as diesel::QuerySource>::FromClause: diesel::query_builder::QueryFragment<_>` is not satisfied
  --> database/src/users/models.rs:46:10
   |
46 |         .execute(&conn);
   |          ^^^^^^^ the trait `diesel::query_builder::QueryFragment<_>` is not implemented for `<<C as diesel::associations::HasTable>::Table as diesel::QuerySource>::FromClause`
   |
   = help: the following implementations were found:
             <&'a T as diesel::query_builder::QueryFragment<DB>>
   = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::query_builder::InsertStatement<<C as diesel::associations::HasTable>::Table, <&C as diesel::Insertable<<C as diesel::associations::HasTable>::Table>>::Values>`
   = note: required because of the requirements on the impl of `diesel::query_dsl::load_dsl::ExecuteDsl<_, _>` for `diesel::query_builder::InsertStatement<<C as diesel::associations::HasTable>::Table, <&C as diesel::Insertable<<C as diesel::associations::HasTable>::Table>>::Values>`

error[E0277]: the trait bound `<&C as diesel::Insertable<<C as diesel::associations::HasTable>::Table>>::Values: diesel::query_builder::QueryFragment<_>` is not satisfied
  --> database/src/users/models.rs:46:10
   |
46 |         .execute(&conn);
   |          ^^^^^^^ the trait `diesel::query_builder::QueryFragment<_>` is not implemented for `<&C as diesel::Insertable<<C as diesel::associations::HasTable>::Table>>::Values`
   |
   = help: the following implementations were found:
             <&'a T as diesel::query_builder::QueryFragment<DB>>
   = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::query_builder::InsertStatement<<C as diesel::associations::HasTable>::Table, <&C as diesel::Insertable<<C as diesel::associations::HasTable>::Table>>::Values>`
   = note: required because of the requirements on the impl of `diesel::query_dsl::load_dsl::ExecuteDsl<_, _>` for `diesel::query_builder::InsertStatement<<C as diesel::associations::HasTable>::Table, <&C as diesel::Insertable<<C as diesel::associations::HasTable>::Table>>::Values>`

error[E0277]: the trait bound `<&C as diesel::Insertable<<C as diesel::associations::HasTable>::Table>>::Values: diesel::insertable::CanInsertInSingleQuery<_>` is not satisfied
  --> database/src/users/models.rs:46:10
   |
46 |         .execute(&conn);
   |          ^^^^^^^ the trait `diesel::insertable::CanInsertInSingleQuery<_>` is not implemented for `<&C as diesel::Insertable<<C as diesel::associations::HasTable>::Table>>::Values`
   |
   = help: the following implementations were found:
             <&'a T as diesel::insertable::CanInsertInSingleQuery<DB>>
   = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::query_builder::InsertStatement<<C as diesel::associations::HasTable>::Table, <&C as diesel::Insertable<<C as diesel::associations::HasTable>::Table>>::Values>`
   = note: required because of the requirements on the impl of `diesel::query_dsl::load_dsl::ExecuteDsl<_, _>` for `diesel::query_builder::InsertStatement<<C as diesel::associations::HasTable>::Table, <&C as diesel::Insertable<<C as diesel::associations::HasTable>::Table>>::Values>`

error: aborting due to 3 previous errors

非常感谢!

【问题讨论】:

    标签: rust crud rust-diesel


    【解决方案1】:

    我终于通过定义以下 trait bounds 解决了!

    fn create<C, T>(model: C, pool: DBPool)
    where
        T: diesel::associations::HasTable,
        <T::Table as diesel::QuerySource>::FromClause:
            diesel::query_builder::QueryFragment<diesel::pg::Pg>,
        C: diesel::Insertable<T::Table>,
        C::Values: diesel::insertable::CanInsertInSingleQuery<diesel::pg::Pg>
            + diesel::query_builder::QueryFragment<diesel::pg::Pg>,
    {
        let conn = pool.get().unwrap();
    
        diesel::insert_into(T::table())
            .values(model)
            .execute(&conn);
    }
    
    create::<UserCreate, users::table>(user, pool);
    

    基本上,TableInsertable 需要一对额外的界限。如果可以直接从Insertable 获取表就好了,以避免在函数定义中使用其他类型,但我可以使用它:)

    【讨论】:

    • 嗨,如果我想用get_result 替换excute,我需要实现什么特征。谢谢@codearm
    【解决方案2】:

    接受的答案是正确的,但可以通过使用更高的界限来减少冗长

    use diesel::query_builder::{InsertStatement};
    use diesel::query_dsl::methods::{ExecuteDsl};
    
    pub fn insert_into_table<T, M>(conn: &Pgconnection, table: T, records: M)
    where
        T: Table,
        M: diesel::Insertable<T>,
        InsertStatement<T, M::Values>: ExecuteDsl<PgConnection>,
    {
        diesel::insert_into(table)
            .values(records)
            .execute(conn);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-15
      • 2021-12-06
      相关资源
      最近更新 更多