1
votes

Desired code: The commented out block compiles and works, however I'd like to move from nested matching style to a cleaner chain of functions

async fn ws_req_resp(msg: String, conn: PgConn) -> Result<String, Box<dyn std::error::Error>>{
    let req: WSReq = serde_json::from_str(&msg)?;

    match req.request_type{
        "upsert_competitions" => {
            // let dr = serde_json::from_value(req.data);
            // match dr{
            //     Ok(d) => match upsert_competitions(conn, d).await{
            //         Ok(x) => serde_json::to_string(&x).map_err(|e| e.into()),
            //         Err(e) => Err(Box::new(e))
            //         }
            //     Err(e) => Err(Box::new(e))
            // }
            serde_json::from_value(req.data).and_then(|d| async move {
                upsert_competitions(conn, d).await}).and_then(|r| serde_json::to_string(&r))
                .map_err(|e| e.into())
        },
        uwotm8 => {
            Err(Box::new(InvalidRequestError{req_type: uwotm8.to_string()}))
        }
    }
}

upsert_competitions signature pub async fn upsert_competitions(conn: PgConn, new: Vec<ApiNewCompetition>) -> Result<Vec<DbCompetition>, diesel::result::Error>

Error:

expected enum `std::result::Result<_, serde_json::error::Error>`
           found opaque type `impl core::future::future::Future`

Have tried putting the await in multiple places in chain and none compile. Believe awaiting a future should sit until it's finished, then return the result.

(It might be better for me to return a future from this function; and unwrap outside. However I do not understand why the await in the chain is failing, so clearly I'm lacking understanding...also trying to return a future I run into issues with compiler not knowing Size of return)

Full code https://github.com/open-fantasy-sports/fantasy-sport-api-rust/blob/ef9db156efa8dbc159eae1c80fb7ac0a6a3ddee3/result_server/src/main.rs#L63

1

1 Answers

0
votes

Someone told me can't use await in function chains like this.

When I switched to returning a Box<dyn std::error::Error + Sync + Send + 'static> error-type. Then I was able to use ? operator successfully again for central code (previously think it was failing due to ambiguous error return type).

So even without function changing could use this syntax to make code nice and readable.

updated code:

pub async fn upsert_competitions(req: WSReq, conn: PgConn, ws_conns: &mut WSConnections_, user_ws_id: Uuid) -> Result<String, BoxError>{
    let deserialized: Vec<NewCompetition> = serde_json::from_value(req.data)?;
    let competitions_out= db::upsert_competitions(&conn, deserialized.into_iter().map(transform_from).collect_vec())?;
    if let Some(ws_user) = ws_conns.lock().await.get_mut(&user_ws_id){
        sub_to_competitions(ws_user, competitions_out.iter().map(|c| &c.competition_id)).await;
    }
    publish_competitions(ws_conns, &competitions_out).await;
    let resp_msg = WSMsgOut::resp(req.message_id, req.method, competitions_out);
    serde_json::to_string(&resp_msg).map_err(|e| e.into())
}