I am trying to update a field in a table use Diesel. I need to verify an association in another table, so I am LEFT JOIN-ing the other table. Here is a SQL representation of what I am doing:
UPDATE table_name AS tn
SET field = 'value'
FROM table_name
LEFT JOIN other_table AS ot
ON ot.id_field_one = {some_id}
WHERE tn.id_field_one = {some_id} and ot.id_field_two = {some_different_id};
Here is what I have tried with Diesel:
dsl::update(
table_name
.left_join(other_table.on(other_table_fields::id_field_one.eq(some_id)))
.filter(table_fields::id_field_one.eq(some_id))
.filter(other_table_fields::id_field_two.eq(some_different_id))
)
.set(table_fields::field.eq("value"))
.execute(db_connection)?;
I get the following error (I've replaced the table and field names to match the names of my examples above):
error[E0277]: the trait bound `diesel::query_builder::SelectStatement<JoinOn<diesel::query_source::joins::Join<table_name::table, other_table::table, LeftOuter>, diesel::expression::operators::Eq<other_table::columns::some_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>, query_builder::select_clause::DefaultSelectClause, query_builder::distinct_clause::NoDistinctClause, query_builder::where_clause::WhereClause<And<diesel::expression::operators::Eq<other_table::columns::some_different_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>, diesel::expression::operators::Eq<table_name::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>>>: diesel::query_builder::IntoUpdateTarget` is not satisfied
--> src/file.rs:297:9
|
296 | match dsl::update(
| ----------- required by a bound introduced by this call
297 | / table_name
298 | | .left_join(other_table.on(other_table_fields::some_id.eq(some_id)))
299 | | .filter(other_table_fields::some_different_id.eq(some_different_id))
300 | | .filter(table_fields::id.eq(some_id)),
| |________________________________________________________________^ the trait `diesel::query_builder::IntoUpdateTarget` is not implemented for `diesel::query_builder::SelectStatement<JoinOn<diesel::query_source::joins::Join<table_name::table, other_table::table, LeftOuter>, diesel::expression::operators::Eq<other_table::columns::some_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>, query_builder::select_clause::DefaultSelectClause, query_builder::distinct_clause::NoDistinctClause, query_builder::where_clause::WhereClause<And<diesel::expression::operators::Eq<other_table::columns::some_different_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>, diesel::expression::operators::Eq<table_name::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>>>`
|
= help: the trait `diesel::query_builder::IntoUpdateTarget` is implemented for `diesel::query_builder::SelectStatement<F, query_builder::select_clause::DefaultSelectClause, query_builder::distinct_clause::NoDistinctClause, W>`
note: required by a bound in `diesel::update`
--> /Users/tanner/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-1.4.8/src/query_builder/functions.rs:80:18
|
80 | pub fn update<T: IntoUpdateTarget>(source: T) -> UpdateStatement<T::Table, T::WhereClause> {
| ^^^^^^^^^^^^^^^^ required by this bound in `diesel::update`
error[E0277]: the trait bound `JoinOn<diesel::query_source::joins::Join<table_name::table, other_table::table, LeftOuter>, diesel::expression::operators::Eq<other_table::columns::some_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>: HasTable` is not satisfied
The SQL works when I run it as a query, but I can't figure out how to represent the same thing in working Rust code. What am I missing here?
Diesel does currently not support joins in that position. You can either use diesel::sql_query to write the whole query or provide a custom query dsl extension for your specific query.
Related
I have a procedural macro I have implemented which depends on the proc-macro-error crate. My client project depends on this macro crate.
When I build for native, everything works perfectly, but when I build for wasm, I get a number of errors thrown from proc-macro-error:
error[E0599]: no method named `unwrap` found for struct `proc_macro2::Span` in the current scope
--> /Users/spencerkohan/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro-error-1.0.4/src/imp/delegate.rs:33:38
|
33 | let span = span_range.collapse().unwrap();
| ^^^^^^ method not found in `proc_macro2::Span`
error[E0599]: no method named `unwrap` found for struct `proc_macro2::Span` in the current scope
--> /Users/spencerkohan/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro-error-1.0.4/src/imp/delegate.rs:49:53
|
49 | res.span_note(span_range.collapse().unwrap(), msg)
| ^^^^^^ method not found in `proc_macro2::Span`
error[E0599]: no method named `unwrap` found for struct `proc_macro2::Span` in the current scope
--> /Users/spencerkohan/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro-error-1.0.4/src/imp/delegate.rs:52:53
|
52 | res.span_help(span_range.collapse().unwrap(), msg)
| ^^^^^^ method not found in `proc_macro2::Span`
error[E0599]: no method named `unwrap` found for struct `proc_macro2::Span` in the current scope
--> /Users/spencerkohan/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro-error-1.0.4/src/imp/delegate.rs:60:42
|
60 | let span = span_range.collapse().unwrap();
| ^^^^^^ method not found in `proc_macro2::Span`
error[E0277]: the trait bound `proc_macro::TokenStream: From<TokenStream2>` is not satisfied
--> /Users/spencerkohan/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro-error-1.0.4/src/lib.rs:459:29
|
459 | gen_error().into()
| ^^^^ the trait `From<TokenStream2>` is not implemented for `proc_macro::TokenStream`
|
= help: the trait `From<proc_macro::TokenTree>` is implemented for `proc_macro::TokenStream`
= note: required because of the requirements on the impl of `Into<proc_macro::TokenStream>` for `TokenStream2`
error[E0277]: the trait bound `proc_macro::TokenStream: From<TokenStream2>` is not satisfied
--> /Users/spencerkohan/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro-error-1.0.4/src/lib.rs:464:34
|
464 | Ok(_) => gen_error().into(),
| ^^^^ the trait `From<TokenStream2>` is not implemented for `proc_macro::TokenStream`
|
= help: the trait `From<proc_macro::TokenTree>` is implemented for `proc_macro::TokenStream`
= note: required because of the requirements on the impl of `Into<proc_macro::TokenStream>` for `TokenStream2`
error[E0277]: the trait bound `proc_macro2::Span: From<proc_macro::Span>` is not satisfied
--> /Users/spencerkohan/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro-error-1.0.4/src/lib.rs:549:37
|
549 | first: self.clone().into(),
| ^^^^ the trait `From<proc_macro::Span>` is not implemented for `proc_macro2::Span`
|
= note: required because of the requirements on the impl of `Into<proc_macro2::Span>` for `proc_macro::Span`
error[E0277]: the trait bound `proc_macro2::Span: From<proc_macro::Span>` is not satisfied
--> /Users/spencerkohan/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro-error-1.0.4/src/lib.rs:550:36
|
550 | last: self.clone().into(),
| ^^^^ the trait `From<proc_macro::Span>` is not implemented for `proc_macro2::Span`
|
= note: required because of the requirements on the impl of `Into<proc_macro2::Span>` for `proc_macro::Span`
It doesn't make sense to me why there should be an issue: this code is not actually compiled for wasm, it's only called inside the proc macro, which is used at compile time.
How can I solve this issue?
If I have the schema.rs:
table! {
Foo (id) {
id -> Integer,
label -> Nullable<Text>,
}
}
And I filter like:
let result: String = foo_dsl::Foo
.select(foo_dsl::label)
.filter(foo_dsl::label.is_not_null())
.first(&conn)
.unwrap();
I get this error:
error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, Mysql>` is not satisfied
--> src/main.rs:21:10
|
21 | .first(&conn)
| ^^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, Mysql>` is not implemented for `*const str`
|
= help: the following other types implement trait `FromSql<A, DB>`:
<*const str as FromSql<diesel::sql_types::Text, DB>>
<std::string::String as FromSql<ST, DB>>
= note: required because of the requirements on the impl of `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, Mysql>` for `std::string::String`
= note: required because of the requirements on the impl of `Queryable<diesel::sql_types::Nullable<diesel::sql_types::Text>, Mysql>` for `std::string::String`
= note: required because of the requirements on the impl of `LoadQuery<MysqlConnection, std::string::String>` for `diesel::query_builder::SelectStatement<table, query_builder::select_clause::SelectClause<columns::label>, query_builder::distinct_clause::NoDistinctClause, query_builder::where_clause::WhereClause<IsNotNull<columns::label>>, query_builder::order_clause::NoOrderClause, query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<BigInt, i64>>>`
note: required by a bound in `first`
--> /home/kmdreko/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-1.4.8/src/query_dsl/mod.rs:1343:22
|
1343 | Limit<Self>: LoadQuery<Conn, U>,
| ^^^^^^^^^^^^^^^^^^ required by this bound in `first`
This makes sense; the field is specified as Nullable and will work if I used Option<String>. But for this query I know that the value exists, since I filter by .is_not_null(). Is it possible to strip the Nullable column wrapper or do I need to manually unwrap after the query result?
You have several options there:
Use .unwrap() or a similar method on the result
Use an explicit select clause + .assume_not_null(). (Note that this method is only available on diesel 2.0, as your question is missing information about the diesel version it's hard to tell if you can use this directly or if you need to implement something like this on your own).
I am having difficulty determining from Diesel's documentation how to express this query with Diesel (without using raw_sql):
SELECT *
FROM budgets AS b
LEFT JOIN user_budgets AS ub
ON (ub.budget_id = {budget_id}
AND ub.user_id = {user_id})
WHERE b.id = {budget_id}
LIMIT 1;
{budget_id} and {user_id} are variable. This is what I've tried:
let budget = budgets
.select(budget_fields::all_columns)
.left_join(user_budgets.on(user_budget_fields::budget_id.eq(budget_id)))
.left_join(user_budget_fields::user_id.eq(user_id))
.filter(budget_fields::id.eq(budget_id))
.first::<Budget>(db_connection)?;
but I get this error:
error[E0277]: the trait bound `budgets::table: JoinTo<diesel::expression::operators::Eq<user_budgets::columns::user_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>` is not satisfied
--> src/utils/db/budget.rs:46:10
|
46 | .left_join(user_budget_fields::user_id.eq(user_id))
| ^^^^^^^^^ the trait `JoinTo<diesel::expression::operators::Eq<user_budgets::columns::user_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>` is not implemented for `budgets::table`
|
= help: the following other types implement trait `JoinTo<T>`:
<budgets::table as JoinTo<JoinOn<Join, On>>>
<budgets::table as JoinTo<diesel::query_builder::BoxedSelectStatement<'a, QS, ST, DB>>>
<budgets::table as JoinTo<diesel::query_builder::SelectStatement<F, S, D, W, O, L, Of, G>>>
<budgets::table as JoinTo<diesel::query_source::joins::Join<Left, Right, Kind>>>
= note: required because of the requirements on the impl of `JoinTo<diesel::expression::operators::Eq<user_budgets::columns::user_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>` for `diesel::query_source::joins::Join<budgets::table, user_budgets::table, LeftOuter>`
= note: required because of the requirements on the impl of `JoinWithImplicitOnClause<diesel::expression::operators::Eq<user_budgets::columns::user_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>, LeftOuter>` for `diesel::query_builder::SelectStatement<JoinOn<diesel::query_source::joins::Join<budgets::table, user_budgets::table, LeftOuter>, diesel::expression::operators::Eq<user_budgets::columns::budget_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>, query_builder::select_clause::SelectClause<(budgets::columns::id, budgets::columns::is_shared, budgets::columns::is_private, budgets::columns::is_deleted, budgets::columns::name, budgets::columns::description, budgets::columns::start_date, budgets::columns::end_date, budgets::columns::latest_entry_time, budgets::columns::modified_timestamp, budgets::columns::created_timestamp)>>`
For more information about this error, try `rustc --explain E0277`.
I have also tried this:
let budget = budgets
.select(budget_fields::all_columns)
.left_join(
user_budgets
.on(user_budget_fields::budget_id.eq(budget_id))
.and(user_budget_fields::user_id.eq(user_id)),
)
.filter(budget_fields::id.eq(budget_id))
.first::<Budget>(db_connection)?;
but I get this error:
error[E0599]: the method `and` exists for struct `OnClauseWrapper<user_budgets::table, diesel::expression::operators::Eq<user_budgets::columns::budget_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>`, but its trait bounds were not satisfied
--> src/utils/db/budget.rs:48:18
|
48 | .and(user_budget_fields::user_id.eq(user_id)),
| ^^^ method cannot be called on `OnClauseWrapper<user_budgets::table, diesel::expression::operators::Eq<user_budgets::columns::budget_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>` due to unsatisfied trait bounds
|
::: /Users/tanner/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-1.4.8/src/query_source/joins.rs:281:1
|
281 | pub struct OnClauseWrapper<Source, On> {
| --------------------------------------
| |
| doesn't satisfy `<_ as diesel::Expression>::SqlType = diesel::sql_types::Bool`
| doesn't satisfy `_: BoolExpressionMethods`
| doesn't satisfy `_: diesel::Expression`
|
= note: the following trait bounds were not satisfied:
`<OnClauseWrapper<user_budgets::table, diesel::expression::operators::Eq<user_budgets::columns::budget_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>> as diesel::Expression>::SqlType = diesel::sql_types::Bool`
which is required by `OnClauseWrapper<user_budgets::table, diesel::expression::operators::Eq<user_budgets::columns::budget_id, diesel::expression::bound::Bound<diesel::sql_types::Uuid, uuid::Uuid>>>: BoolExpressionMethods`
For more information about this error, try `rustc --explain E0599`.
What am I missing here?
You definitely want a single left_join. In your second attempt, the error is that the and needs to be inside the call to on, not after it (the argument to on must be the full boolean expression).
let budget = budgets
.select(budget_fields::all_columns)
.left_join(
user_budgets.on(
user_budget_fields::budget_id.eq(budget_id)
.and(user_budget_fields::user_id.eq(user_id))),
)
.filter(budget_fields::id.eq(budget_id))
.first::<Budget>(db_connection)?;
I wanted to implement a conversion trait that would cover all types supporting already existing conversion. I thought that this could be done in following way:
impl<T> Into<B> for T
where
T: Into<A>,
{
fn into(self) -> B {
let a: A = self.into();
B::CaseA(a)
}
}
However compiler throws a following error:
error[E0119]: conflicting implementations of trait `std::convert::Into<block::ItemContent>`
--> yrs\src\block.rs:945:1
|
945 | / impl<T> Into<B> for T
946 | | where
947 | | T: Into<A>,
948 | | {
... |
952 | | }
953 | | }
| |_^
|
= note: conflicting implementation in crate `core`:
- impl<T, U> Into<U> for T
where U: From<T>;
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`B`)
--> yrs\src\block.rs:945:6
|
945 | impl<T> Into<B> for T
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`B`)
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
Is it possible to achieve this? I'm looking for a way to automatically extend conversion for a new type for all instances, that support conversion to another existing type.
What you are trying to do can be achieved (as the error says) by covering T with a local type. The reason you cannot do it without that is because otherwise someone else could also do the same and the Rust won't be able to tell which impl to use. So you need a local wrapper type to keep the separation.
The complete reasoning behind this is referenced in the error explanation:
https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md
And https://rust-lang.github.io/rfcs/2451-re-rebalancing-coherence.html
hope this helps ;)
A
I have an iterator that maps over some values, creating tuples on the way. I need to get the maximum by one of the elements on the tuple (which is not Copy), but interior references are getting in the way (as was expected when it got stabilised).
How can I make something like this work?
// Not a Copy type!
#[derive(Ord, PartialOrd, Eq, PartialEq)]
struct t(i8);
fn main() {
// This works
let v = vec![(t(0),), (t(1),)];
v.iter().min_by_key(|v| &v.0);
// This doesn't
let v = vec![0, 1];
v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
}
Playground
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:12:47
|
12 | v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 12:43...
--> src/main.rs:12:43
|
12 | v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
| ^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:12:47
|
12 | v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
| ^^^^
note: but, the lifetime must be valid for the method call at 12:5...
--> src/main.rs:12:5
|
12 | v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that a type/lifetime parameter is in scope here
--> src/main.rs:12:5
|
12 | v.iter().map(|i| (t(*i),)).min_by_key(|v| &v.0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
They cannot. As values flow through iterator adapters, they are moved. Moving a value causes any references to it to be invalidated. You are attempting to take a reference to a value that only exists in the iterator pipeline; the reference cannot live long enough. This is equivalent to this basic example:
(0..9).map(|x| &x)
You will need to use Iterator::min_by:
v.iter().map(|i| (X(*i),)).min_by(|a, b| a.0.cmp(&b.0));
This works because the returned value from the closure is an Ordering with no references to the original values.