Diesel-Rust(Postgres)通用过滤功能的泛型函数实现疑问
通用Diesel过滤逻辑实现方案
泛型函数方案
利用Diesel提供的trait约束泛型参数,实现类型安全的通用过滤逻辑,消除重复代码。
泛型约束说明
需要为列类型T和值类型V绑定Diesel核心trait:
T需实现ExpressionMethods(提供eq/lt等过滤方法)和AppearsOnTable(确保列属于目标表)V需能被转换为列对应的SQL类型(AsExpression<T::SqlType>)- 每个过滤操作对应的表达式需返回布尔类型的SQL表达式,且能应用在目标表上
通用过滤函数实现
use diesel::{ExpressionMethods, QueryDsl, AppearsOnTable}; use schema::entities; pub fn query_filter<T, V>( op: FilterOp, query: &mut entities::BoxedQuery<diesel::pg::Pg>, column: T, value: V, ) where T: ExpressionMethods + AppearsOnTable<entities::table> + Clone, V: diesel::AsExpression<T::SqlType>, <T as ExpressionMethods>::Eq<V>: diesel::Expression<SqlType = diesel::sql_types::Bool> + AppearsOnTable<entities::table>, <T as ExpressionMethods>::Ne<V>: diesel::Expression<SqlType = diesel::sql_types::Bool> + AppearsOnTable<entities::table>, <T as ExpressionMethods>::Lt<V>: diesel::Expression<SqlType = diesel::sql_types::Bool> + AppearsOnTable<entities::table>, <T as ExpressionMethods>::Le<V>: diesel::Expression<SqlType = diesel::sql_types::Bool> + AppearsOnTable<entities::table>, <T as ExpressionMethods>::Gt<V>: diesel::Expression<SqlType = diesel::sql_types::Bool> + AppearsOnTable<entities::table>, <T as ExpressionMethods>::Ge<V>: diesel::Expression<SqlType = diesel::sql_types::Bool> + AppearsOnTable<entities::table>, <T as ExpressionMethods>::Like<V>: diesel::Expression<SqlType = diesel::sql_types::Bool> + AppearsOnTable<entities::table>, { match op { FilterOp::NONE => {} FilterOp::EQUAL => *query = query.filter(column.eq(value)), FilterOp::NOT_EQUAL => *query = query.filter(column.ne(value)), FilterOp::LESS_THAN => *query = query.filter(column.lt(value)), FilterOp::LESS_THAN_EQUAL => *query = query.filter(column.le(value)), FilterOp::GREATER_THAN => *query = query.filter(column.gt(value)), FilterOp::GREATER_THAN_EQUAL => *query = query.filter(column.ge(value)), FilterOp::CONTAINS | FilterOp::STRING_LIKE => { let like_val = format!("%{}%", value); *query = query.filter(column.like(like_val)); } } }
调用示例
// 处理Text类型列source_id query_filter(op, &mut query, &schema::entities::dsl::source_id, filter_value.string_value()); // 处理Uuid类型列uid let uuid_val = Uuid::parse_str(filter_value.string_value()).unwrap(); query_filter(op, &mut query, &schema::entities::dsl::uid, uuid_val);
宏方案(更灵活)
如果泛型约束过于繁琐,或者需要扩展特殊类型的处理逻辑,宏是更简洁的选择,直接展开为针对特定列的代码。
过滤宏定义
#[macro_export] macro_rules! apply_filter { ($query:expr, $column:ident, $op:expr, $value:expr) => { match $op { FilterOp::NONE => {} FilterOp::EQUAL => $query = $query.filter($column.eq($value)), FilterOp::NOT_EQUAL => $query = $query.filter($column.ne($value)), FilterOp::LESS_THAN => $query = $query.filter($column.lt($value)), FilterOp::LESS_THAN_EQUAL => $query = $query.filter($column.le($value)), FilterOp::GREATER_THAN => $query = $query.filter($column.gt($value)), FilterOp::GREATER_THAN_EQUAL => $query = $query.filter($column.ge($value)), FilterOp::CONTAINS | FilterOp::STRING_LIKE => { let like_val = format!("%{}%", $value); $query = $query.filter($column.like(like_val)); } } }; }
调用示例
match filter_column.as_str() { "source_id" => apply_filter!(query, schema::entities::dsl::source_id, op, filter_value.string_value()), "uid" => { let uuid_val = Uuid::parse_str(filter_value.string_value()).unwrap(); apply_filter!(query, schema::entities::dsl::uid, op, uuid_val); } // 其他列分支 _ => {} }
额外优化建议
- 针对
CONTAINS/STRING_LIKE,可根据列类型调整逻辑:文本类型用ILIKE实现大小写不敏感匹配,数组类型用Postgres的@>操作符 - 为
FilterValue实现类型转换方法(如to_uuid(&self) -> Result<Uuid, ParseError>),避免调用处重复解析逻辑 - 结合
Option处理可选过滤条件,用filter(option_filter)链式调用简化代码
内容的提问来源于stack exchange,提问作者TazMainiac
相关产品推荐
相关产品推荐

