fred_rs/category/
series.rs

1//! Get the series in a category
2//! 
3//! [https://research.stlouisfed.org/docs/api/fred/category_series.html](https://research.stlouisfed.org/docs/api/fred/category_series.html)
4//! 
5//! ```
6//! use fred_rs::client::FredClient;
7//! use fred_rs::category::series::{Builder, OrderBy, SortOrder};
8//! use fred_rs::series::Response;
9//! 
10//! let mut c = match FredClient::new() {
11//!     Ok(c) => c,
12//!     Err(msg) => {
13//!         println!("{}", msg);
14//!         assert_eq!(2, 1);
15//!         return
16//!     },
17//! };
18//! 
19//! let mut builder = Builder::new();
20//! builder
21//!     .limit(5)
22//!     .sort_order(SortOrder::Descending)
23//!     .order_by(OrderBy::Frequency);
24//! 
25//! let resp: Response = match c.category_series(125, Some(builder)) {
26//!     Ok(resp) => resp,
27//!     Err(msg) => {
28//!         println!("{}", msg);
29//!         assert_eq!(2, 1);
30//!         return
31//!     },
32//! };
33//! 
34//! for item in resp.seriess {
35//!     println!(
36//!         "{}: {} {}",
37//!         item.id,
38//!         item.title,
39//!         item.popularity,
40//!     );
41//! }
42//! ```
43
44/// Determines the order of search results
45/// 
46/// [https://research.stlouisfed.org/docs/api/fred/category_series.html#order_by](https://research.stlouisfed.org/docs/api/fred/category_series.html#order_by)
47pub enum OrderBy {
48    /// Default
49    SeriesId,
50    Title,
51    Units,
52    Frequency,
53    SeasonalAdjustment,
54    RealtimeStart,
55    RealtimeEnd,
56    LastUpdated,
57    ObservationStart,
58    ObservationEnd,
59    Popularity,
60    GroupPopularity,
61}
62
63/// Sort order options for the fred/category/series endpoint
64/// 
65/// [https://research.stlouisfed.org/docs/api/fred/category_series.html#sort_order](https://research.stlouisfed.org/docs/api/fred/category_series.html#sort_order)
66pub enum SortOrder {
67    /// Dates returned in ascending order (default)
68    Ascending,    
69    /// Dates returned in descending order
70    Descending,   
71}
72
73/// Apply result filter
74/// 
75/// This should be used in conjunction with the filter_value argument to filter results based on one (maybe more than one?) of the fields.
76/// 
77/// [https://research.stlouisfed.org/docs/api/fred/category_series.html#filter_variable](https://research.stlouisfed.org/docs/api/fred/category_series.html#filter_variable)
78pub enum FilterVariable {
79    Frequency,
80    Units,
81    SeasonalAdjustment,
82}
83
84pub struct Builder {
85    option_string: String,
86    include_tags: String,
87    exclude_tags: String,
88}
89
90impl Builder {
91
92    /// Initializes a new category::series::Builder that can be used to add commands to an API request
93    /// 
94    /// The builder does not do validity checking of the arguments nor does it check for duplicates.
95    /// 
96    /// ```
97    /// use fred_rs::category::series::Builder;
98    /// // Create a new builder
99    /// let mut builder = Builder::new();
100    /// // add arguments to the builder
101    /// builder
102    ///     .realtime_start("1900-01-01")
103    ///     .realtime_end("2000-01-01");
104    /// ```
105    pub fn new() -> Builder {
106        Builder {
107            option_string: String::new(),
108            include_tags: String::new(),
109            exclude_tags: String::new(),
110        }
111    }
112
113    /// Returns the current arguments as a URL formatted string
114    pub(crate) fn build(mut self) -> String {
115        if self.include_tags.len() > 0 {
116            self.option_string += format!("&tag_names={}", self.include_tags).as_str()
117        }
118        if self.exclude_tags.len() > 0 {
119            self.option_string += format!("&exclude_tag_names={}", self.exclude_tags).as_str()
120        }
121        self.option_string
122    }
123
124    /// Adds a realtime_start argument to the builder
125    /// 
126    /// # Arguments
127    /// * `start_date` - date formatted as YYYY-MM-DD
128    /// 
129    /// [https://research.stlouisfed.org/docs/api/fred/category_series.html#realtime_start](https://research.stlouisfed.org/docs/api/fred/category_series.html#realtime_start)
130    pub fn realtime_start(&mut self, start_date: &str) -> &mut Builder {
131        self.option_string += format!("&realtime_start={}", start_date).as_str();
132        self
133    }
134
135    /// Adds a realtime_end argument to the builder
136    /// 
137    /// # Arguments
138    /// * `end_date` - date formatted as YYYY-MM-DD
139    /// 
140    /// [https://research.stlouisfed.org/docs/api/fred/category_series.html#realtime_end](https://research.stlouisfed.org/docs/api/fred/category_series.html#realtime_end)
141    pub fn realtime_end(&mut self, end_date: &str) -> &mut Builder {
142        self.option_string += format!("&realtime_end={}", end_date).as_str();
143        self
144    }
145
146    /// Adds a limit argument to the builder
147    /// 
148    /// The limit argument specifies a maximum number of observations to return.
149    /// 
150    /// # Arguments
151    /// * `num_results` - Maximum number of results to return
152    /// 
153    /// [https://research.stlouisfed.org/docs/api/fred/category_series.html#limit](https://research.stlouisfed.org/docs/api/fred/category_series.html#limit)
154    pub fn limit(&mut self, num_results: usize) -> &mut Builder {
155        let num_results = if num_results > 1000 { // max value is 1000
156            1000
157        } else {
158            num_results
159        };
160        self.option_string += format!("&limit={}", num_results).as_str();
161        self
162    }
163
164    /// Adds an offset argument to the builder
165    /// 
166    /// 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.
167    /// 
168    /// # Arguments
169    /// * `ofs` - the offset amount
170    /// 
171    /// [https://research.stlouisfed.org/docs/api/fred/category_series.html#offset](https://research.stlouisfed.org/docs/api/fred/category_series.html#offset)
172    pub fn offset(&mut self, ofs: usize) -> &mut Builder {
173        self.option_string += format!("&offset={}", ofs).as_str();
174        self
175    }
176
177    /// Adds the search_type argument to the request
178    /// 
179    /// # Arguments
180    /// * `order` - result ranking system
181    /// 
182    /// [https://research.stlouisfed.org/docs/api/fred/category_series.html#order_by](https://research.stlouisfed.org/docs/api/fred/category_series.html#order_by)
183    pub fn order_by(&mut self, order: OrderBy) -> &mut Builder {
184        match order {
185            OrderBy::SeriesId => {
186                self.option_string += "&order_by=series_id";
187            },
188            OrderBy::Title => {
189                self.option_string += "&order_by=title";
190            },
191            OrderBy::Units => {
192                self.option_string += "&order_by=units";
193            },
194            OrderBy::Frequency => {
195                self.option_string += "&order_by=frequency";
196            },
197            OrderBy::SeasonalAdjustment => {
198                self.option_string += "&order_by=seasonal_adjustment";
199            },
200            OrderBy::RealtimeStart => {
201                self.option_string += "&order_by=realtime_start";
202            },
203            OrderBy::RealtimeEnd => {
204                self.option_string += "&order_by=realtime_end";
205            },
206            OrderBy::LastUpdated => {
207                self.option_string += "&order_by=last_updated";
208            },
209            OrderBy::ObservationStart => {
210                self.option_string += "&order_by=observation_start";
211            },
212            OrderBy::ObservationEnd => {
213                self.option_string += "&order_by=observation_end";
214            },
215            OrderBy::Popularity => {
216                self.option_string += "&order_by=popularity";
217            },
218            OrderBy::GroupPopularity => {
219                self.option_string += "&order_by=group_popularity";
220            },
221        };
222        self
223    }
224
225    /// Change the sort order of the data
226    /// 
227    /// # Arguments
228    /// * `order` - Data sort order enum
229    /// 
230    /// [https://research.stlouisfed.org/docs/api/fred/category_series.html#sort_order](https://research.stlouisfed.org/docs/api/fred/category_series.html#sort_order)
231    pub fn sort_order(&mut self, order: SortOrder) -> &mut Builder {
232        match order {
233            SortOrder::Descending => {
234                self.option_string += format!("&sort_order=desc").as_str()
235            },
236            _ => () // ASC is the default so do nothing
237        }
238        self
239    }
240
241    /// Adds the filter_variable argument to the request
242    /// 
243    /// # Arguments
244    /// * `var` - the varible by which to filter
245    /// 
246    /// [https://research.stlouisfed.org/docs/api/fred/category_series.html#filter_variable](https://research.stlouisfed.org/docs/api/fred/category_series.html#filter_variable)
247    pub fn filter_variable(&mut self, var: FilterVariable) -> &mut Builder {
248        match var {
249            FilterVariable::Frequency => {
250                self.option_string += "&filter_variable=frequency";
251            },
252            FilterVariable::Units => {
253                self.option_string += "&filter_variable=units";
254            },
255            FilterVariable::SeasonalAdjustment => {
256                self.option_string += "&filter_variable=seasonal_adjustment";
257            },
258        };
259        self
260    }
261
262    /// Sets the filter value for the specified filter variable
263    /// 
264    /// Results will only include a subset of the original results that match this value for the filter_variable argument.
265    /// 
266    /// # Arguments
267    /// * `val` - the filter value
268    /// 
269    /// [https://research.stlouisfed.org/docs/api/fred/category_series.html#filter_value](https://research.stlouisfed.org/docs/api/fred/category_series.html#filter_value)
270    pub fn filter_value(&mut self, val: &str) -> &mut Builder {
271        self.option_string += format!("&filter_value={}", val).as_str();
272        self
273    }
274
275    /// Adds a tag name to include in the search
276    /// 
277    /// Results must match all included tag names.
278    /// 
279    /// # Arguments
280    /// * `tag` - tag name to add
281    /// 
282    /// [https://research.stlouisfed.org/docs/api/fred/category_series.html#tag_names](https://research.stlouisfed.org/docs/api/fred/category_series.html#tag_names)
283    pub fn tag_name(&mut self, tag: &str) -> &mut Builder {
284        if self.include_tags.len() != 0 {
285            self.include_tags.push(';');
286        } 
287        self.include_tags += tag;
288        self
289    }
290
291    /// Adds a tag name to exclude in the search
292    /// 
293    /// Results must match no excluded tag names.
294    /// 
295    /// # Arguments
296    /// * `tag` - tag name to add
297    /// 
298    /// [https://research.stlouisfed.org/docs/api/fred/category_series.html#exclude_tag_names](https://research.stlouisfed.org/docs/api/fred/category_series.html#exclude_tag_names)
299    pub fn exclude_tag(&mut self, tag: &str) -> &mut Builder {
300        if self.exclude_tags.len() != 0 {
301            self.exclude_tags.push(';');
302        } 
303        self.exclude_tags += tag;
304        self
305    }
306
307}
308
309#[cfg(test)]
310mod tests {
311    use super::*;
312    use crate::series::Response;
313    use crate::client::FredClient;
314
315    #[test]
316    fn category_series_with_options() {
317        let mut c = match FredClient::new() {
318            Ok(c) => c,
319            Err(msg) => {
320                println!("{}", msg);
321                assert_eq!(2, 1);
322                return
323            },
324        };
325
326        let mut builder = Builder::new();
327        builder
328            .limit(5)
329            .sort_order(SortOrder::Descending)
330            .order_by(OrderBy::Frequency);
331
332        let resp: Response = match c.category_series(125, Some(builder)) {
333            Ok(resp) => resp,
334            Err(msg) => {
335                println!("{}", msg);
336                assert_eq!(2, 1);
337                return
338            },
339        };
340
341        for item in resp.seriess {
342            println!(
343                "{}: {} {}",
344                item.id,
345                item.title,
346                item.popularity,
347            );
348        }
349    } 
350}