I am trying to create a simple Rust CRUD app, using Diesel and a repository pattern. My goal is to make the read/write methods generic, even if I know it might impact the code readability.
Here is my Base repository struct
pub struct BasePgRepository<'a, T, M> {
pub connection: Connection<Ccr>,
pub _lifetime_phantom: PhantomData<&'a String>,
pub _model_phantom: PhantomData<M>,
pub _table_phantom: PhantomData<T>,
}
And here is the implementation of a get_one method, which gets an entity based on its ID.
pub async fn get_one(&mut self, example_id: &str) -> Result<M, RepositoryError<'a>> {
let get_one_result = M::table().find(example_id).first::<M>(&mut self.connection).await;
if let Err(get_one_error) = get_one_result {
match get_one_error {
diesel::result::Error::NotFound => Err(RepositoryError {
error_type: RepositoryErrorType::NotFound,
message: None,
diesel_error: Some(get_one_error)
}),
_ => Err(RepositoryError {
error_type: RepositoryErrorType::Unknown,
message: Some("An unknow error occurred"),
diesel_error: Some(get_one_error)
})
}
} else if let Ok(example) = get_one_result {
Ok(example)
} else {
Err(RepositoryError {
error_type: RepositoryErrorType::Unknown,
message: Some("An unknow error occurred"),
diesel_error: None
})
}
}
The rust compiler throws an error when invoking the first() method, with the following diagnostic:
error[E0277]: the trait bound `<T as FindDsl<&'a str>>::Output: Table` is not satisfied
--> src/repository/example_pg_repository.rs:39:58
|
39 | let get_one_result = M::table().find(example_id).first::<M>(&mut self.connection).await;
| ^^^^^ the trait `Table` is not implemented for `<T as FindDsl<&'a str>>::Output`
|
= note: required for `<T as FindDsl<&'a str>>::Output` to implement `LimitDsl`
help: consider further restricting the associated type
|
38 | pub async fn get_one(&mut self, example_id: &str) -> Result<M, RepositoryError<'a>> where <T as FindDsl<&'a str>>::Output: Table {
| ++++++++++++++++++++++++++++++++++++++++++++
However, if I add this bound to my method: where <T as FindDsl<&'a str>>::Output: Table, then the diagnostic becomes:
error[E0277]: the trait bound `<<T as FindDsl<&'a str>>::Output as AsQuery>::Query: diesel::Table` is not satisfied
--> src/repository/example_pg_repository.rs:39:58
|
39 | let get_one_result = M::table().find(example_id).first::<M>(&mut self.connection).await;
| ^^^^^ the trait `diesel::Table` is not implemented for `<<T as FindDsl<&'a str>>::Output as AsQuery>::Query`
|
= note: required for `<<T as FindDsl<&'a str>>::Output as AsQuery>::Query` to implement `LimitDsl`
help: consider further restricting the associated type
|
38 | pub async fn get_one(&mut self, example_id: &str) -> Result<M, RepositoryError<'a>> where <T as FindDsl<&'a str>>::Output: Table, <<T as FindDsl<&'a str>>::Output as AsQuery>::Query: diesel::Table {
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
And it goes on. Each time I add a bound, I have to add another encapsulating the previous one.
=> What is the right approach to get all the required bounds ? I thought I just had to examine the bounds required by the object and the method I call.