Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix(cli): backfill active-filtered markets and dedupe status helper
- Keep markets list filling up to --limit when --active is set by paginating additional API pages\n- Preserve independent active/closed semantics while avoiding undersized result pages\n- Move shared Option<bool> filter matcher into commands/mod.rs and reuse in events/markets\n- Add/retain tests and run full suite
  • Loading branch information
morluto committed Feb 24, 2026
commit 5949b7924b06c52d5868415b297dbc409d71fb09
6 changes: 1 addition & 5 deletions src/commands/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use polymarket_client_sdk::gamma::{
},
};

use super::is_numeric_id;
use super::{flag_matches, is_numeric_id};
use crate::output::events::{print_event_detail, print_events_table};
use crate::output::tags::print_tags_table;
use crate::output::{OutputFormat, print_json};
Expand Down Expand Up @@ -78,10 +78,6 @@ fn apply_status_filters(
.collect()
}

fn flag_matches(value: Option<bool>, filter: Option<bool>) -> bool {
filter.is_none_or(|expected| value == Some(expected))
}

pub async fn execute(client: &gamma::Client, args: EventsArgs, output: OutputFormat) -> Result<()> {
match args.command {
EventsCommand::List {
Expand Down
64 changes: 52 additions & 12 deletions src/commands/markets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use polymarket_client_sdk::gamma::{
},
};

use super::is_numeric_id;
use super::{flag_matches, is_numeric_id};
use crate::output::markets::{print_market_detail, print_markets_table};
use crate::output::tags::print_tags_table;
use crate::output::{OutputFormat, print_json};
Expand Down Expand Up @@ -87,8 +87,55 @@ fn apply_status_filters(
.collect()
}

fn flag_matches(value: Option<bool>, filter: Option<bool>) -> bool {
filter.is_none_or(|expected| value == Some(expected))
async fn list_markets(
client: &gamma::Client,
limit: i32,
offset: Option<i32>,
order: Option<String>,
ascending: bool,
active: Option<bool>,
closed: Option<bool>,
) -> Result<Vec<Market>> {
let page_size = limit.max(1);
let mut next_offset = offset.unwrap_or(0);
let mut collected: Vec<Market> = Vec::new();

loop {
let request = MarketsRequest::builder()
.limit(page_size)
.maybe_closed(closed)
.maybe_offset(Some(next_offset))
.maybe_order(order.clone())
.maybe_ascending(if ascending { Some(true) } else { None })
.build();

let page = client.markets(&request).await?;
if page.is_empty() {
break;
}

let raw_count = page.len();
collected.extend(apply_status_filters(page, active, closed));

if collected.len() >= page_size as usize {
collected.truncate(page_size as usize);
break;
}

// Without an active filter, the API-side limit should be authoritative.
if active.is_none() {
break;
}

// Reached end of available results from the backend.
if raw_count < page_size as usize {
break;
}

next_offset += raw_count as i32;
}

Ok(collected)
}

pub async fn execute(
Expand All @@ -105,15 +152,8 @@ pub async fn execute(
order,
ascending,
} => {
let request = MarketsRequest::builder()
.limit(limit)
.maybe_closed(closed)
.maybe_offset(offset)
.maybe_order(order)
.maybe_ascending(if ascending { Some(true) } else { None })
.build();

let markets = apply_status_filters(client.markets(&request).await?, active, closed);
let markets =
list_markets(client, limit, offset, order, ascending, active, closed).await?;

match output {
OutputFormat::Table => print_markets_table(&markets),
Expand Down
17 changes: 17 additions & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ pub fn parse_condition_id(s: &str) -> anyhow::Result<B256> {
.map_err(|_| anyhow::anyhow!("Invalid condition ID: must be a 0x-prefixed 32-byte hex"))
}

pub fn flag_matches(value: Option<bool>, filter: Option<bool>) -> bool {
filter.is_none_or(|expected| value == Some(expected))
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -87,4 +91,17 @@ mod tests {
let err = parse_condition_id("garbage").unwrap_err().to_string();
assert!(err.contains("32-byte"), "got: {err}");
}

#[test]
fn flag_matches_true_cases() {
assert!(flag_matches(Some(true), Some(true)));
assert!(flag_matches(Some(false), Some(false)));
assert!(flag_matches(Some(true), None));
}

#[test]
fn flag_matches_false_cases() {
assert!(!flag_matches(Some(true), Some(false)));
assert!(!flag_matches(None, Some(true)));
}
}