I am trying to migrate an application from rocket 0.4 to rocket 0.5 Before it was using rocket_contrib feature diesel_postgres_pool and I though rocket_sync_db_pools would be the best fit for migration (but I am open to alternatives here)
I tried to change the code like this:
- let quality = subjects::table
- .find(&sub)
- .select(subjects::quality)
- .first::<i16>(&conn.0)
- .ok();
+ let quality = conn.run( move |conn| {
+ subjects::table
+ .find(&sub)
+ .select(subjects::quality)
+ .first::<i16>(conn)
+ .ok();
+ });
But now I am not getting the actual result but a Promise.
The documentation suggests to use .await
which seems to cause that the calling func needs to be async, too. But I cannot do this, because the code is also used in traits, which cannot be async easily.
I am pretty new to rust and don't understand two (or more) things:
- Why does my function have to be async if we are waiting for the result (with await)?
- Why does the sync DB pool return async promises / need async functions.
Is this the right approach?
What are the alternatives to fix this without rebuilding the full application?
EDIT
This is a step forward, after importing async_trait.
#[async_trait]
impl Statistic for Subject {
async fn compute(conn: &DbConn, sub: String) -> Result<Self, Error> {
[...]
let quality = conn.run( move |conn| {
return subjects::table
.find(&sub)
.select(subjects::quality)
.first::<i16>(conn)
.ok();
}).await;
But it seems to bring problems on the callee of compute:
identifiers
.map(|identifier| {
Self::compute(&conn, identifier.clone()).map(|statistic| (identifier, statistic))
})
.collect()
Causes an error:
23 | Self::compute(&conn, identifier.clone()).map(|statistic| (identifier, statistic))
| ^^^ `Pin<Box<dyn std::future::Future<Output = Result<Self, error::Error>> + std::marker::Send>>` is not an iterator
EDIT2: I might not need the async_trait crate, as rocket already supplies such a solution: https://rocket.rs/master/guide/upgrading-from-0.4/#async-traits
EDIT3: So I tried:
identifiers
.map(async move |identifier| {
join_all(Self::compute(&conn, identifier.clone())).await.map(|statistic| (identifier, statistic))
})
.collect()
This leads to a new error :-)
error[E0658]: async closures are unstable
--> src/aggregator.rs:23:18
|
23 | .map(async move |identifier| {
| ^^^^^
|
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
= help: to use an async block, remove the `||`: `async {`
EDIT4:
After trying pigeonhands answer with this code:
let quality = Handle::current().block_on(async move {
conn.run(move |conn| {
subjects::table
.find(&sub)
.select(subjects::quality)
.first::<i16>(conn)
.ok();
})
});
Ok(Subject {
sub,
quality,
count,
opinion_count,
positive_count,
confirmed_count,
})
I am getting
error[E0308]: mismatched types
--> src/aggregator.rs:84:13
|
74 | conn.run(move |conn| {
| ----------- the found closure
...
84 | quality,
| ^^^^^^^ expected enum `std::option::Option`, found opaque type