首页 > 解决方案 > 将任何 Diesel 表作为参数传递

问题描述

我已经实现了 Diesel 的 Rust 项目,它生成了包含我所有表的 schema.rs 文件:

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

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

如何在我的实用程序函数中将任何表作为参数传递?例如,

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

标签: rustrust-diesel

解决方案


首先:在 Rust 中使用 Diesel 编写跨多个表/列的通用代码通常不是一个好主意,特别是如果您是该语言的新手并且对 trait bounds 和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, 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)
}

推荐阅读