Diesel泛型操作时如何访问表的具体列以省去表和表达式参数
实现方案
你可以通过定义专用特征标记所有包含time列的表,再通过特征约束限制函数的适用范围即可,完整实现如下:
1. 定义通用特征标记带time列的表
use diesel::associations::HasTable; use diesel::ExpressionMethods; use diesel::SortableExpression; // 原有记录时间特征保持不变 pub trait Time { fn time(&self) -> i32; } /// 专门标记所有包含time列的表 pub trait HasTimeColumn: HasTable { /// 对应表的time列类型 type TimeColumn: ExpressionMethods + SortableExpression<Self::Table>; /// 获取time列实例 fn time_col() -> Self::TimeColumn; }
2. 给业务表实现该特征
以你示例中的cat表为例:
use crate::schema::cat; impl HasTimeColumn for cat::dsl::cat { type TimeColumn = cat::dsl::time; fn time_col() -> Self::TimeColumn { cat::dsl::time } }
后续新增其他带time列的表,只需要对应实现一遍HasTimeColumn特征即可。
3. 编写通用查询函数
use diesel::expression::operators::Desc; use diesel::helper_types::{Limit, Order}; use diesel::query_dsl::methods::{LimitDsl, OrderDsl}; use diesel::query_dsl::LoadQuery; use diesel::SqliteConnection; use diesel::RunQueryDsl; use diesel::OptionalExtension; pub fn get_most_recent_entry<Tbl, Record>( conn: &SqliteConnection, ) -> Result<i32, String> where Tbl: HasTimeColumn, Tbl::Table: OrderDsl<Desc<Tbl::TimeColumn>>, Order<Tbl::Table, Desc<Tbl::TimeColumn>>: LoadQuery<SqliteConnection, Record> + LimitDsl, Limit<Order<Tbl::Table, Desc<Tbl::TimeColumn>>>: LoadQuery<SqliteConnection, Record>, Record: Time, { Tbl::table() .order(Tbl::time_col().desc()) .first(conn) .optional() .map(|x| x.map_or(0, |x| x.time())) .map_err(|e| format!("Error here! {:?}", e)) }
4. 调用方式和你预期完全一致
#[derive(Queryable)] pub struct Cat { id: u32, name: String, time: i32 } impl Time for Cat { fn time(&self) -> i32 { self.time } } fn main() -> Result<(), String> { let conn = pool.get()?; let latest_time = get_most_recent_entry::<cat::dsl::cat, Cat>(&conn)?; println!("最新时间: {}", latest_time); Ok(()) }
内容的提问来源于stack exchange,提问作者the-notable
相关产品推荐
相关产品推荐

