You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 18:20:25