Skip to main content

ferric_fred/
releases_request.rs

1use crate::{Client, ReleasesResults, Result, SortOrder};
2
3/// A builder for the release-listing endpoints, returned by
4/// [`Client::releases`] (`fred/releases`, all data releases) and
5/// [`Client::source_releases`] (`fred/source/releases`, the releases of one
6/// source). Both share optional sort and paging and return [`ReleasesResults`];
7/// `source_releases` additionally carries the `source_id`. Finish with
8/// [`send`](ReleasesRequest::send).
9///
10/// ```no_run
11/// # async fn run(client: &ferric_fred::Client) -> ferric_fred::Result<()> {
12/// let results = client.releases().limit(20).send().await?;
13/// println!("{} releases", results.count);
14/// # Ok(())
15/// # }
16/// ```
17#[derive(Debug, Clone)]
18#[must_use = "a ReleasesRequest does nothing until you call `.send()`"]
19pub struct ReleasesRequest<'a> {
20    client: &'a Client,
21    /// The endpoint path, `/releases` or `/source/releases`.
22    path: &'static str,
23    /// FRED's `source_id`; required by `/source/releases`, absent for
24    /// `/releases`.
25    source_id: Option<String>,
26    sort_order: Option<SortOrder>,
27    limit: Option<u32>,
28    offset: Option<u32>,
29}
30
31impl<'a> ReleasesRequest<'a> {
32    pub(crate) fn new(client: &'a Client, path: &'static str) -> Self {
33        Self {
34            client,
35            path,
36            source_id: None,
37            sort_order: None,
38            limit: None,
39            offset: None,
40        }
41    }
42
43    /// Construct a request for `/source/releases` filtered to one source.
44    pub(crate) fn with_source(client: &'a Client, path: &'static str, source_id: String) -> Self {
45        Self {
46            source_id: Some(source_id),
47            ..Self::new(client, path)
48        }
49    }
50
51    /// The endpoint path this request targets (used by the client to dispatch).
52    pub(crate) fn path(&self) -> &'static str {
53        self.path
54    }
55
56    /// Sort order of the results by release id (`sort_order`).
57    pub fn sort_order(mut self, order: SortOrder) -> Self {
58        self.sort_order = Some(order);
59        self
60    }
61
62    /// Maximum number of results to return, `1..=1000` (`limit`).
63    pub fn limit(mut self, limit: u32) -> Self {
64        self.limit = Some(limit);
65        self
66    }
67
68    /// Number of results to skip from the start (`offset`), for paging.
69    pub fn offset(mut self, offset: u32) -> Self {
70        self.offset = Some(offset);
71        self
72    }
73
74    /// Run the request and return a page of releases with pagination metadata.
75    ///
76    /// # Errors
77    ///
78    /// Returns an error if the request fails to send, FRED returns a non-success
79    /// status, or the response body cannot be deserialized.
80    pub async fn send(self) -> Result<ReleasesResults> {
81        self.client.execute_releases(&self).await
82    }
83
84    /// Serialize the set parameters to FRED query key/value pairs. `api_key` and
85    /// `file_type` are added by the client, not here.
86    pub(crate) fn query_params(&self) -> Vec<(&'static str, String)> {
87        let mut params: Vec<(&'static str, String)> = Vec::new();
88        if let Some(source_id) = &self.source_id {
89            params.push(("source_id", source_id.clone()));
90        }
91        if let Some(order) = self.sort_order {
92            params.push(("sort_order", order.query_code().to_owned()));
93        }
94        if let Some(limit) = self.limit {
95            params.push(("limit", limit.to_string()));
96        }
97        if let Some(offset) = self.offset {
98            params.push(("offset", offset.to_string()));
99        }
100        params
101    }
102}
103
104impl crate::paginate::sealed::Sealed for ReleasesRequest<'_> {}
105impl crate::paginate::Paginate for ReleasesRequest<'_> {
106    type Page = ReleasesResults;
107    const MAX_PAGE: u32 = 1000;
108    fn requested_limit(&self) -> Option<u32> {
109        self.limit
110    }
111    fn requested_offset(&self) -> Option<u32> {
112        self.offset
113    }
114    fn with_paging(self, limit: u32, offset: u32) -> Self {
115        self.limit(limit).offset(offset)
116    }
117    fn send_page(self) -> impl std::future::Future<Output = Result<Self::Page>> + Send {
118        self.send()
119    }
120}