1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use chrono::NaiveDate;
use crate::{Client, RegionalData, Result, SeriesId};
/// A builder for a GeoFRED / Maps `series/data` request, returned by
/// [`Client::series_data`] — one regional series' values across regions, over
/// time.
///
/// Only `series_id` is required; with no date set FRED returns the most recent
/// date. Set an optional single [`date`](SeriesDataRequest::date) or a
/// [`start_date`](SeriesDataRequest::start_date) (which returns every date from
/// then on), and finish with [`send`](SeriesDataRequest::send).
///
/// ```no_run
/// # async fn run(client: &ferric_fred::Client) -> ferric_fred::Result<()> {
/// use ferric_fred::SeriesId;
/// let data = client
/// .series_data(&SeriesId::new("SMU56000000500000001"))
/// .send()
/// .await?;
/// println!("{} dates", data.meta.data.len());
/// # Ok(())
/// # }
/// ```
#[derive(Debug, Clone)]
#[must_use = "a SeriesDataRequest does nothing until you call `.send()`"]
pub struct SeriesDataRequest<'a> {
client: &'a Client,
series_id: SeriesId,
date: Option<NaiveDate>,
start_date: Option<NaiveDate>,
}
impl<'a> SeriesDataRequest<'a> {
pub(crate) fn new(client: &'a Client, series_id: SeriesId) -> Self {
Self {
client,
series_id,
date: None,
start_date: None,
}
}
/// Return data for a single date (`date`). With neither this nor
/// [`start_date`](Self::start_date) set, FRED returns the most recent date.
pub fn date(mut self, date: NaiveDate) -> Self {
self.date = Some(date);
self
}
/// Return data for every date from `start_date` onward.
pub fn start_date(mut self, start_date: NaiveDate) -> Self {
self.start_date = Some(start_date);
self
}
/// Run the request and return the regional data.
///
/// # Errors
///
/// Returns an error if the request fails to send, FRED returns a non-success
/// status, or the response body cannot be deserialized.
pub async fn send(self) -> Result<RegionalData> {
self.client.execute_series_data(&self).await
}
/// Serialize the set parameters to FRED query key/value pairs. `api_key` and
/// `file_type` are added by the client, not here.
pub(crate) fn query_params(&self) -> Vec<(&'static str, String)> {
let mut params: Vec<(&'static str, String)> = Vec::new();
params.push(("series_id", self.series_id.as_str().to_owned()));
if let Some(date) = self.date {
params.push(("date", date.to_string()));
}
if let Some(start_date) = self.start_date {
params.push(("start_date", start_date.to_string()));
}
params
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_client() -> Client {
Client::new("test-key").expect("client builds")
}
#[test]
fn defaults_send_only_the_series_id() {
let client = test_client();
let request = client.series_data(&SeriesId::new("SMU56000000500000001"));
assert_eq!(
request.query_params(),
vec![("series_id", "SMU56000000500000001".to_owned())]
);
}
#[test]
fn date_and_start_date_serialize() {
let client = test_client();
let request = client
.series_data(&SeriesId::new("SMU56000000500000001"))
.date(NaiveDate::from_ymd_opt(2013, 1, 1).unwrap())
.start_date(NaiveDate::from_ymd_opt(2010, 1, 1).unwrap());
let params = request.query_params();
for expected in [
("series_id", "SMU56000000500000001"),
("date", "2013-01-01"),
("start_date", "2010-01-01"),
] {
assert!(
params.contains(&(expected.0, expected.1.to_owned())),
"missing {expected:?} in {params:?}"
);
}
}
}