diff --git a/contracts/client/src/handlers/query.rs b/contracts/client/src/handlers/query.rs index a6d051d..90c6811 100644 --- a/contracts/client/src/handlers/query.rs +++ b/contracts/client/src/handlers/query.rs @@ -1,5 +1,6 @@ use abstract_app::sdk::cw_helpers::load_many; use cosmwasm_std::{to_json_binary, Binary, Deps, Env, Order, StdResult}; +use cw_paginate::{DEFAULT_LIMIT, MAX_LIMIT}; use cw_storage_plus::Bound; use ibcmail::{ client::{ @@ -7,7 +8,7 @@ use ibcmail::{ msg::{MessageFilter, MessagesResponse}, state::{RECEIVED, SENT}, }, - MessageId, MessageStatus, + Message, MessageId, MessageStatus, }; use crate::{ @@ -57,13 +58,16 @@ fn query_messages( let messages = load_many(map, deps.storage, ids)?; let messages = messages.into_iter().map(|(_, m)| m).collect(); - Ok(MessagesResponse { messages }) + Ok(MessagesResponse { + messages, + next_key: None, + }) } fn query_messages_list( deps: Deps, status: MessageStatus, - _filter: Option, + filter: Option, start: Option, limit: Option, ) -> ClientResult { @@ -73,23 +77,77 @@ fn query_messages_list( _ => return Err(ClientError::NotImplemented("message type".to_string())), }; - let messages = cw_paginate::paginate_map( - &map, - deps.storage, - start.as_ref().map(Bound::exclusive), - limit, - |_id, message| Ok::<_, ClientError>(message), - )?; + // Apply the filter on the map + let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; + + let response = { + // Used to get the next key + let mut next_key = None; + // Messages that pass the filter + let mut messages = vec![]; + // Total number of messages analyzed (used on to make sure there might be future results) + let mut queried_messages_nb = 0; + + for i in map + .range( + deps.storage, + start.as_ref().map(Bound::exclusive), + None, + Order::Ascending, + ) + .take(limit) + { + queried_messages_nb += 1; + let (_, message) = i?; + next_key = Some(message.id.clone()); + + if !matches_filter(&filter, &message)? { + continue; + } + + messages.push(message); + } + + // If there is less results than the expected limit, that means we have exhausted the map + if queried_messages_nb != limit { + next_key = None; + } + + MessagesResponse { messages, next_key } + }; // TODO REMOVE, This could run out of gas let len = map.keys(deps.storage, None, None, Order::Ascending).count(); - println!("Messages: {:?}, len: {:?}", messages, len); + println!("Messages Response: {:?}, len: {:?}", response, len); - Ok(MessagesResponse { messages }) + Ok(response) } fn query_config(deps: Deps) -> StdResult { let _config = CONFIG.load(deps.storage)?; Ok(ConfigResponse {}) } + +// Keeping a result here in case we need to parse things or use Addr in the future +/// Verifies that the given message matches the filter, if any +fn matches_filter(filter: &Option, message: &Message) -> StdResult { + if let Some(filter) = &filter { + if let Some(sender) = &filter.from { + if message.sender != *sender { + return Ok(false); + } + } + if let Some(contains) = &filter.contains { + if !message.body.contains(contains) && !message.subject.contains(contains) { + return Ok(false); + } + } + if let Some(sent_after) = &filter.sent_after { + if message.timestamp.nanos() < sent_after.nanos() { + return Ok(false); + } + } + } + Ok(true) +} diff --git a/packages/ibcmail/src/client/msg.rs b/packages/ibcmail/src/client/msg.rs index cf486fd..82066b7 100644 --- a/packages/ibcmail/src/client/msg.rs +++ b/packages/ibcmail/src/client/msg.rs @@ -1,4 +1,5 @@ use cosmwasm_schema::QueryResponses; +use cosmwasm_std::Timestamp; use crate::{client::ClientApp, Message, MessageId, MessageStatus, NewMessage, Route, Sender}; @@ -51,6 +52,8 @@ pub enum ClientQueryMsg { #[cosmwasm_schema::cw_serde] pub struct MessageFilter { pub from: Option, + pub contains: Option, + pub sent_after: Option, } #[cosmwasm_schema::cw_serde] @@ -62,4 +65,5 @@ pub struct ConfigResponse {} #[cosmwasm_schema::cw_serde] pub struct MessagesResponse { pub messages: Vec, + pub next_key: Option, }