Diesel generic update - rust

I am trying implementation of a generic update method using diesel. At first I tried to pass an object
pub fn update<Model, Tab>(
conn: &PgConnection,
_: Tab,
current_model: Model,
mut new_model: Model,
) -> Result<Model, diesel::result::Error>
but with this there were some difficulties and I changed it to a reference.
Now i have this code:
pub fn update<'m, Model, Tab>(
conn: &PgConnection,
_: Tab,
current_model: &Model,
mut new_model: Model,
) -> Result<Model, diesel::result::Error>
where
Model: AsChangeset<Target = Tab>
+ Insertable<Tab>
+ diesel::Queryable<<<Tab as Table>::AllColumns as diesel::Expression>::SqlType, Pg>
+ IntoUpdateTarget
+ HasTable<Table = Tab>
+ 'm
+ diesel::Queryable<
<<<&'m Model as HasTable>::Table as Table>::AllColumns as diesel::Expression>::SqlType,
Pg,
>
+ AsChangeset<Target = Tab>,
&'m Model: Identifiable + IntoUpdateTarget,
<<&'m Model as HasTable>::Table as QuerySource>::FromClause: QueryFragment<Pg>,
<&'m Model as IntoUpdateTarget>::WhereClause: QueryFragment<Pg>,
Pg: HasSqlType<
<<<&'m Model as HasTable>::Table as Table>::AllColumns as diesel::Expression>::SqlType,
>,
<<&'m Model as HasTable>::Table as Table>::AllColumns: QueryFragment<Pg>,
&'m Model: AsChangeset,
<&'m Model as AsChangeset>::Changeset: QueryFragment<Pg>,
<Model as AsChangeset>::Changeset: QueryFragment<Pg>,
<Model as IntoUpdateTarget>::WhereClause: QueryFragment<Pg>,
Tab: HasTable<Table = Tab> + Table + IntoUpdateTarget + FindDsl<Model>,
<Tab as QuerySource>::FromClause: QueryFragment<Pg>,
<Tab as IntoUpdateTarget>::WhereClause: QueryFragment<Pg>,
<Tab as Table>::AllColumns: QueryFragment<Pg>,
{
Ok(diesel::update(current_model)
.set(new_model)
.get_result(conn)
.unwrap())
}
But when compiling, it gives such an error and I don’t quite understand what’s wrong and how best to fix it.
error[E0271]: type mismatch resolving `<Model as AsChangeset>::Target == <&Model as HasTable>::Table`
|
38 | pub fn update<'m, Model, Tab>(
| --- this type parameter
...
78 | .set(new_model)
| ^^^ expected associated type, found type parameter `Tab`
|
= note: expected associated type `<&Model as HasTable>::Table`
found type parameter `Tab`
= note: you might be missing a type parameter or trait bound
note: required by a bound in `UpdateStatement::<T, U>::set`
|
43 | V: changeset::AsChangeset<Target = T>,
| ^^^^^^^^^^ required by this bound in `UpdateStatement::<T, U>::set`
Does anyone have any ideas how this can be solved? And is it possible to implement an abstract update over a diesel engine at all, maybe someone has implemented something similar. Thanks in advance

As a general advice: Avoid writing generic code in that way to "abstract" over diesel. It is quite hard to write this code as diesel is opinionated about it's API. If you feel that something is hard to abstract over it is a quite clear sign that you likely head into the wrong direction. In this case you seem to exchange the builder based pattern diesel uses to a single function call. Both require exactly the same information and I would say both are similar "hard" to type. So maybe just use that variant diesel already provides?
That written: It is certainly possible to implement such a function. It requires to fulfill any trait bound rustc requests. I generally advice to not only look at the first bound rustc advice to add, but also on the required because of: lines, because often they contain the same trait bound in different messages. Adding this shared bound allows to simplify the relevant code.
To fix the error messages contained in your question in just need to add the following bounds:
pub fn update<Model, Tab>(
conn: &PgConnection,
table: Tab,
mut new_model: Model,
) -> Result<Usize, diesel::result::Error>
where
Model: AsChangeset<Target = Tab> + Insertable<Tab>,
Tab: Identifiable
+ QueryFragment<Pg>
+ HasTable<Table = Tab>
+ diesel::Table
+ IntoUpdateTarget
+ AsChangeset,
<Tab as QuerySource>::FromClause: QueryFragment<Pg>,
<Tab as IntoUpdateTarget>::WhereClause: QueryFragment<Pg>,
<Model as AsChangeset>::Changeset: QueryFragment<Pg>,
{ … }

Related

Implementing Index trait for any type that implement my trait

