Attempt to create generic queries with Diesel - "first" method with incomplete trait bounds

46 Views Asked by At

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.

0

There are 0 best solutions below