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);
It seems that based on your attempts and self-answer that you are fixated on using a single .filter() call and sort out the dynamicism beforehand. However, I would encourage you and future viewers to instead rely on the flexibility provided by the boxed statement created by .into_boxed():
use crate::Foo::dsl as foo_dsl;
use crate::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())))
.into_boxed();
query = query.filter(foo_dsl::id.eq(42));
query = query.filter(bar_dsl::id.eq(17));
This is more in line with how the developers of Diesel have designed dynamic queries to be done.
into_boxed() says: "This is useful for cases where you want to conditionally modify a query, but need the type to remain the same."
BoxableExpression says: "For cases where you want to dynamically construct a query, boxing the query is usually more ergonomic."
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);
}
I have a working function foo, which compiles without error:
use chrono;
fn foo() {
let now = chrono::offset::Local::now();
let mut buf = String::new();
buf.push_str(&now.format("%Y/%m/%d").to_string());
}
When I try to extract the now variable to a parameter:
fn foo<T: chrono::TimeZone>(now: chrono::DateTime<T>) {
let mut buf = String::new();
buf.push_str(&now.format("%Y/%m/%d").to_string());
}
I run into this error when compiling:
error[E0599]: no method named `format` found for struct `chrono::DateTime<T>` in the current scope
--> src/lib.rs:108:35
|
108 | buf.push_str(&now.format("%Y/%m/%d").to_string());
| ^^^^^^ method not found in `chrono::DateTime<T>`
|
= note: the method `format` exists but the following trait bounds were not satisfied:
`<T as chrono::TimeZone>::Offset: std::fmt::Display`
The note says that format exists (it does, as in the first code snippet), but trait bounds aren't satisfied. How do I specify the missing trait bound to make this compile?
I'm guessing it should be possible somehow, considering that the first snippet compiles and I'm only extracting the same type as a parameter.
Related chrono docs: https://docs.rs/chrono/0.4.19/chrono/struct.DateTime.html
I took a look at the impl block for DateTime. It had code of the form below. I updated the function's signature to match, and it now compiles successfully.
fn foo<T: chrono::TimeZone>(now: chrono::DateTime<T>)
where
T::Offset: std::fmt::Display, {
...
}
lazy_static::lazy_static! {
static ref file_data: String = fs::read_to_string("static/login.html").expect("unable to read from static/login.html");
}
#[tokio::main]
async fn main() {
// code omitted
let login = warp::path("login").map(move || warp::reply::html(file_data));
// code omitted
}
Compile error:
error[E0277]: the trait bound `hyper::body::body::Body: std::convert::From<file_data>` is not satisfied
--> src/main.rs:45:49
|
45 | let login = warp::path("login").map(move || warp::reply::html(file_data));
| ^^^^^^^^^^^^^^^^^ the trait `std::convert::From<file_data>` is not implemented for `hyper::body::body::Body`
|
::: /home/ichi/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.3/src/reply.rs:170:11
|
170 | Body: From<T>,
| ------- required by this bound in `warp::reply::html`
|
= help: the following implementations were found:
<hyper::body::body::Body as std::convert::From<&'static [u8]>>
<hyper::body::body::Body as std::convert::From<&'static str>>
<hyper::body::body::Body as std::convert::From<bytes::bytes::Bytes>>
<hyper::body::body::Body as std::convert::From<std::borrow::Cow<'static, [u8]>>>
and 4 others
I am trying to pass a String to a closure. According to the documentation, From<String> is implemented for hyper::body::Body and file_data is of type String. So why am I getting this error?
From lazy_static
For a given static ref NAME: TYPE = EXPR;, the macro generates a unique type that implements Deref<TYPE> and stores it in a static with name NAME. (Attributes end up attaching to this type.)
That is, the type of the variable is not TYPE!
This is why you see the error
the trait `std::convert::From<file_data>` is not implemented for `hyper::body::body::Body`
^^^^^^^^^
You'd probably have better luck explicitly de-referencing or cloning the global variable: warp::reply::html(&*file_data) or warp::reply::html(file_data.clone()).
The issue here is that lazy_static creates a wrapper type that references your data, and hyper doesn't know how to handle it. You could use file_data.clone() to clone the referenced data and construct a body from that, but in this case there's actually a simpler method. Since your string has a fixed value and Body implements From<&'static str>, you don't actually need a heap-allocated String or lazy_static at all: You can use the following code which just uses a constant string slice that can be used directly.
const FILE_DATA: &str = "test";
#[tokio::main]
async fn main() {
// code omitted
let login = warp::path("login").map(move || warp::reply::html(FILE_DATA));
// code omitted
}
I am testing some Rust code and want to log some of the intermediate data to a file to make sure it is correct before I write the next element in the pipeline that consumes the data. In any other language I'd just write the data to a file handle stored in a static variable, but rust complains (correctly) that this is not thread safe. Since the application in question uses gstreamer this is theoretically a threat. I'll just paste my naive version below:
use std::fs::File;
use std::io::Write;
fn main() {
log_mesh("bacon");
}
static mut meshes : Option<Result<File, std::io::Error>> = None;
fn log_mesh(message: &str)
{
if let None = meshes {
meshes = Some(File::open("/tmp/meshes.txt"));
}
if let Ok(mut f) = meshes.unwrap() {
f.write_all(message.as_bytes());
f.flush();
}
}
This results in two important kinds of compile errors:
error[E0507]: cannot move out of static item
--> src/main.rs:16:24
|
16 | if let Ok(mut f) = meshes.unwrap() {
| ^^^^^^ cannot move out of static item
error[E0133]: use of mutable static is unsafe and requires unsafe function or block
--> src/main.rs:12:19
|
12 | if let None = meshes {
| ^^^^^^ use of mutable static
|
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
I have flailed around with Mutex, lazy_static!, mut_static, but all of them lead me into the woods and I get lost. I assume there has to be some compact idiom to solve this problem that isn't coming up in Google search results.
The first attempt at lazy_static! usage would be
use lazy_static::lazy_static;
use std::sync::Mutex;
use std::fs::File;
use std::io::Write;
lazy_static! {
static ref meshes : Mutex<Result<File, std::io::Error>> = Mutex::new(File::open("/tmp/meshes.txt"));
}
pub fn log_mesh(message: &str)
{
let mut tmp = meshes.lock().unwrap();
if let Ok(ref mut f) = tmp {
f.write_all(message.as_bytes());
f.flush();
}
}
which triggers this compile error:
error[E0308]: mismatched types
--> src/module2.rs:16:12
|
16 | if let Ok(ref mut f) = tmp {
| ^^^^^^^^^^^^^ --- this match expression has type `std::sync::MutexGuard<'_, std::result::Result<std::fs::File, std::io::Error>>`
| |
| expected struct `std::sync::MutexGuard`, found enum `std::result::Result`
|
= note: expected type `std::sync::MutexGuard<'_, std::result::Result<std::fs::File, std::io::Error>, >`
found type `std::result::Result<_, _>`
which is somewhat discouraging and chock-full of behind-the-curtain magic, but can be solved by changing it to
if let Ok(ref mut f) = *tmp {
I hesitate to mark it as an answer because there could be race conditions a more experienced coder can spot or another idiom that is superior.
I am using Rayon to produce reasonably large return values. This uses a lot of memory when collecting all returned values into a Vec. Is there a way to avoid creating a Vec and directly consuming as an iterable?
Here is an example which doesn't work:
fn main() {
let numbers: Vec<_> = "12.03 0.3 44.2 45 zzz".split_whitespace().collect();
let x = numbers
.par_iter()
.map(|n| n.parse::<f32>())
.filter_map(|n| n.ok());
for n in x {
println!("{:?}", n);
}
}
error[E0277]: the trait bound `rayon::iter::FilterMap<rayon::iter::Map<rayon::slice::Iter<'_, &str>, [closure#src/main.rs:10:14: 10:34]>, [closure#src/main.rs:11:21: 11:31]>: std::iter::Iterator` is not satisfied
|
13 | for n in x {
| ^ `rayon::iter::FilterMap<rayon::iter::Map<rayon::slice::Iter<'_, &str>, [closure#src/main.rs:10:14: 10:34]>, [closure#src/main.rs:11:21: 11:31]>` is not an iterator; maybe try calling `.iter()` or a similar method
|
= help: the trait `std::iter::Iterator` is not implemented for `rayon::iter::FilterMap<rayon::iter::Map<rayon::slice::Iter<'_, &str>, [closure#src/main.rs:10:14: 10:34]>, [closure#src/main.rs:11:21: 11:31]>`
= note: required by `std::iter::IntoIterator::into_iter`
playground
You are looking for ParallelIterator::for_each:
extern crate rayon; // 1.0.2
use rayon::prelude::*;
fn main() {
let numbers = ["12.03", "0.3", "44.2", "45", "zzz"];
let x = numbers.par_iter().flat_map(|n| n.parse::<f32>());
x.for_each(|n| {
println!("{:?}", n);
});
}
Related:
ParallelIterator::for_each_with
ParallelIterator::try_for_each
ParallelIterator::try_for_each_with
See also:
How to satisfy the Iterator trait bound in order to use Rayon here?