apify_client/clients/run_collection.rs
1//! Client for an Actor-run collection (`/v2/actor-runs`, `/v2/actors/{id}/runs`, etc.).
2
3use crate::clients::base::{list_resource, ResourceContext};
4use crate::clients::pagination::ListIterator;
5use crate::common::{ListOptions, PaginationList, QueryParams};
6use crate::error::ApifyClientResult;
7use crate::http_client::HttpClient;
8use crate::models::ActorRun;
9
10/// Filtering options for [`RunCollectionClient::list`], covering the spec query parameters of
11/// `GET /v2/actor-runs` and `GET /v2/actors/{actorId}/runs`.
12///
13/// As in the reference client, the same options type is reused for the task-scoped run
14/// collection (`GET /v2/actor-tasks/{actorTaskId}/runs`), whose spec does not define
15/// `startedAfter`/`startedBefore`; those params are simply ignored server-side when set on a
16/// task-scoped list. This deliberate reference-parity reuse keeps the API surface uniform.
17#[derive(Debug, Default, Clone)]
18pub struct RunListOptions {
19 /// Only return runs with one of these statuses (e.g. `SUCCEEDED`, `RUNNING`). The API
20 /// accepts multiple statuses; they are sent as a comma-separated list. Empty means no
21 /// status filter. Matches the reference client, whose `status` accepts a string or array.
22 pub status: Vec<String>,
23 /// Only return runs started at or after this ISO 8601 timestamp. (Actor-scoped lists only.)
24 pub started_after: Option<String>,
25 /// Only return runs started at or before this ISO 8601 timestamp. (Actor-scoped lists only.)
26 pub started_before: Option<String>,
27}
28
29/// Client for listing Actor runs.
30#[derive(Debug, Clone)]
31pub struct RunCollectionClient {
32 ctx: ResourceContext,
33}
34
35impl RunCollectionClient {
36 pub(crate) fn new(http: HttpClient, base_url: &str, resource_path: &str) -> Self {
37 Self {
38 ctx: ResourceContext::collection(http, base_url, resource_path),
39 }
40 }
41
42 /// Lists runs with offset/limit pagination and optional status/started-time filtering.
43 ///
44 /// Unlike other collections, run listing takes two arguments: the shared [`ListOptions`]
45 /// (offset/limit/desc) and a [`RunListOptions`] filter (status and start-time bounds).
46 ///
47 /// # Example
48 /// ```no_run
49 /// use apify_client::{ApifyClient, ListOptions, RunListOptions};
50 ///
51 /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
52 /// let client = ApifyClient::new("my-api-token");
53 /// let runs = client
54 /// .runs()
55 /// .list(
56 /// ListOptions { limit: Some(10), desc: Some(true), ..Default::default() },
57 /// RunListOptions { status: vec!["SUCCEEDED".to_string()], ..Default::default() },
58 /// )
59 /// .await?;
60 /// for run in runs.items {
61 /// println!("{}", run.id);
62 /// }
63 /// # Ok(())
64 /// # }
65 /// ```
66 pub async fn list(
67 &self,
68 options: ListOptions,
69 filter: RunListOptions,
70 ) -> ApifyClientResult<PaginationList<ActorRun>> {
71 let mut params = QueryParams::new();
72 params
73 .add_int("offset", options.offset)
74 .add_int("limit", options.limit)
75 .add_bool("desc", options.desc)
76 .add_csv("status", Some(&filter.status))
77 .add_str("startedAfter", filter.started_after)
78 .add_str("startedBefore", filter.started_before);
79 list_resource(&self.ctx, None, ¶ms).await
80 }
81
82 /// Lazily iterates over all runs matching `options`/`filter`, fetching pages on demand.
83 ///
84 /// The idiomatic-Rust counterpart of the reference client's async-iterable run listing;
85 /// yields one [`ActorRun`] at a time across all pages.
86 ///
87 /// `options.limit` caps the *total* number of runs yielded across all pages, unlike
88 /// [`list`](Self::list) where `limit` is a single page's size. Set the per-page fetch size
89 /// with [`with_chunk_size`](crate::ListIterator::with_chunk_size); see
90 /// [`ListIterator`] for details.
91 pub fn iterate(&self, options: ListOptions, filter: RunListOptions) -> ListIterator<ActorRun> {
92 let client = self.clone();
93 let start = options.offset.unwrap_or(0);
94 let total_limit = options.limit;
95 ListIterator::new(
96 start,
97 total_limit,
98 Box::new(move |offset, page_limit| {
99 let client = client.clone();
100 let mut options = options.clone();
101 let filter = filter.clone();
102 options.offset = Some(offset);
103 options.limit = page_limit;
104 Box::pin(async move { client.list(options, filter).await })
105 }),
106 )
107 }
108}