How to correctly move values into a earlier created vec from a while loop?

I am trying to push users from a while loop into a mutable Vec. The println! inside the
while loop show that the users variable is being filled and is growing.

But when I afterwards want to send it out via Ok(users) it's empty. What I am doing wrong?
Help would be appreciated.

async fn get_all_users(pgpool: Arc<PgPool>) -> Result<Vec<User>, Error> {
    let mut users: Vec<User> = Vec::new();
    let mut incoming = sqlx::query_as::<_, User>(
        r#"
SELECT user_id, first_name, last_name, telephone_number, email_address FROM "user"
        "#,
    )
    .fetch(&*pgpool);

    while let Ok(user) = incoming.try_next().await {
        if let Some(user) = user {
            users.push(user);
            println!("The updated users get_all_users {:?}", &users);
        }
    }
    if !users.is_empty() {
        println!("users is not empty: {:?}", &users);
        Ok(users)
    } else {
        println!("users is empty");
        Err(Error::DbError)
    }
}

I can’t see anything wrong. Maybe start with double-checking that the code you posted is exactly the code you've ran?

E.g. double-check that what you posted here is an accurate copy-paste with no manual edits that could remove the mistake; tweak the printed messages in a noticeable way, and check that those changes are visible when executing, so you can rule out that you just missed saving the files and/or re-building your project, or you're editing a different clone of your project than the one you're executing, or things like that.

1 Like

Perhaps you could also clarify what exactly you mean by this. On first read I’ve assumed that you mean you’re hitting the users is empty case/printout (because you mentioned, for contrast, explicitly only the “println! in the while loop”), but if you instead are speaking of observed program behavior around the call site of get_all_users, then your mistake could of course simply be there, right?

1 Like

This looks wrong to me. You probably want

while let Some(user) = incoming.try_next().await? {
    users.push(user);
    println!("The updated users get_all_users {:?}", &users);
}

Your version continues until there is an error.

2 Likes

Thanks for the suggestion. The try_next gives a Result, so I still need to use Ok first. This in turn returns an Option. Is this correct?

 while let Ok(user_incoming) = incoming.try_next().await {
        if let Some(user_incoming) = user_incoming {
            let _ = &users.push(user_incoming);
        } else {
            break;
        }
    }

The break: leaves the while loop and then I should be able to return the users wrapped in Ok, `Ok(users).

@Bruecki Thanks you for your advice. I finally understood my error in logic. This is what finally worked.

async fn get_all_user(pgpool: &PgPool) -> Result<Vec<User>, anyhow::Error> {
    let mut users: Vec<User> = Vec::new();
    // Here we are getting one user at a time, so we expect a User and not a Vec<User>
    let mut records = sqlx::query_as::<_, User>(
        r#"
SELECT user_id, first_name, last_name, telephone_number, email_address from "user"
        "#,
    )
    .fetch(pgpool);

    while let Some(record) = &records.try_next().await? {
        let _ = &users.push(record.clone());
    }
    Ok(users)
}

Thanks a lot!