finance_query/endpoints/
search.rs1use super::urls::api;
2use crate::client::YahooClient;
6use crate::constants::Region;
7use crate::error::Result;
8use tracing::info;
9
10#[derive(Debug, Clone)]
12pub struct SearchOptions {
13 pub quotes_count: u32,
15 pub news_count: u32,
17 pub enable_fuzzy_query: bool,
19 pub enable_logo_url: bool,
21 pub enable_research_reports: bool,
23 pub enable_cultural_assets: bool,
25 pub recommend_count: u32,
27 pub region: Option<Region>,
29}
30
31impl Default for SearchOptions {
32 fn default() -> Self {
33 Self {
34 quotes_count: 10,
35 news_count: 0,
36 enable_fuzzy_query: false,
37 enable_logo_url: true,
38 enable_research_reports: false,
39 enable_cultural_assets: false,
40 recommend_count: 5,
41 region: None,
42 }
43 }
44}
45
46impl SearchOptions {
47 pub fn new() -> Self {
49 Self::default()
50 }
51
52 pub fn quotes_count(mut self, count: u32) -> Self {
54 self.quotes_count = count;
55 self
56 }
57
58 pub fn news_count(mut self, count: u32) -> Self {
60 self.news_count = count;
61 self
62 }
63
64 pub fn enable_fuzzy_query(mut self, enable: bool) -> Self {
66 self.enable_fuzzy_query = enable;
67 self
68 }
69
70 pub fn enable_logo_url(mut self, enable: bool) -> Self {
72 self.enable_logo_url = enable;
73 self
74 }
75
76 pub fn enable_research_reports(mut self, enable: bool) -> Self {
78 self.enable_research_reports = enable;
79 self
80 }
81
82 pub fn enable_cultural_assets(mut self, enable: bool) -> Self {
84 self.enable_cultural_assets = enable;
85 self
86 }
87
88 pub fn recommend_count(mut self, count: u32) -> Self {
90 self.recommend_count = count;
91 self
92 }
93
94 pub fn region(mut self, region: Region) -> Self {
96 self.region = Some(region);
97 self
98 }
99}
100
101pub async fn fetch(
121 client: &YahooClient,
122 query: &str,
123 options: &SearchOptions,
124) -> Result<serde_json::Value> {
125 if query.trim().is_empty() {
126 return Err(crate::error::YahooError::InvalidParameter {
127 param: "query".to_string(),
128 reason: "Empty search query".to_string(),
129 });
130 }
131
132 info!("Searching for: {} (options: {:?})", query, options);
133
134 let quotes_count = options.quotes_count.to_string();
135 let news_count = options.news_count.to_string();
136 let fuzzy = options.enable_fuzzy_query.to_string();
137 let logo = options.enable_logo_url.to_string();
138 let research = options.enable_research_reports.to_string();
139 let cultural = options.enable_cultural_assets.to_string();
140 let recommend = options.recommend_count.to_string();
141
142 let lang = options
144 .region
145 .as_ref()
146 .map(|c| c.lang().to_string())
147 .unwrap_or_else(|| client.config().lang.clone());
148 let region = options
149 .region
150 .as_ref()
151 .map(|c| c.region().to_string())
152 .unwrap_or_else(|| client.config().region.clone());
153
154 let params = [
155 ("q", query),
156 ("lang", &lang),
157 ("region", ®ion),
158 ("quotesCount", "es_count),
159 ("newsCount", &news_count),
160 ("enableFuzzyQuery", &fuzzy),
161 ("enableLogoUrl", &logo),
162 ("enableResearchReports", &research),
163 ("enableCulturalAssets", &cultural),
164 ("recommendedCount", &recommend),
165 ("listsCount", "0"), ("enableNavLinks", "false"), ("enableEnhancedTrivialQuery", "true"),
168 ];
169
170 let response = client.request_with_params(api::SEARCH, ¶ms).await?;
171
172 Ok(response.json().await?)
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use crate::client::ClientConfig;
179
180 #[tokio::test]
181 #[ignore] async fn test_fetch_search() {
183 let client = YahooClient::new(ClientConfig::default()).await.unwrap();
184 let options = SearchOptions::new().quotes_count(5);
185 let result = fetch(&client, "Apple", &options).await;
186 assert!(result.is_ok());
187 let json = result.unwrap();
188 assert!(json.get("quotes").is_some());
189 }
190
191 #[tokio::test]
192 #[ignore] async fn test_fetch_search_with_news() {
194 let client = YahooClient::new(ClientConfig::default()).await.unwrap();
195 let options = SearchOptions::new()
196 .quotes_count(5)
197 .news_count(3)
198 .enable_research_reports(true);
199 let result = fetch(&client, "NVDA", &options).await;
200 assert!(result.is_ok());
201 let json = result.unwrap();
202 assert!(json.get("quotes").is_some());
203 }
204
205 #[tokio::test]
206 #[ignore = "requires network access - validation tested in common::tests"]
207 async fn test_empty_query() {
208 let client = YahooClient::new(ClientConfig::default()).await.unwrap();
209 let options = SearchOptions::new();
210 let result = fetch(&client, "", &options).await;
211 assert!(result.is_err());
212 }
213}