I have two tables which I want to join, filter, and select only specific columns in 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,))
Here is a repo with a repro (see comments in the code).
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!
.
The following thing is compilable:
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,))
}
While the following (no joinable
even though I have explicit .on()
) causes compilation error:
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!.
According to the documentation diesel::dsl::InnerJoin
is defined as following:
type InnerJoin<Source, Rhs> = <Source as JoinWithImplicitOnClause<Rhs, Inner>>::Output;
This and the statement
Represents the return type of .inner_join(rhs)
indicates that this type is designed to be used with inner_join
statements without explicit on
clauses.
Now this opens the question how to correctly specify the return type, as diesel 1.4 does not export a corresponding type via diesel::dsl
. The documentation of diesels master branch indicates that a corresponding type exists there, but the relevant types form the type definition are not exposed on the 1.4 release as part of the public API. This indicates that it is currently not possible to name this type using an existing diesel release.