use crate::clients::base::{list_resource, ResourceContext};
use crate::common::{PaginationList, QueryParams};
use crate::error::ApifyClientResult;
use crate::http_client::HttpClient;
use crate::models::ActorStoreListItem;
#[derive(Debug, Default, Clone)]
pub struct StoreListOptions {
pub offset: Option<i64>,
pub limit: Option<i64>,
pub search: Option<String>,
pub sort_by: Option<String>,
pub category: Option<String>,
pub username: Option<String>,
pub pricing_model: Option<String>,
pub include_unrunnable_actors: Option<bool>,
pub allows_agentic_users: Option<bool>,
pub response_format: Option<String>,
}
#[derive(Debug, Clone)]
pub struct StoreCollectionClient {
ctx: ResourceContext,
}
impl StoreCollectionClient {
pub(crate) fn new(http: HttpClient, base_url: &str) -> Self {
Self {
ctx: ResourceContext::collection(http, base_url, "store"),
}
}
pub async fn list(
&self,
options: StoreListOptions,
) -> ApifyClientResult<PaginationList<ActorStoreListItem>> {
let params = self.build_params(&options);
list_resource(&self.ctx, None, ¶ms).await
}
pub fn iterate(&self, options: StoreListOptions) -> StoreActorIterator {
StoreActorIterator {
client: self.clone(),
options,
buffer: std::collections::VecDeque::new(),
next_offset: 0,
total: None,
exhausted: false,
}
}
fn build_params(&self, options: &StoreListOptions) -> QueryParams {
let mut params = QueryParams::new();
params
.add_int("offset", options.offset)
.add_int("limit", options.limit)
.add_str("search", options.search.clone())
.add_str("sortBy", options.sort_by.clone())
.add_str("category", options.category.clone())
.add_str("username", options.username.clone())
.add_str("pricingModel", options.pricing_model.clone())
.add_bool("includeUnrunnableActors", options.include_unrunnable_actors)
.add_bool("allowsAgenticUsers", options.allows_agentic_users)
.add_str("responseFormat", options.response_format.clone());
params
}
}
pub struct StoreActorIterator {
client: StoreCollectionClient,
options: StoreListOptions,
buffer: std::collections::VecDeque<ActorStoreListItem>,
next_offset: i64,
total: Option<i64>,
exhausted: bool,
}
impl StoreActorIterator {
pub async fn next(&mut self) -> ApifyClientResult<Option<ActorStoreListItem>> {
if let Some(item) = self.buffer.pop_front() {
return Ok(Some(item));
}
if self.exhausted {
return Ok(None);
}
let start_offset = self.options.offset.unwrap_or(0) + self.next_offset;
let mut page_options = self.options.clone();
page_options.offset = Some(start_offset);
let page = self.client.list(page_options).await?;
if self.total.is_none() {
self.total = Some(page.total);
}
if page.items.is_empty() {
self.exhausted = true;
return Ok(None);
}
self.next_offset += page.items.len() as i64;
if let Some(total) = self.total {
if start_offset + page.items.len() as i64 >= total {
self.exhausted = true;
}
}
self.buffer.extend(page.items);
Ok(self.buffer.pop_front())
}
}