In diesel, I want to build up the argument for .filter()
in a programmatic way, but rust complains that into_boxed()
cannot be called due to unsatisfied trait bounds.
#[macro_use]
extern crate diesel;
mod schema;
use diesel::{QueryDsl, ExpressionMethods, JoinOnDsl, NullableExpressionMethods};
fn main() {
use crate::schema::Foo::dsl as foo_dsl;
use crate::schema::Bar::dsl as bar_dsl;
let mut query = foo_dsl::Foo
.inner_join(bar_dsl::Bar
.on(bar_dsl::foo_id.eq(foo_dsl::id.nullable())))
.select((foo_dsl::id,)).into_boxed();
let mut filter = foo_dsl::id.eq(42).into_boxed();
filter = filter.and(bar_dsl::id.eq(17));
query = query.filter(filter);
}
Complains
Error[E0599]: the method `into_boxed` exists for struct `diesel::expression::operators::Eq<Foo::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>`, but its trait bounds were not satisfied
--> src/main.rs:14:42
|
14 | let mut filter = foo_dsl::id.eq(42).into_boxed();
| ^^^^^^^^^^ method cannot be called on `diesel::expression::operators::Eq<Foo::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>` due to unsatisfied trait bounds
|
::: /home/ross/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-1.4.8/src/expression/operators.rs:343:1
|
343 | diesel_infix_operator!(Eq, " = ");
| ---------------------------------
| |
| doesn't satisfy `_: QueryDsl`
| doesn't satisfy `_: Table`
|
= note: the following trait bounds were not satisfied:
`diesel::expression::operators::Eq<Foo::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>: Table`
which is required by `diesel::expression::operators::Eq<Foo::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>: QueryDsl`
`&diesel::expression::operators::Eq<Foo::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>: Table`
which is required by `&diesel::expression::operators::Eq<Foo::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>: QueryDsl`
`&mut diesel::expression::operators::Eq<Foo::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>: Table`
which is required by `&mut diesel::expression::operators::Eq<Foo::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>: QueryDsl`
For more information about this error, try `rustc --explain E0599`.
error: could not compile `and_or` due to previous error
How can I build up a filter against a query that has a join? BoxableExpression
exists, but my combined filter
filter = filter.and(bar_dsl::id.eq(17));
is not for one single table.
This example could clearly be done without the filter
variable and done directly in the .filter()
call on the query. It is an S.S.C.C.E.
Can a boxed filter be built up somehow? With BoxableExpression
or using into_boxed()
?
schema.rs looks like:
table! {
use diesel::sql_types::*;
Bar (id) {
id -> Nullable<Integer>,
foo_id -> Nullable<Integer>,
}
}
table! {
use diesel::sql_types::*;
Foo (id) {
id -> Integer,
label -> Text,
}
}
joinable!(Bar -> Foo (foo_id));
allow_tables_to_appear_in_same_query!(
Bar,
Foo,
);
p.s.
With hints from this answer by @weiznich,
It looks like I can figure out a valid BoxableExpression
as:
pub type QueryType = diesel::dsl::InnerJoin<foo_dsl::Foo, bar_dsl::Bar>;
let mut filter: Box<dyn BoxableExpression<QueryType, DB, SqlType = Bool>>
= Box::new(foo_dsl::id.eq(42));
filter = Box::new(filter.and(bar_dsl::id.eq(17)));
Now, when I use that filter
variable like
query = query.filter(filter);
I get
error[E0277]: the trait bound `dyn BoxableExpression<diesel::query_builder::SelectStatement<JoinOn<diesel::query_source::joins::Join<Foo::table, Bar::table, Inner>, diesel::expression::operators::Eq<diesel::expression::nullable::Nullable<Bar::columns::foo_id>, diesel::expression::nullable::Nullable<Foo::columns::id>>>>, Sqlite, SqlType = diesel::sql_types::Bool>: AppearsOnTable<JoinOn<diesel::query_source::joins::Join<Foo::table, Bar::table, Inner>, diesel::expression::operators::Eq<Bar::columns::foo_id, diesel::expression::nullable::Nullable<Foo::columns::id>>>>` is not satisfied
--> src/main.rs:27:19
|
27 | query = query.filter(filter);
| ^^^^^^ the trait `AppearsOnTable<JoinOn<diesel::query_source::joins::Join<Foo::table, Bar::table, Inner>, diesel::expression::operators::Eq<Bar::columns::foo_id, diesel::expression::nullable::Nullable<Foo::columns::id>>>>` is not implemented for `dyn BoxableExpression<diesel::query_builder::SelectStatement<JoinOn<diesel::query_source::joins::Join<Foo::table, Bar::table, Inner>, diesel::expression::operators::Eq<diesel::expression::nullable::Nullable<Bar::columns::foo_id>, diesel::expression::nullable::Nullable<Foo::columns::id>>>>, Sqlite, SqlType = diesel::sql_types::Bool>`
|
= note: required because of the requirements on the impl of `AppearsOnTable<JoinOn<diesel::query_source::joins::Join<Foo::table, Bar::table, Inner>, diesel::expression::operators::Eq<Bar::columns::foo_id, diesel::expression::nullable::Nullable<Foo::columns::id>>>>` for `Box<dyn BoxableExpression<diesel::query_builder::SelectStatement<JoinOn<diesel::query_source::joins::Join<Foo::table, Bar::table, Inner>, diesel::expression::operators::Eq<diesel::expression::nullable::Nullable<Bar::columns::foo_id>, diesel::expression::nullable::Nullable<Foo::columns::id>>>>, Sqlite, SqlType = diesel::sql_types::Bool>>`
= note: required because of the requirements on the impl of `FilterDsl<Box<dyn BoxableExpression<diesel::query_builder::SelectStatement<JoinOn<diesel::query_source::joins::Join<Foo::table, Bar::table, Inner>, diesel::expression::operators::Eq<diesel::expression::nullable::Nullable<Bar::columns::foo_id>, diesel::expression::nullable::Nullable<Foo::columns::id>>>>, Sqlite, SqlType = diesel::sql_types::Bool>>>` for `diesel::query_builder::BoxedSelectStatement<'_, (diesel::sql_types::Integer,), JoinOn<diesel::query_source::joins::Join<Foo::table, Bar::table, Inner>, diesel::expression::operators::Eq<Bar::columns::foo_id, diesel::expression::nullable::Nullable<Foo::columns::id>>>, Sqlite>`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `and_or` due to previous error
p.p.s.
Interesting. I can get things to compile with the BoxableExpression
as long as I don't let the query be into_boxed
as well. The following compiles:
pub type QueryType = diesel::dsl::InnerJoin<foo_dsl::Foo, bar_dsl::Bar>;
let mut filter: Box<dyn BoxableExpression<QueryType, DB, SqlType = Bool>>
= Box::new(foo_dsl::id.eq(42));
filter = Box::new(filter.and(bar_dsl::id.eq(17)));
let mut query = foo_dsl::Foo
.inner_join(bar_dsl::Bar.on(bar_dsl::foo_id.eq(foo_dsl::id.nullable())))
.filter(filter);
The following filter buildup with BoxableExpression
works and is usable with a query that is then itself boxed with .into_boxed()
:
#[macro_use]
extern crate diesel;
mod schema;
use diesel::{QueryDsl, ExpressionMethods, JoinOnDsl, NullableExpressionMethods};
use diesel::sql_types::*;
use diesel::expression::BoxableExpression;
use diesel::BoolExpressionMethods;
use std::boxed::Box;
type DB = diesel::sqlite::Sqlite;
fn main() {
use crate::schema::Foo::dsl as foo_dsl;
use crate::schema::Bar::dsl as bar_dsl;
let mut filter: Box<dyn BoxableExpression<_, DB, SqlType = Bool>>
= Box::new(foo_dsl::id.eq(42));
filter = Box::new(filter.and(bar_dsl::id.eq(17)));
let mut query = foo_dsl::Foo
.inner_join(bar_dsl::Bar.on(bar_dsl::foo_id.eq(foo_dsl::id.nullable())))
.into_boxed();
let query = query.filter(filter);
}