1

I have Rust project with Diesel implemented and it generated schema.rs file which contains all of my tables:

table! {
    users (id) {
        id -> Uuid,
        name -> Varchar,
    }
}

table! {
    items (id) {
        id -> Uuid,
        name -> Varchar,
    }
}

How could I pass any table as an argument inside of my utility function? For instance,

pub trait Search {
    fn internal_get_by_id(
        diesel_table: diesel::table, // this argument should pass any diesel table
        table_id: diesel::table::id, // this argument should pass Uuid from table
        conn: &Conn,
        id: Uuid,
    ) -> Fallible<Option<Self>>
    where
        Self: Sized,
    {
        diesel_table
            .filter(table_id.eq(id))
            .first(conn.raw())
            .optional()
            .map_err(Error::from)
    }

    fn get_by_id(conn: &Conn, id: Uuid) -> Fallible<Option<Self>>
    where
        Self: Sized;
}

impl Search for User {
    fn get_by_id(conn: &Conn, id: Uuid) -> Fallible<Option<User>> {
        Self::internal_get_by_id(users::table, users::id, conn, id)
    }
}

impl Search for Item {
    fn get_by_id(conn: &Conn, id: Uuid) -> Fallible<Option<Item>> {
        Self::internal_get_by_id(items::table, items::id, conn, id)
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Pat
  • 21
  • 7
  • 1
    [Writing Diesel CRUD operations for generic types](https://stackoverflow.com/q/58589018/155423); [Generic usage of Diesel's find or filter to perform deletions](https://stackoverflow.com/q/55213466/155423); [Generic function using Diesel causes overflow](https://stackoverflow.com/q/48487871/155423); [How do I combine multiple functions using Diesel into one through abstraction?](https://stackoverflow.com/q/47874398/155423). – Shepmaster Sep 29 '20 at 13:07
  • 1
    @Shepmaster after trying for almost 5 hours, I couldn't write a working code from all the sources you gave me, I am fairly new to Rust and this `where` definitions for T are really confusing to me at the moment – Pat Sep 29 '20 at 19:27
  • I'm not sure you can pass _any_ table as a function argument - Rust explicitly doesn't support variadic functions. You could try creating an enum with variants of `schema::users` and `schema::items` and pass that instead. – jla Sep 30 '20 at 00:04

1 Answers1

3

First of all: It is generally not a good idea to write code that is generic over multiple tables/columns using Diesel in Rust, especially if you are new to the language and don't have a really good understanding on trait bounds and where clauses yet.

You need to list all trait bounds that are required to allow building this generic query so that everything can be checked at compile time. The following implementation should solve this (not tested, hopefully I did not miss a trait bound)

fn internal_get_by_id<T, C>(
    diesel_table: T, 
    table_id: C,     
    conn: &Conn,
    id: Uuid,
) -> Fallible<Option<Self>>
where
    Self: Sized,
    T: Table + FilterDsl<dsl::Eq<C, Uuid>>,
    C: Column + Expression<SqlType = diesel::sql_types::Uuid>,
    dsl::Filter<T, dsl::Eq<C, Uuid>>: LimitDsl,
    dsl::Limit<dsl::Filter<T, dsl::Eq<C, Uuid>>>: LoadQuery<Conn, Self>,
    Self: Queryable<dsl::SqlTypeOf<dsl::Limit<dsl::Filter<T, dsl::Eq<C, Uuid>>>>, Conn::Backend>,
{
    diesel_table
        .filter(table_id.eq(id))
        .first(conn.raw())
        .optional()
        .map_err(Error::from)
}
weiznich
  • 2,910
  • 9
  • 16
  • getting `error[E0223]: ambiguous associated type` on `src/utils/utility.rs:28:13 -> Conn::Backend` – Pat Sep 30 '20 at 14:24
  • 1
    @Pat Without additional information in your post that's not possible to address this error message. Please provide a complete minimal reproducing example using this [guide](https://stackoverflow.com/tags/rust-diesel/info) – weiznich Sep 30 '20 at 15:02