fred_rs/series/updates.rs
1//! Get economic data series sorted by when observations were updated on the FREDĀ® server
2//!
3//! [https://research.stlouisfed.org/docs/api/fred/series_updates.html](https://research.stlouisfed.org/docs/api/fred/series_updates.html)
4//!
5//! ```
6//! use fred_rs::client::FredClient;
7//! use fred_rs::series::updates::{Builder, Response};
8//!
9//! let mut c = match FredClient::new() {
10//! Ok(c) => c,
11//! Err(msg) => {
12//! println!("{}", msg);
13//! assert_eq!(2, 1);
14//! return
15//! },
16//! };
17//!
18//! let mut builder = Builder::new();
19//! builder
20//! .limit(5);
21//!
22//! let resp: Response = match c.series_updates(Some(builder)) {
23//! Ok(resp) => resp,
24//! Err(msg) => {
25//! println!("{}", msg);
26//! assert_eq!(2, 1);
27//! return
28//! },
29//! };
30//!
31//! for item in resp.seriess {
32//! println!(
33//! "{}: {} {}",
34//! item.title,
35//! item.id,
36//! item.popularity,
37//! );
38//! }
39//! ```
40
41use serde::Deserialize;
42use std::fmt::{self, Display, Formatter};
43
44use crate::series::Series;
45
46#[derive(Deserialize, Clone, Debug, Default)]
47/// Response data structure for the fred/series/updates endpoint
48///
49/// [https://research.stlouisfed.org/docs/api/fred/series_updates.html] (https://research.stlouisfed.org/docs/api/fred/series_updates.html)
50pub struct Response {
51 /// The Real Time start date for the request
52 pub realtime_start: String,
53 /// The Real Time end data for the request
54 pub realtime_end: String,
55 /// What variable the requested wass filtered with
56 pub filter_variable: String,
57 /// Value that must match the filter field to include a result
58 pub filter_value: String,
59 /// How the results are ordered
60 pub order_by: String,
61 // Results are listed in ascending or descending
62 pub sort_order: String,
63 /// Number of results returned
64 pub count: usize,
65 /// ???
66 pub offset: usize,
67 /// Maximum number of results to return
68 pub limit: usize,
69 /// Series returned by the search
70 pub seriess: Vec<Series>,
71}
72
73impl Display for Response {
74 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
75 for item in self.seriess.iter() {
76 match item.fmt(f) {
77 Ok(_) => (),
78 Err(e) => return Err(e),
79 }
80 match writeln!(f, "") {
81 Ok(_) => (),
82 Err(e) => return Err(e),
83 }
84 }
85 Ok(())
86 }
87}
88
89/// Used to filter series included in the results
90///
91/// [https://research.stlouisfed.org/docs/api/fred/series_updates.html#filter_value](https://research.stlouisfed.org/docs/api/fred/series_updates.html#filter_value)
92pub enum FilterValue {
93 /// Macroeconomic data series
94 Macro,
95 /// Regional data series
96 Regional,
97 /// (Default) All data series
98 All,
99}
100
101pub struct Builder {
102 option_string: String,
103}
104
105impl Builder {
106
107 /// Initializes a new series::updates::Builder that can be used to add commands to an API request
108 ///
109 /// The builder does not do validity checking of the arguments nor does it check for duplicates.
110 ///
111 /// ```
112 /// use fred_rs::series::updates::Builder;
113 /// // Create a new builder
114 /// let mut builder = Builder::new();
115 /// // add arguments to the builder
116 /// builder
117 /// .realtime_start("1900-01-01")
118 /// .realtime_end("2000-01-01");
119 /// ```
120 pub fn new() -> Builder {
121 Builder {
122 option_string: String::new(),
123 }
124 }
125
126 /// Returns the current arguments as a URL formatted string
127 ///
128 /// Returns Err if there are no tag names specified using tag_name().
129 pub(crate) fn build(self) -> String {
130 self.option_string
131 }
132
133 /// Adds a realtime_start argument to the builder
134 ///
135 /// # Arguments
136 /// * `start_date` - date formatted as YYYY-MM-DD
137 ///
138 /// [https://research.stlouisfed.org/docs/api/fred/series_updates.html#realtime_start](https://research.stlouisfed.org/docs/api/fred/series_updates.html#realtime_start)
139 pub fn realtime_start(&mut self, start_date: &str) -> &mut Builder {
140 self.option_string += format!("&realtime_start={}", start_date).as_str();
141 self
142 }
143
144 /// Adds a realtime_end argument to the builder
145 ///
146 /// # Arguments
147 /// * `end_date` - date formatted as YYYY-MM-DD
148 pub fn realtime_end(&mut self, end_date: &str) -> &mut Builder {
149 self.option_string += format!("&realtime_end={}", end_date).as_str();
150 self
151 }
152
153 /// Adds a limit argument to the builder
154 ///
155 /// The limit argument specifies a maximum number of observations to return.
156 ///
157 /// # Arguments
158 /// * `num_results` - Maximum number of results to return
159 ///
160 /// [https://research.stlouisfed.org/docs/api/fred/series_updates.html#realtime_end](https://research.stlouisfed.org/docs/api/fred/series_updates.html#realtime_end)
161 pub fn limit(&mut self, num_results: usize) -> &mut Builder {
162 let num_results = if num_results > 1000 { // max value is 1000
163 1000
164 } else {
165 num_results
166 };
167 self.option_string += format!("&limit={}", num_results).as_str();
168 self
169 }
170
171 /// Adds an offset argument to the builder
172 ///
173 /// Adding an offset shifts the starting result number. For example, if limit is 5 and offset is 0 then results 1-5 will be returned, but if offset was 5 then results 6-10 would be returned.
174 ///
175 /// # Arguments
176 /// * `ofs` - the offset amount
177 ///
178 /// [https://research.stlouisfed.org/docs/api/fred/series_updates.html#offset](https://research.stlouisfed.org/docs/api/fred/series_updates.html#offset)
179 pub fn offset(&mut self, ofs: usize) -> &mut Builder {
180 self.option_string += format!("&offset={}", ofs).as_str();
181 self
182 }
183
184 /// Adds the filter_value argument to the request
185 ///
186 /// # Arguments
187 /// * `value` - value with which to filter results
188 ///
189 /// [https://research.stlouisfed.org/docs/api/fred/series_updates.html#filter_value](https://research.stlouisfed.org/docs/api/fred/series_updates.html#filter_value)
190 pub fn filter_value(&mut self, value: FilterValue) -> &mut Builder {
191 match value {
192 FilterValue::Macro => {
193 self.option_string += "&filter_value=macro";
194 },
195 FilterValue::Regional => {
196 self.option_string += "&filter_value=regional";
197 },
198 _ => (), // All is default so do nothing
199 };
200 self
201 }
202
203 /// Limit results to a certian time range
204 ///
205 /// Both a start and end time must be specified together as per the API docs.
206 ///
207 /// # Arguments
208 /// * `start_time` - Start time to limit results to (YYYYMMDDHhmm format)
209 /// * `end_time` - End time to limit results to (YYYYMMDDHhmm format)
210 ///
211 /// [https://research.stlouisfed.org/docs/api/fred/series_updates.html#start_time](https://research.stlouisfed.org/docs/api/fred/series_updates.html#start_time)
212 ///
213 /// [https://research.stlouisfed.org/docs/api/fred/series_updates.html#end_time](https://research.stlouisfed.org/docs/api/fred/series_updates.html#end_time)
214 pub fn time_range(&mut self, start_time: &str, end_time: &str) -> &mut Builder {
215 self.option_string += format!(
216 "&start_time={}&end_time={}",
217 start_time,
218 end_time
219 ).as_str();
220 self
221 }
222
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228 use crate::client::FredClient;
229
230 #[test]
231 fn series_updates_with_options() {
232 let mut c = match FredClient::new() {
233 Ok(c) => c,
234 Err(msg) => {
235 println!("{}", msg);
236 assert_eq!(2, 1);
237 return
238 },
239 };
240
241 let mut builder = Builder::new();
242 builder
243 .limit(5);
244
245 let resp: Response = match c.series_updates(Some(builder)) {
246 Ok(resp) => resp,
247 Err(msg) => {
248 println!("{}", msg);
249 assert_eq!(2, 1);
250 return
251 },
252 };
253
254 for item in resp.seriess {
255 println!(
256 "{}: {} {}",
257 item.title,
258 item.id,
259 item.popularity,
260 );
261 }
262 }
263}