Actix and Diesel - passing a closure utilizing QueryDsl?

Viewed 55

I'm using Actix and Diesel. The way I set it up is that I have a DbExecutor - an async worker which takes messages and returns the results of the queries they represent, like so:

#[derive(Message)]
#[rtype(result = "Result<User>")]
pub struct RetrieveUser {
    pub uid: i64,
}

impl Handler<RetrieveUser> for DbExecutor {
  // ...
  fn handle(&mut self, msg: InsertFile, _: &mut Self::Context) -> Self::Result {
      use crate::schema::users::dsl::*;
      // ...
      Ok(users.filter(uid.eq(msg.uid)).execute(connection))
  }
}

fn my_route_handler() {
    db_executor.send(RetrieveUser{ uid: 123 });
    //...
}

However, there is a table which doesn't fit neatly into these simple queries, and I would like to specify the filters from the side of the message sender. I was thinking I could send a message containing a closure which takes the users object, and then execute it on the side of the DbExecutor, returning the results:

fn my_ideal_route_handler(){
   db_executor.send(RetrieveUsers { predicate: |users| users.filter(uid.eq(123)) });
}

However, I am stuck, seeing as all Messages have to implement Copy, and the Diesel types are confusing - I am not sure how to specify the type I need generically enough, while getting it to compile, eg.:

// FAILS

#[derive(Message)]
#[rtype(result = "Result<Vec<User>>")]
pub struct RetrieveUsers {
    pub predicate: dyn FnOnce(dyn QueryDsl) -> dyn RunQueryDsl<PgConnection>,
}

I am also not sure whether this approach is even sensible at all, so I am open to other suggestions which would:

  • allow me to query the table dynamically
  • still keep most of the database handling separate and not all across the project as if I were passing the plain database connection around
  • (ideally) utilize concurrent access to the database
0 Answers
Related