传递任何柴油表作为参数

问题描述

我有一个实施了Diesel的Rust项目,它生成了包含我所有表的schema.rs文件

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

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

如何在实用程序函数内部传递任何表作为参数? 例如,

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

解决方法

首先:在Rust中使用Diesel编写在多个表/列上通用的代码通常不是一个好主意,尤其是如果您是该语言的新手并且对特征范围没有很好的了解和where子句。

您需要列出所有允许构建此通用查询所需的特征范围,以便可以在编译时检查所有内容。下面的实现应该可以解决这个问题(未经测试,希望我没有错过特征绑定)

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,Uuid>>>: LoadQuery<Conn,Self>,Self: Queryable<dsl::SqlTypeOf<dsl::Limit<dsl::Filter<T,Uuid>>>>,Conn::Backend>,{
    diesel_table
        .filter(table_id.eq(id))
        .first(conn.raw())
        .optional()
        .map_err(Error::from)
}