ferric_fred/
series_search_request.rs1use crate::{Client, OrderBy, Result, SearchType, SeriesSearchResults, SortOrder};
2
3#[derive(Debug, Clone)]
23#[must_use = "a SeriesSearchRequest does nothing until you call `.send()`"]
24pub struct SeriesSearchRequest<'a> {
25 client: &'a Client,
26 search_text: String,
27 search_type: Option<SearchType>,
28 order_by: Option<OrderBy>,
29 sort_order: Option<SortOrder>,
30 limit: Option<u32>,
31 offset: Option<u32>,
32}
33
34impl<'a> SeriesSearchRequest<'a> {
35 pub(crate) fn new(client: &'a Client, search_text: String) -> Self {
36 Self {
37 client,
38 search_text,
39 search_type: None,
40 order_by: None,
41 sort_order: None,
42 limit: None,
43 offset: None,
44 }
45 }
46
47 pub fn search_type(mut self, search_type: SearchType) -> Self {
49 self.search_type = Some(search_type);
50 self
51 }
52
53 pub fn order_by(mut self, order_by: OrderBy) -> Self {
55 self.order_by = Some(order_by);
56 self
57 }
58
59 pub fn sort_order(mut self, order: SortOrder) -> Self {
61 self.sort_order = Some(order);
62 self
63 }
64
65 pub fn limit(mut self, limit: u32) -> Self {
67 self.limit = Some(limit);
68 self
69 }
70
71 pub fn offset(mut self, offset: u32) -> Self {
73 self.offset = Some(offset);
74 self
75 }
76
77 pub async fn send(self) -> Result<SeriesSearchResults> {
84 self.client.execute_search(&self).await
85 }
86
87 pub(crate) fn query_params(&self) -> Vec<(&'static str, String)> {
90 let mut params: Vec<(&'static str, String)> = Vec::new();
91 params.push(("search_text", self.search_text.clone()));
92 if let Some(search_type) = self.search_type {
93 params.push(("search_type", search_type.query_code().to_owned()));
94 }
95 if let Some(order_by) = self.order_by {
96 params.push(("order_by", order_by.query_code().to_owned()));
97 }
98 if let Some(order) = self.sort_order {
99 params.push(("sort_order", order.query_code().to_owned()));
100 }
101 if let Some(limit) = self.limit {
102 params.push(("limit", limit.to_string()));
103 }
104 if let Some(offset) = self.offset {
105 params.push(("offset", offset.to_string()));
106 }
107 params
108 }
109}
110
111impl crate::paginate::sealed::Sealed for SeriesSearchRequest<'_> {}
112impl crate::paginate::Paginate for SeriesSearchRequest<'_> {
113 type Page = SeriesSearchResults;
114 const MAX_PAGE: u32 = 1000;
115 fn requested_limit(&self) -> Option<u32> {
116 self.limit
117 }
118 fn requested_offset(&self) -> Option<u32> {
119 self.offset
120 }
121 fn with_paging(self, limit: u32, offset: u32) -> Self {
122 self.limit(limit).offset(offset)
123 }
124 fn send_page(self) -> impl std::future::Future<Output = Result<Self::Page>> + Send {
125 self.send()
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 fn test_client() -> Client {
134 Client::new("test-key").expect("client builds")
135 }
136
137 #[test]
138 fn defaults_send_only_the_search_text() {
139 let client = test_client();
140 let request = client.search("real gnp");
141 assert_eq!(
142 request.query_params(),
143 vec![("search_text", "real gnp".to_owned())]
144 );
145 }
146
147 #[test]
148 fn parameters_serialize_to_fred_codes() {
149 let client = test_client();
150 let request = client
151 .search("unemployment")
152 .search_type(SearchType::FullText)
153 .order_by(OrderBy::Popularity)
154 .sort_order(SortOrder::Descending)
155 .limit(25)
156 .offset(50);
157
158 let params = request.query_params();
159 for expected in [
160 ("search_text", "unemployment"),
161 ("search_type", "full_text"),
162 ("order_by", "popularity"),
163 ("sort_order", "desc"),
164 ("limit", "25"),
165 ("offset", "50"),
166 ] {
167 assert!(
168 params.contains(&(expected.0, expected.1.to_owned())),
169 "missing {expected:?} in {params:?}"
170 );
171 }
172 }
173}