问题
I am trying to write a Rust crate which removes some boilerplate code from the user when creating simple CRUD operations with Diesel
For instance, if you have a Diesel Insertable
like this one:
#[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>,
}
I want the crate user to just write create<UserCreate>(model, pool)
, to insert the struct fields into a database row.
To do so, I've written the following function signature (simplified for example):
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);
}
The issue is that the compiler complains about some missing trait bounds for C
and &C
at .execute(&conn)
and I am not quite sure how to place them in the where
clause, there may be also a simpler way of doing this which I am not aware of. Any hint is very welcome!
Compiler output:
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
Thank you very much!
回答1:
I've finally solved by defining the following 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);
Basically, you need a pair of extra bounds for the Table
and the Insertable
. It would be nice if it was possible to get the table directly from the Insertable
, to avoid using another type in the function definition, but I can work with that :)
回答2:
The accepted answer is correct but can be made less verbose by using higher bounds
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);
}
来源:https://stackoverflow.com/questions/58589018/writing-diesel-crud-operations-for-generic-types