finance_query/tickers/core/
membership.rs1use super::Tickers;
2use std::sync::Arc;
3
4impl Tickers {
5 pub fn add_symbols<S, I>(&mut self, symbols: I)
26 where
27 S: Into<String>,
28 I: IntoIterator<Item = S>,
29 {
30 use std::collections::HashSet;
32
33 let existing: HashSet<&str> = self.symbols.iter().map(|s| &**s).collect();
34 let to_add: Vec<Arc<str>> = symbols
35 .into_iter()
36 .map(Into::into)
37 .filter(|s| !existing.contains(s.as_str()))
38 .map(|s| s.into())
39 .collect();
40
41 self.symbols.extend(to_add);
42 }
43
44 pub async fn remove_symbols<S, I>(&mut self, symbols: I)
61 where
62 S: Into<String>,
63 I: IntoIterator<Item = S>,
64 {
65 use std::collections::HashSet;
66 let owned: Vec<String> = symbols.into_iter().map(Into::into).collect();
67 let to_remove: HashSet<&str> = owned.iter().map(|s| s.as_str()).collect();
68
69 self.symbols.retain(|s| !to_remove.contains(&**s));
71
72 let (
74 mut quote_cache,
75 mut chart_cache,
76 mut events_cache,
77 mut financials_cache,
78 mut news_cache,
79 mut recommendations_cache,
80 mut options_cache,
81 mut spark_cache,
82 ) = tokio::join!(
83 self.quote_cache.write(),
84 self.chart_cache.write(),
85 self.events_cache.write(),
86 self.financials_cache.write(),
87 self.news_cache.write(),
88 self.recommendations_cache.write(),
89 self.options_cache.write(),
90 self.spark_cache.write(),
91 );
92
93 for symbol in &to_remove {
95 let key: Arc<str> = (*symbol).into();
96 quote_cache.remove(&key);
97 events_cache.remove(&key);
98 news_cache.remove(&key);
99 }
100
101 chart_cache.retain(|(sym, _, _), _| !to_remove.contains(&**sym));
103 financials_cache.retain(|(sym, _, _), _| !to_remove.contains(&**sym));
104 recommendations_cache.retain(|(sym, _), _| !to_remove.contains(&**sym));
105 options_cache.retain(|(sym, _), _| !to_remove.contains(&**sym));
106 spark_cache.retain(|(sym, _, _), _| !to_remove.contains(&**sym));
107
108 drop((
110 quote_cache,
111 chart_cache,
112 events_cache,
113 financials_cache,
114 news_cache,
115 recommendations_cache,
116 options_cache,
117 spark_cache,
118 ));
119
120 #[cfg(feature = "indicators")]
121 self.indicators_cache
122 .write()
123 .await
124 .retain(|(sym, _, _), _| !to_remove.contains(&**sym));
125 }
126
127 pub async fn clear_cache(&self) {
132 tokio::join!(
133 async { self.quote_cache.write().await.clear() },
135 async { self.chart_cache.write().await.clear() },
136 async { self.events_cache.write().await.clear() },
137 async { self.financials_cache.write().await.clear() },
138 async { self.news_cache.write().await.clear() },
139 async { self.recommendations_cache.write().await.clear() },
140 async { self.options_cache.write().await.clear() },
141 async { self.spark_cache.write().await.clear() },
142 async {
143 #[cfg(feature = "indicators")]
144 self.indicators_cache.write().await.clear();
145 },
146 async { self.charts_fetch.write().await.clear() },
148 async { self.financials_fetch.write().await.clear() },
149 async { self.recommendations_fetch.write().await.clear() },
150 async { self.options_fetch.write().await.clear() },
151 async { self.spark_fetch.write().await.clear() },
152 async {
153 #[cfg(feature = "indicators")]
154 self.indicators_fetch.write().await.clear();
155 },
156 );
157 }
158
159 pub async fn clear_quote_cache(&self) {
163 self.quote_cache.write().await.clear();
164 }
165
166 pub async fn clear_chart_cache(&self) {
171 tokio::join!(
172 async { self.chart_cache.write().await.clear() },
173 async { self.events_cache.write().await.clear() },
174 async { self.spark_cache.write().await.clear() },
175 async {
176 #[cfg(feature = "indicators")]
177 self.indicators_cache.write().await.clear();
178 },
179 );
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[tokio::test]
188 async fn test_tickers_add_symbols() {
189 let mut tickers = Tickers::new(["AAPL"]).await.unwrap();
190 assert_eq!(tickers.len(), 1);
191 assert_eq!(tickers.symbols(), &["AAPL"]);
192
193 tickers.add_symbols(["MSFT", "GOOGL"]);
194 assert_eq!(tickers.len(), 3);
195 assert!(tickers.symbols().contains(&"AAPL"));
196 assert!(tickers.symbols().contains(&"MSFT"));
197 assert!(tickers.symbols().contains(&"GOOGL"));
198
199 tickers.add_symbols(["AAPL"]);
201 assert_eq!(tickers.len(), 3);
202 }
203
204 #[tokio::test]
205 #[ignore = "requires network access"]
206 async fn test_tickers_remove_symbols() {
207 let mut tickers = Tickers::new(["AAPL", "MSFT", "GOOGL"]).await.unwrap();
208 assert_eq!(tickers.len(), 3);
209
210 let _ = tickers.quotes().await;
212
213 tickers.remove_symbols(["MSFT"]).await;
215 assert_eq!(tickers.len(), 2);
216 assert!(tickers.symbols().contains(&"AAPL"));
217 assert!(!tickers.symbols().contains(&"MSFT"));
218 assert!(tickers.symbols().contains(&"GOOGL"));
219
220 let quotes = tickers.quotes().await.unwrap();
222 assert!(!quotes.quotes.contains_key("MSFT"));
223 assert_eq!(quotes.quotes.len(), 2);
224 }
225}