如何在Diesel v2中实现适配单表与关联查询的通用boxed过滤器?
如何为包含指定表的所有查询集创建通用Boxed过滤器(Diesel v2)
问题背景
需要实现一个通用的boxed过滤器,既能应用于单表Foo的查询集,也能应用于所有包含Foo表的关联查询集。当前代码在关联查询上调用filter时触发 trait 未实现的错误,尝试参数化查询集类型后,需明确泛型参数的 trait 约束。
原始代码
use diesel::*; use diesel::expression::*; use std::boxed::Box; type DB = diesel::pg::Pg; diesel::table! { Foo (id) { id -> Int4, } } diesel::table! { Bar (id) { id -> Int4, foo_id -> Int4, } } diesel::allow_tables_to_appear_in_same_query!( Foo, Bar, ); pub fn get_queryset<'a>() -> Foo::BoxedQuery<'a, DB> { Foo::table.into_boxed() } use diesel::helper_types::*; type QuerySetJoinType<'a> = IntoBoxed< 'a, Filter< InnerJoinOn<Foo::table, Bar::table, Eq<Bar::foo_id, Foo::id>>, Eq<Bar::id, diesel::expression::SqlLiteral<diesel::sql_types::Integer>> >, DB >; pub fn get_queryset_with_join<'a>() -> QuerySetJoinType<'a> { Foo::table .inner_join(Bar::table.on(Bar::foo_id.eq(Foo::id))) .filter(Bar::id.eq(42)) .into_boxed() } type FilterReturnType = Box<dyn BoxableExpression<Foo::table, DB, SqlType = diesel::sql_types::Bool>>; pub fn get_filter<'a>() -> FilterReturnType { let mut result : FilterReturnType = Box::new(Foo::id.eq(Foo::id)); result = Box::new(result.and(Foo::id.gt(42))); result } fn main() { get_queryset().filter(get_filter()); get_queryset_with_join().filter(get_filter()); }
错误信息
| 58 | get_queryset_with_join().filter(get_filter()); | ^^^^^^ the trait `AppearsOnTable<JoinOn<query_source::joins::Join<Foo::table, Bar::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<Bar::columns::foo_id, Foo::columns::id>>>>` is not implemented for `dyn diesel::BoxableExpression<Foo::table, Pg, SqlType = Bool>`
解决方案
要让过滤器兼容所有包含Foo表的查询集,需为泛型参数QS添加以下 trait 约束,并正确处理生命周期:
use diesel::query_source::QuerySource; pub fn get_filter<'a, QS>( ) -> Box<dyn BoxableExpression<QS, DB, SqlType = diesel::sql_types::Bool> + 'a> where QS: QuerySource, Foo::table: AppearsOnTable<QS>, { let mut result: Box<dyn BoxableExpression<QS, DB, SqlType = diesel::sql_types::Bool> + 'a> = Box::new(Foo::id.eq(Foo::id)); result = Box::new(result.and(Foo::id.gt(42))); result }
核心说明
Foo::table: AppearsOnTable<QS>:这是关键约束,确保查询源QS中包含Foo表,不管是单表查询还是多表关联查询都能匹配QS: QuerySource:保证QS是Diesel认可的有效查询源类型- 生命周期
'a:让boxed表达式的生命周期与查询集的生命周期绑定,避免悬垂引用问题
修改后,main函数中的两个查询集调用filter(get_filter())都能正常编译运行。
内容的提问来源于stack exchange,提问作者Ross Rogers
相关产品推荐
相关产品推荐

