Pass any Diesel table as an argument

1k views Asked by At

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)
    }
}
1

There are 1 answers

2
weiznich On

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)
}