Is there any way to bypass rust orphan rule here? (i want to implement Index trait for any types that implement Board trait).
I mean, Board trait is mine, CellLocation struct is mine, Piece trait is mine, and indexing could be done by using get_piece for any struct that implements Board.
Or it's not idiomatic because user may want to implement his own indexing logic for his struct even if his struct implements Board? Or for any other reason?
pub trait Board {
type Piece: Piece;
fn get_piece(&self, location: CellLocation) -> Option<Self::Piece>;
}
// getting error here
impl<TBoard: Board> Index<CellLocation> for TBoard {
type Output = TBoard::Piece;
fn index(&self, index: CellLocation) -> &Self::Output {
todo!()
}
}
|
56 | impl<TBoard: Board> Index<CellLocation> for TBoard {
| ^^^^^^ type parameter `TBoard` must be covered by another type when it appears before the first local type (`CellLocation`)
|
= 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

Sender cannot be shared between threads safely when using question mark operator

Sending a struct containing a Sender through a channel and using the question mark to handle errors, Rust complains about Sender<..> not implementing Sync.
Without the question mark, it doesn't.
So, is the Sync trait expected from the Sender?
Not understanding the question mark operator in detail, I assume an anyhow::Error is being constructed - but why would the Sender end up in the error object?
(My application has one database thread that handles all queries and communicates via channels)
Here's the code:
|db: Db| -> anyhow::Result<()> {
let (res_tx, res_rx) = mpsc::channel::<Result<Vec<Row>>>();
db.send(database_handler::Request::Query {
query: "select name from actions",
params: Vec::new(),
result: res_tx,
})?; // dis be line 35
}
Here's the error:
error[E0277]: `Sender<Result<Vec<postgres::Row>, anyhow::Error>>` cannot be shared between threads safely
--> src/events.rs:35:6
|
35 | })?;
| ^ `Sender<Result<Vec<postgres::Row>, anyhow::Error>>` cannot be shared between threads safely
|
= help: within `SendError<Request<'_>>`, the trait `Sync` is not implemented for `Sender<Result<Vec<postgres::Row>, anyhow::Error>>`
= help: the following other types implement trait `FromResidual<R>`:
<Result<T, F> as FromResidual<Result<Infallible, E>>>
<Result<T, F> as FromResidual<Yeet<E>>>
note: required because it appears within the type `Request<'_>`
--> src/database.rs:39:10
|
39 | pub enum Request<'a> {
| ^^^^^^^
= note: required because it appears within the type `SendError<Request<'_>>`
= note: required because of the requirements on the impl of `From<SendError<Request<'_>>>` for `anyhow::Error`
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, SendError<Request<'_>>>>` for `Result<(), anyhow::Error>`
And these are the involved types:
type Db<'a> = Sender<database_handler::Request<'a>>;
type ParamsType<'a> = Vec<&'a (dyn ToSql + Sync)>;
pub enum Request<'a> {
Query { query: &'static str, params: ParamsType<'a>, result: Sender<Result<Vec<Row>>> },
QueryOne { query: &'static str, params: ParamsType<'a>, result: Sender<Result<Option<Row>>> },
Execute { query: &'static str, params: ParamsType<'a>, result: Sender<Result<u64>> },
}
You are correct that an anyhow::Error is being constructed, but - from what? Since Sender::send() takes ownership of the value you give it, the error it returns when it fails to send includes the original value, allowing you to retry sending later or in a different manner. So your anyhow::Error gets constructed from SendError<Query> that contains a Query.
The Sync requirement comes from anyhow::Error itself being Send and Sync (because it's useful to move error to a different thread), so its From implementation must require the same of the source error. In your case the source error is SendError<Query> which is not Sync because it contains Query whose result field contains a (different) Sender, which not Sync.
Once aware of this, you can see the error message telling you this, too. The fix is to replace db.send(...)? with something like db.send(...).map_err(|_| anyhow!("receiver is gone")). Also, you'll need an explicit Ok(()) at the end of the closure.

Rust Diesel Abstract update function

I currently trying to implement abstract function which will update a few meta fields for any table in the database, but getting problems with Identifiable.
I have a database where every table has meta-fields:
....
pub updu: Option<Uuid>, // ID of a user who changed it
pub updt: Option<NaiveDateTime>, //updated with current date/time on every change
pub ver: Option<i32>, //Version increases on every change
.....
I want to implement a function which would make update for every entity. Currently I have this implementation:
pub fn update<Model>(
conn: &PgConnection,
old_model: Model,
mut updated_model: Model,
user_id: Uuid,
) -> Result<Model, diesel::result::Error>
where
Model: MetaFields + AsChangeset<Target = <Model as HasTable>::Table> + IntoUpdateTarget,
Update<Model, Model>: LoadQuery<PgConnection, Model>
{
updated_model.update_fields(user_id);
Ok(
diesel::update(old_model)
.set(updated_model)
.get_result(conn).unwrap()
)
When I am trying to call it it shows this error:
error[E0277]: the trait bound `Marking: Identifiable` is not satisfied
--> src/service/marking_service.rs:116:24
|
116 | web::block(move || common::dao::update(&conn2, real_marking1[0].clone(), marking2_to_update, jwt_token.user_id))
| ^^^^^^^^^^^^^^^^^^^ the trait `Identifiable` is not implemented for `Marking`
|
= help: the following implementations were found:
<&'ident Marking as Identifiable>
= note: required because of the requirements on the impl of `IntoUpdateTarget` for `Marking`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `testapi` due to previous error
An entity which I am trying to update in this example is:
use chrono::{NaiveDateTime, Utc};
use common::model::MetaFields;
use common::utils::constants::DEL_MARK_AVAILABLE;
use serde::{Deserialize, Serialize};
use serde_json;
use uuid::Uuid;
use crate::schema::marking;
#[derive(
Clone,
Serialize,
Deserialize,
Debug,
Queryable,
Insertable,
AsChangeset,
Identifiable,
QueryableByName,
Default,
)]
#[primary_key(uuid)]
#[table_name = "marking"]
pub struct Marking {
pub uuid: Uuid,
pub updt: Option<NaiveDateTime>,
pub ver: Option<i32>,
pub updu: Option<Uuid>,
pub comment: Option<String>,
pub status: Option<String>,
}
impl MetaFields for Marking {
fn update_fields(&mut self, user_id: Uuid) {
self.updu = Option::from(user_id);
self.ver = Option::from(self.ver.unwrap() + 1);
self.updt = Option::from(Utc::now().naive_local());
}
}
As you can see Identifiable is defined for this entity, but for some reason update cannot see it. Could someone suggest what I am missing here?
Update, schema:
table! {
marking (uuid) {
uuid -> Uuid,
updt -> Nullable<Timestamp>,
ver -> Nullable<Int4>,
updu -> Nullable<Uuid>,
comment -> Nullable<Varchar>,
status -> Nullable<Varchar>,
}
}
diesel = { version = "1.4.6", features = ["postgres", "uuid", "chrono", "uuidv07", "serde_json"] }
r2d2 = "0.8"
r2d2-diesel = "1.0.0"
diesel_json = "0.1.0"
Your code is almost correct. The error message already mentions the issue:
#[derive(Identifiable)] does generate basically the following impl: impl<'a> Identifiable for &'a struct {}, which means that trait is only implemented for a reference to self. Depending on your other trait setup you can try the following things:
Pass a reference as old_model common::dao::update
Change the definition of common::dao::update to take a reference as second argument. Then you can separate the trait bounds for Model so that you bound IntoUpdateTarget on &Model instead.
(It's hard to guess which one will be the better solution as your question is missing a lot of important context. Please try to provide a complete minimal example in the future.)

How to include <T as Trait>::Blocknumber in a struct within a Substrate FRAME pallet

Can anybody tell me please how to include <T as Trait>::BlockNumber and <T as Trait>::AccountId in my struct within my pallet module?
My current solution is to add a generic parameter T with a Trait bound to "Trait". Link to code.
I think the usage of that generic struct as a function parameter type in decl_module! (line 72) does lead to the following error:
error[E0277]: T doesn't implement std::fmt::Debug
-- snip --
= help: the trait std::fmt::Debug is not implemented for T
= note: required because of the requirements on the impl of std::fmt::Debug for PhysicalProof<T, [u8; 32]>
= note: required because of the requirements on the impl of std::fmt::Debug for (PhysicalProof<T, [u8; 32]>,)
= note: required by std::fmt::Debug::fmt
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider further restricting this bound
impl<$trait_instance: $trait_name + std::fmt::Debug $(, $instance: $instantiable)?> $crate::dispatch::fmt::Debug
I have tried to implement fmt::Debug manually for T within that struct, but either that is not a solution or I am incapable of doing it correctly.
To derive Debug for as struct, all of its fields must be able to implement Debug. Right now, the compiler doesn't know if T is debuggable.
You can tell the compiler that T implements Debug by adding a Debug as a bound for type T:
#[derive(Debug)]
pub struct PhysicalProof<T, ProofData> where
// `T` must implement `Debug`
T: Trait + Debug,
{
proof: ProofData,
date: T::BlockNumber,
}
A suggestion from Guillaume from substrate-technical Element chat that solved the problem:
in rust the code:
/// Structure that contains the proof
#[derive(Debug)]
pub struct PhysicalProof<T, ProofData> where
ProofData: Codec + Clone + Debug + Decode + Encode + Eq + PartialEq,
T: Trait,
{
proof: ProofData,
date: T::BlockNumber,
}
Will do impl<..> Debug for PhysicalPool<...> where ..., ProofData: Debug, T: Debug this additional bounds are unwanted in your situation, but rust add them anyway.
Thus when you try to use the stuct it says it doesn't implement Debug because T doesn't implement Debug.
One solution is to implmeent manually, another one would be to do:
/// Structure that contains the proof
#[derive(Debug)]
pub struct PhysicalProof<BlockNumber ProofData> where
ProofData: Codec + Clone + Debug + Decode + Encode + Eq + PartialEq, BLockNumber: ...
{
proof: ProofData,
date: BlockNumber,
}

Is it possible to store a Rust struct containing a closure in a different struct?

The Crius library provides
circuit-breaker-like functionality for Rust. Crius defines a struct called Command which looks like this:
pub struct Command<P, T, CMD>
where
T: Send,
CMD: Fn(P) -> Result<T, Box<CommandError>> + Sync + Send,
{
pub config: Option<Config>,
pub cmd: CMD,
phantom_data: PhantomData<P>,
}
Is it possible to store an instance of Command as a field in a different struct?
I started out trying to return a value of this type from a
function. Simply instantiating the type is no problem:
/// This function constructs a simple instance of `Command<P, T, CMD>` with the
/// types set to:
///
/// P ~ u8
/// T ~ u8
/// CMD: Fn(u8) -> Result<u8, Box<CommandError>> + Send + Sync
///
/// This function compiles fine. However, there is no *concrete* type
/// for `CMD`. In compiler output it will be referred to as an
/// "anonymous" type looking like this:
///
/// Command<u8, u8, [closure#src/lib.rs:19:21: 19:38]>
fn simple_command_instance() {
let _ = Command::define(|n: u8| Ok(n * 2));
}
It becomes more difficult when writing a return type for the
function:
fn return_command_instance() -> Command<u8, u8, ???> {
^
|
What goes here? -------
Command::define(|n: u8| Ok(n * 2))
}
The type inferred by the compiler is anonymous - it can't be put in
there. Many times when closures are passed around, people resort to
using a Box<F: Fn<...>>, however there is no implementation for
impl Fn<T> for Box<Fn<T>> - so boxing the type breaks the
constraints given by crius::command::Command.
In versions of Rust that have the new impl Trait feature (such as the
upcoming stable release), this is possible:
/// Use new `impl Trait` syntax as a type parameter in the return
/// type:
fn impl_trait_type_param() -> Command<u8, u8, impl Fn(u8) -> Result<u8, Box<CommandError>>> {
Command::define(|n: u8| Ok(n * 2))
}
This does not work in stable Rust and impl Trait can only
be used in return types, not in struct members.
Trying to propagate the generic type ends up looking something like
this:
fn return_cmd_struct<F>() -> Command<u8, u8, F>
where
F: Fn(u8) -> Result<u8, Box<CommandError>> + Send + Sync,
{
Command::define(|n: u8| Ok(n * 2))
}
But this does not compile:
error[E0308]: mismatched types
--> src/lib.rs:33:21
|
33 | Command::define(|n: u8| Ok(n * 2))
| ^^^^^^^^^^^^^^^^^ expected type parameter, found closure
|
= note: expected type `F`
found type `[closure#src/lib.rs:33:21: 33:38]`
Again, I don't know of a way to specify that concrete type in the
result signature.
Even if propagating the type as a generic parameter worked, it would
still be an issue for our specific use-case. We want to store a
Command as part of an actix actor which registers as a
SystemService, which requires a Default implementation, which
again eventually forces us to provide a concrete type.
If anyone has any ideas about possible ways to do this, please share
them. Definitely knowing that it isn't possible would also be nice.
I currently know of no way a closure may be used as part of a return type other than using impl or Box, both of which you have mentioned and cannot be used in this situation.
An alternative would be to use a function pointer instead of a closure, like so:
fn return_command_instance() -> Command<u8, u8, fn(u8) -> Result<u8, Box<CommandError>>> {
Command::define(|n: u8| Ok(n * 2))
}
Notice the lower case fn to signify a function pointer and not the trait Fn. This is explained in more details in the chapter on Advanced Functions & Closures.
This will only work if you do not capture any variables in the function, if you do it will be compiled into a closure.

Resources