Reputation: 1
Im trying to implement a generic repository for any model i have. The problem im facing now as i understand lies in trait bounds for struct which are derived with Queryable (DBSchema), Insertable (InsertDBSchema) and AsChangeset (UpdateDBSchema)
Here is the code of traits
pub trait DieselCrudMeta: Send + Sync {
type Schema: Send;
type CreateSchema: Send;
type UpdateSchema: Send;
type Filter: Send;
type Error: Send;
type DBSchema: Send + Queryable<Self::SqlType, Pg> + From<Self::Schema> + Into<Self::Schema>;
type InsertDBSchema: Insertable<Self::Table> + From<Self::CreateSchema> + Send;
type UpdateDBSchema: From<Self::UpdateSchema> + Send;
// type Table: diesel::Table + BoxedDsl<'static, Pg, Output=BoxedSelectStatement<'static, Self::SqlType, FromClause<Self::Table>, Pg>>;
type Table: diesel::Table;
type SqlType: SqlTypeOrSelectable + Send;
fn table() -> Self::Table;
// fn to_db_insert_schema(schema: Self::CreateSchema) -> Self::InsertDBSchema;
// fn apply_filters(
// query: BoxedSelectStatement<'static, Self::SqlType, FromClause<Self::Table>, Pg>,
// filters: Vec<Self::Filter>
// ) -> BoxedSelectStatement<'static, Self::SqlType, FromClause<Self::Table>, Pg>;
}
#[async_trait]
pub trait Repository: Send + Sync {
type Schema;
type CreateSchema;
type UpdateSchema;
type Error;
type Filter;
async fn create(&self, schema: Self::CreateSchema) -> Result<Self::Schema, Self::Error>;
async fn get(&self, id: i32) -> Result<Self::Schema, Self::Error>;
async fn get_one(&self, filters: Vec<Self::Filter>) -> Result<Self::Schema, Self::Error>;
async fn get_many(&self, filters: Vec<Self::Filter>, page: Option<u32>, limit: Option<u32>) -> Result<Vec<Self::Schema>, Self::Error>;
async fn count(&self, filters: Vec<Self::Filter>) -> Result<i64, Self::Error>;
async fn update(
&self,
id: i32,
schema: Self::UpdateSchema,
) -> Result<Self::Schema, Self::Error>;
async fn delete(&self, id: i32) -> Result<(), Self::Error>;
}
here is the code of my attempt to implement it
#[async_trait]
impl<T: DieselCrudMeta> Repository for DieselRepository<T> {
type Schema = T::Schema;
type CreateSchema = T::CreateSchema;
type UpdateSchema = T::UpdateSchema;
type Error = T::Error;
type Filter = T::Filter;
async fn create(&self, schema: Self::CreateSchema) -> Result<Self::Schema, Self::Error> {
let insert = T::InsertDBSchema::from(schema);
// let insert = T::to_db_insert_schema(schema);
let pool = self.pool.clone();
let result = run(move || {
let mut conn = pool.get().unwrap();
// insert
diesel::insert_into(T::table())
.values(insert)
.get_result::<T::DBSchema>(&mut conn)
})
.await
.unwrap();
Ok(result.into())
}
async fn get(&self, id: i32) -> Result<Self::Schema, Self::Error> {
todo!()
}
async fn get_one(&self, filters: Vec<Self::Filter>) -> Result<Self::Schema, Self::Error> {
todo!()
}
async fn get_many(&self, filters: Vec<Self::Filter>, page: Option<u32>, limit: Option<u32>) -> Result<Vec<Self::Schema>, Self::Error> {
todo!()
}
async fn count(&self, filters: Vec<Self::Filter>) -> Result<i64, Self::Error> {
todo!()
}
async fn update(&self, id: i32, schema: Self::UpdateSchema) -> Result<Self::Schema, Self::Error> {
todo!()
}
async fn delete(&self, id: i32) -> Result<(), Self::Error> {
todo!()
}
}
First problem i encounetered wath tied to trait evaluating overflow, but it was solved by removing & before insert variable in .values() call. But i dont fully understand why it happened and will appreciate solutions.
But now even with first problem "fixed" whatever i try (i tried a lot of combiantions of bounds etc.) I encounter one final problem which looks like that
error[E0277]: the trait bound `InsertStatement<<T as DieselCrudMeta>::Table, <<T as DieselCrudMeta>::InsertDBSchema as diesel::Insertable<<T as DieselCrudMeta>::Table>>::Values>: LoadQuery<'_, _, <T as DieselCrudMeta>::DBSchema>` is not satisfied
--> src/infrastructure/database/repositories/mod.rs:97:44
|
97 | .get_result::<T::DBSchema>(&mut conn)
| ---------- ^^^^^^^^^ the trait `AsQuery` is not implemented for `InsertStatement<<T as DieselCrudMeta>::Table, <<T as DieselCrudMeta>::InsertDBSchema as diesel::Insertable<<T as DieselCrudMeta>::Table>>::Values>`
| |
| required by a bound introduced by this call
|
= note: required for `InsertStatement<<T as DieselCrudMeta>::Table, <<T as DieselCrudMeta>::InsertDBSchema as diesel::Insertable<<T as DieselCrudMeta>::Table>>::Values>` to implement `LoadQuery<'_, _, <T as DieselCrudMeta>::DBSchema>`
note: required by a bound in `get_result`
--> /Users/tony/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/diesel-2.2.7/src/query_dsl/mod.rs:1722:15
|
1720 | fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult<U>
| ---------- required by a bound in this associated function
1721 | where
1722 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_result`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
80 | impl<T: DieselCrudMeta> Repository for DieselRepository<T> where InsertStatement<<T as DieselCrudMeta>::Table, <<T as DieselCrudMeta>::InsertDBSchema as diesel::Insertable<<T as DieselCrudMeta>::Table>>::Values>: AsQuery {
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
which when attempted to fix like compiler suggests transforms into next one
error[E0277]: the trait bound `Pg: QueryMetadata<<InsertStatement<<T as DieselCrudMeta>::Table, <<T as DieselCrudMeta>::InsertDBSchema as diesel::Insertable<<T as DieselCrudMeta>::Table>>::Values> as AsQuery>::SqlType>` is not satisfied
--> src/infrastructure/database/repositories/mod.rs:97:44
|
97 | .get_result::<T::DBSchema>(&mut conn)
| ---------- ^^^^^^^^^ the trait `HasSqlType<<InsertStatement<<T as DieselCrudMeta>::Table, <<T as DieselCrudMeta>::InsertDBSchema as diesel::Insertable<<T as DieselCrudMeta>::Table>>::Values> as AsQuery>::SqlType>` is not implemented for `Pg`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `HasSqlType<ST>`:
`Pg` implements `HasSqlType<BigInt>`
`Pg` implements `HasSqlType<CChar>`
`Pg` implements `HasSqlType<Cidr>`
`Pg` implements `HasSqlType<Citext>`
`Pg` implements `HasSqlType<Inet>`
`Pg` implements `HasSqlType<MacAddr>`
`Pg` implements `HasSqlType<Money>`
`Pg` implements `HasSqlType<Oid>`
and 24 others
= note: required for `Pg` to implement `QueryMetadata<<InsertStatement<<T as DieselCrudMeta>::Table, <<T as DieselCrudMeta>::InsertDBSchema as diesel::Insertable<<T as DieselCrudMeta>::Table>>::Values> as AsQuery>::SqlType>`
= note: required for `InsertStatement<<T as DieselCrudMeta>::Table, <<T as DieselCrudMeta>::InsertDBSchema as diesel::Insertable<<T as DieselCrudMeta>::Table>>::Values>` to implement `LoadQuery<'_, PooledConnection<ConnectionManager<PgConnection>>, <T as DieselCrudMeta>::DBSchema>`
note: required by a bound in `get_result`
--> /Users/tony/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/diesel-2.2.7/src/query_dsl/mod.rs:1722:15
|
1720 | fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult<U>
| ---------- required by a bound in this associated function
1721 | where
1722 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_result`
maybe someone tried to implement something like this on trait level
Already seen this answer https://stackoverflow.com/a/79469407
Any help will be appreciated!
Generic repository in rust with diesel
Upvotes: -1
Views: 37