在柴油中显式加入

Explicit JOIN ON in diesel

我有两个表,我想加入、过滤,并且 select 只有 Diesel 中的特定列:

contest_users::dsl::contest_users
    .inner_join(
        contests::table.on(contest_users::contest_id.eq(contests::contest_id)),
    )
    .filter(contest_users::user_id.eq(42))
    .select((contests::columns::contest_id,))

这里有一个repo with a repro(见代码中的注释)

我找到了一些可以编译的解决方案,但我仍然想知道是否可以在不使用 joinable!.

的情况下命名此查询的类型

以下内容是可编译的:

pub fn join_and_filter() -> diesel::dsl::Filter<
    diesel::dsl::Select<
        diesel::dsl::InnerJoin<contest_users::table, contests::table>,
        (contests::columns::contest_id,),
    >,
    diesel::expression::operators::Eq<
        contest_users::columns::user_id,
        diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>,
    >,
> {
    joinable!(contest_users -> contests (contest_id));

    contest_users::dsl::contest_users
        .inner_join(
            contests::table.on(contest_users::contest_id.nullable().eq(contests::contest_id.nullable())),
        )
        .filter(contest_users::user_id.eq(42))
        .select((contests::columns::contest_id,))
}

虽然以下(没有 joinable 即使我有显式 .on())导致编译错误:

pub fn join_and_filter() -> diesel::dsl::Filter<
    diesel::dsl::Select<
        diesel::dsl::InnerJoin<contest_users::table, contests::table>,
        (contests::columns::contest_id,),
    >,
    diesel::expression::operators::Eq<
        contest_users::columns::user_id,
        diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>,
    >,
> {
    contest_users::dsl::contest_users
        .inner_join(
            contests::table.on(contest_users::contest_id.eq(contests::contest_id))
        )
        .filter(contest_users::user_id.eq(42))
        .select((contests::columns::contest_id,))
}
error[E0277]: the trait bound `contest_users::table: JoinTo<contests::table>` is not satisfied
  --> src/main.rs:69:1
   |
69 | / pub fn join_and_filter() -> diesel::dsl::Filter<
70 | |     diesel::dsl::Select<
71 | |         diesel::dsl::InnerJoin<contest_users::table, contests::table>,
72 | |         (contests::columns::contest_id,),
...  |
84 | |         .select((contests::columns::contest_id,))
85 | | }
   | |_^ the trait `JoinTo<contests::table>` is not implemented for `contest_users::table`
   |
   = help: the following implementations were found:
             <contest_users::table as JoinTo<JoinOn<Join, On>>>
             <contest_users::table as JoinTo<diesel::query_builder::BoxedSelectStatement<'a, QS, ST, DB>>>
             <contest_users::table as JoinTo<diesel::query_builder::SelectStatement<F, S, D, W, O, L, Of, G>>>
             <contest_users::table as JoinTo<diesel::query_source::joins::Join<Left, Right, Kind>>>
   = note: required because of the requirements on the impl of `JoinWithImplicitOnClause<contests::table, Inner>` for `contest_users::table`

I have found a few solutions that I can make to compile, but I still wonder if I can name a type of this query without using joinable!.

根据文档 diesel::dsl::InnerJoin 定义如下:

type InnerJoin<Source, Rhs> = <Source as JoinWithImplicitOnClause<Rhs, Inner>>::Output;

这个和声明

Represents the return type of .inner_join(rhs)

表示此类型旨在与没有显式 on 子句的 inner_join 语句一起使用。

现在问题是如何正确指定 return 类型,因为柴油 1.4 不会通过 diesel::dsl 导出相应的类型。 diesles master 分支的文档表明那里存在相应的 type,但是构成类型定义的相关类型并未作为 public API 的一部分在 1.4 版本中公开。这表明目前无法使用现有柴油版本命名此类型。