为泛型编写 Diesel CRUD 操作
Writing Diesel CRUD operations for generic types
我正在尝试编写一个 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<UserCreate>(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);
}
问题是编译器抱怨 C
和 &C
在 .execute(&conn)
缺少一些特征边界,我不太确定如何将它们放在 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
非常感谢!
我终于通过定义以下特征边界解决了!
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);
基本上,Table
和 Insertable
需要一对额外的边界。如果可以直接从 Insertable
获取 table 以避免在函数定义中使用其他类型,那就太好了,但我可以使用它:)
接受的答案是正确的,但可以通过使用更高的界限来减少冗长
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);
}
我正在尝试编写一个 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<UserCreate>(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);
}
问题是编译器抱怨 C
和 &C
在 .execute(&conn)
缺少一些特征边界,我不太确定如何将它们放在 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
非常感谢!
我终于通过定义以下特征边界解决了!
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);
基本上,Table
和 Insertable
需要一对额外的边界。如果可以直接从 Insertable
获取 table 以避免在函数定义中使用其他类型,那就太好了,但我可以使用它:)
接受的答案是正确的,但可以通过使用更高的界限来减少冗长
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);
}