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 am using the Rust config crate and want to switch from loading configuration from a file at runtime to a static string created at compile time.
Right now, it works like this:
config::Config::builder().add_source(File::new("default.toml", FileFormat::Toml));
However when I try it with a static string, it does not:
static DEFAULT: &str = std::include_str!("./default.toml");
[...]
config::Config::builder().add_source(DEFAULT)
Error Message
error[E0277]: the trait bound `&str: Source` is not satisfied
--> src/config.rs:21:25
|
21 | .add_source(DEFAULT)
| ---------- ^^^^^^^ the trait `Source` is not implemented for `&str`
| |
| required by a bound introduced by this call
|
note: required by a bound in `ConfigBuilder::<DefaultState>::add_source`
--> /home/konrad/.cargo/registry/src/github.com-1ecc6299db9ec823/config-0.13.1/src/builder.rs:207:12
|
207 | T: Source + Send + Sync + 'static,
| ^^^^^^ required by this bound in `ConfigBuilder::<DefaultState>::add_source`
How can I read my config from a static string instead of a file?
Use File::from_str():
config::Config::builder().add_source(File::from_str(DEFAULT, FileFormat::Toml));
Here's the error message:
error[E0038]: the trait `room::RoomInterface` cannot be made into an object
--> src\permanent\registry\mod.rs:12:33
|
12 | pub fn load(id : String) -> Result<Box<dyn RoomInterface>, String>{
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `room::RoomInterface` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> src\permanent\rooms\mod.rs:36:31
|
36 | pub trait RoomInterface : Copy + Sized {
| ------------- ^^^^ ^^^^^ ...because it requires `Self: Sized`
| | |
| | ...because it requires `Self: Sized`
| this trait cannot be made into an object...
For more information about this error, try `rustc --explain E0038`.
It says that to use the trait as an object, it requires Sized. Except that Sized is right there, in the declaration of the trait! It literally points to the word "Sized" and tells me I need to have "Sized". What's going on?
The problem is opposite to what you think: The problem is that you require Self: Sized but only traits which do not require Self: Sized can be made into an object.
As the error message states you must remove both bounds for Copy and Sized for RoomInterface:
pub trait RoomInterface {
The article linked in the error message is a great resource, I recommend reading it:
https://doc.rust-lang.org/reference/items/traits.html#object-safety
Also this discussion might be interesting:
https://users.rust-lang.org/t/trait-objects-and-the-sized-trait/14410/2
I am trying to mock a trait using the mockall crate:
#[automock]
trait Foo {
fn foo(input: &Vec<String>) -> Option<&String>;
}
However, I get the following error:
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/names_matcher.rs:79:51
|
79 | fn foo(input: &Vec<String>) -> Option<&String>;
| ^ explicit lifetime name needed here
error[E0623]: lifetime mismatch
--> src/names_matcher.rs:77:9
|
77 | #[automock]
| ^^^^^^^^^^^
| |
| ...but data from `input` is returned here
78 | trait Foo {
79 | fn foo(input: &Vec<String>) -> Option<&String>;
| ------------ this parameter and the return type are declared with different lifetimes...
The function I want to implement will return either None or Some with a reference to one of the elements of the vector in input. If I try to define the lifetimes taking this into account:
#[automock]
trait Foo {
fn foo<'r>(input: &'r Vec<String>) -> Option<&'r String>;
}
I get the following:
error[E0261]: use of undeclared lifetime name `'r`
--> src/names_matcher.rs:79:20
|
79 | fn foo<'r>(input: &'r Vec<String>) -> Option<&'r String>;
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'r` here
|
77 | #[automock]<'r>
| ^^^^
help: consider introducing lifetime `'r` here
|
77 | 'r, #[automock]
| ^^^
But none of the suggestions work, they produce syntax errors. Is there a way to mock a trait like the one I defined above?
This question already has answers here:
How can I have a collection of objects that differ by their associated type?
(3 answers)
Vector of objects belonging to a trait
(3 answers)
Closed 4 years ago.
I am building a command-line application. I have the following trait:
trait ValidatedCommand {
type Output;
fn run() -> Result<Self::Output, std::io::Error>;
}
and I have the following two implementations for it:
struct First;
impl ValidatedCommand for First {
type Output = i32;
fn run() -> Result<i32, std::io::Error> {
Ok(1)
}
}
impl First {
fn new() -> First {
First {}
}
}
struct Second;
impl ValidatedCommand for Second {
type Output = String;
fn run() -> Result<String, std::io::Error> {
Ok(String::from("hello"))
}
}
impl Second {
fn new() -> Second {
Second {}
}
}
Both structs implement the trait, one returning a String and the other an i32.
I'm trying to create a Vec of that trait, but I'm not sure how to go about it. I tried the following:
fn main() {
let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
playground.
which errors with
error[E0191]: the value of the associated type `Output` (from the trait `ValidatedCommand`) must be specified
--> src/main.rs:33:23
|
2 | type Output;
| ------------ `Output` defined here
...
33 | let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
| ^^^^^^^^^^^^^^^^^^^^ associated type `Output` must be specified
error[E0277]: the size for values of type `dyn ValidatedCommand` cannot be known at compilation time
--> src/main.rs:33:19
|
33 | let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn ValidatedCommand`
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required by `std::vec::Vec`
error[E0038]: the trait `ValidatedCommand` cannot be made into an object
--> src/main.rs:33:19
|
33 | let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ValidatedCommand` cannot be made into an object
|
= note: method `run` has no receiver
error[E0308]: mismatched types
--> src/main.rs:33:52
|
33 | let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
| ^^^^^^^^^^^^ expected trait ValidatedCommand, found struct `First`
|
= note: expected type `dyn ValidatedCommand`
found type `First`
error[E0277]: the size for values of type `dyn ValidatedCommand` cannot be known at compilation time
--> src/main.rs:33:47
|
33 | let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn ValidatedCommand`
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required by `std::slice::<impl [T]>::into_vec`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error[E0277]: the size for values of type `dyn ValidatedCommand` cannot be known at compilation time
--> src/main.rs:33:47
|
33 | let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn ValidatedCommand`
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: slice and array elements must have `Sized` type
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error[E0038]: the trait `ValidatedCommand` cannot be made into an object
--> src/main.rs:33:47
|
33 | let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ValidatedCommand` cannot be made into an object
|
= note: method `run` has no receiver
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error[E0277]: the size for values of type `dyn ValidatedCommand` cannot be known at compilation time
--> src/main.rs:33:47
|
33 | let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn ValidatedCommand`
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required by `std::vec::Vec`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error[E0038]: the trait `ValidatedCommand` cannot be made into an object
--> src/main.rs:33:47
|
33 | let commands: Vec<dyn ValidatedCommand> = vec![First::new(), Second::new()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ValidatedCommand` cannot be made into an object
|
= note: method `run` has no receiver
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
I am thinking that maybe there is a way to make use of the associated type, but I have no idea how I might go about it.
Is there a way to get this vector creation to compile?