Holochain Forum

Iterating through "hdk::query_result"

Hello there!
Thank you for taking the time to check my question out but being a complete Rust newbie, I’m struggling with a simple task and I can not seem to get it working, even after going through Rust’s documentation.

My question regards iterating through the output of hdk::query_result. I want to retrieve entries from my local chain of a certain type (Message, in my case). It is that simple. I have the following code, since I am only interested in the Entries field of QueryResults.

pub fn test() -> ZomeApiResult<Vec<Message>> {
    let mut return_vector = Vec::new();

    if let QueryResult::Entries(query_results) = hdk::query_result(
        MESSAGE_ENTRY_NAME.into(),
        QueryArgsOptions{ entries: true, headers: false, ..Default::default()}
    )? {
        for (_, Entry::App(_, entry_value)) in query_results.iter() {
            let message = Message::try_from(entry_value)?;
            return_vector.push(message)
        }

    } else {
        unreachable!()
    }

    Ok(return_vector)
}

But I have the following error:

error[E0005]: refutable pattern in `for` loop binding: `&(_, Dna(_))`, `&(_, AgentId(_))`, `&(_, Deletion(_))` and 7 more not covered
  --> src/message/handlers.rs:62:13
   |
62 |         for (_, Entry::App(_, entry_value)) in query_results.iter() {
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ patterns `&(_, Dna(_))`, `&(_, AgentId(_))`, `&(_, Deletion(_))` and 7 more not covered

I understand that I should match every pattern but is there a way to not do it? It seems that doing so makes the code quite confusing. I am only interested in the entry_value and return a vector with it, after all, right?

Any suggestions would be appreciated, thank you :slight_smile:

Hi @LuchoTurtle, this is the best I’ve found: https://www.reddit.com/r/rust/comments/2ln1r9/is_it_possible_to_destructure_enum_variants_in_a/. It seems rust doesn’t allow matching in the for statements.

Thank you for the answer @guillemcordoba! It’s a detail of Rust that I simply am not used to hehe.

Anyways, I’ve decided to destructure the tuple with an if let statement. Like so!

    // the returning vector holds a tuple of the Message and its corresponding Address
    let mut return_vector: Vec<(Address, Message)> = Vec::new();

    if let QueryResult::Entries(query_results) = hdk::query_result(
        MESSAGE_ENTRY_NAME.into(),
        QueryArgsOptions{ entries: true, headers: false, ..Default::default()}
    )? {
        for tuple in query_results.iter() {

            if let (entry_address, Entry::App(_, entry_value)) = tuple {
                let message = Message::try_from(entry_value)?;
                return_vector.push((entry_address.clone(), message))
            }

        }

    } else {
        unreachable!()
    }

    Ok(return_vector)

It worked for me, I guess :slight_smile: