In diesel 2.0.0, using rust 1.64, I'm trying to return a boxed query from a function to be used elsewhere. This is very easy if you just want to return the table as the base query:
pub fn get_queryset<'a>() -> Foo::BoxedQuery<'a, DB> {
Foo::table.into_boxed()
}
However, if I have a join and a filter, I can't seem to figure out the type.
I have diesel tables defined as:
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,
);
From this, the aforementioned query compiles fine:
pub fn get_queryset<'a>() -> Foo::BoxedQuery<'a, DB> {
Foo::table.into_boxed()
}
Next, I want to define this query:
pub fn get_queryset_with_join<'a>() -> Foo::BoxedQuery<'a, DB> {
Foo::table
.inner_join(Bar::table.on(Bar::foo_id.eq(Foo::id)))
.filter(Bar::id.eq(42))
.into_boxed()
}
Rust complains
error[E0308]: mismatched types
--> src/main.rs:54:5
|
53 | pub fn get_queryset_with_join<'a>() -> Foo::BoxedQuery<'a, DB> {
| ----------------------- expected `BoxedSelectStatement<'a, (Integer,), FromClause<Foo::table>, Pg>` because of return type
54 | / Foo::table
55 | | .inner_join(Bar::table.on(Bar::foo_id.eq(Foo::id)))
56 | | .filter(Bar::id.eq(42))
57 | | .into_boxed()
| |_____________________^ expected a tuple with 1 element, found one with 2 elements
|
= note: expected struct `BoxedSelectStatement<'a, (Integer,), FromClause<Foo::table>, _, _>`
found struct `BoxedSelectStatement<'_, ((Integer,), (Integer, Integer)), FromClause<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>>>>, _, _>`
Ok, so I need to define the BoxedSelectStatement
type explicitly:
type QuerySetJoinType<'a> = BoxedSelectStatement<
'a,
(
<Foo::table as diesel::Table>::AllColumns,
<Bar::table as diesel::Table>::AllColumns
),
FromClause<
JoinOn<
Join<
Foo::table,
Bar::table,
Inner
>,
diesel::expression::grouped::Grouped<
diesel::expression::operators::Eq<
Foo::columns::id,
Bar::columns::foo_id
>
>
>
>,
DB
>;
However, rust complains:
error[E0603]: module `grouped` is private
--> src/main.rs:43:33
|
43 | diesel::expression::grouped::Grouped<
| ^^^^^^^ private module
|
note: the module `grouped` is defined here
How can I correct the type definition? Is there a helper function that implicitly gives me access?
Complete Example:
// main.rs
use diesel::*;
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::internal::table_macro::{BoxedSelectStatement, FromClause, Join, JoinOn, Inner};
type QuerySetJoinType<'a> = BoxedSelectStatement<
'a,
(
<Foo::table as diesel::Table>::AllColumns,
<Bar::table as diesel::Table>::AllColumns
),
FromClause<
JoinOn<
Join<
Foo::table,
Bar::table,
Inner
>,
diesel::expression::grouped::Grouped<
diesel::expression::operators::Eq<
Foo::columns::id,
Bar::columns::foo_id
>
>
>
>,
DB
>;
pub fn get_queryset_with_join<'a>() -> Foo::BoxedQuery<'a, DB> {
Foo::table
.inner_join(Bar::table.on(Bar::foo_id.eq(Foo::id)))
.filter(Bar::id.eq(42))
.into_boxed()
}
fn main() {
println!("Hello, world!");
}
# Cargo.toml
[package]
name = "rust_boxed_test"
version = "0.1.0"
edition = "2021"
[dependencies]
diesel = { version = "2.0.0", features = ["postgres"] }
FYI, I do know that use diesel::internal::*
is an internal interface... but I want to return a non-trivial boxed query from a function.
So, apparently, you're not supposed to use the types emitted by the compiler as they are rather complicated. What you're instead supposed to use is the helper_types
module like the following:
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
>;
These types are indeed much easier to use.
This is used like:
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()
}