1use crate::{Query, LazyQuery, Queryable};
2
3pub trait QueryExt<T> {
20 fn query(&self) -> Query<T>;
25}
26
27impl<T: 'static> QueryExt<T> for Vec<T> {
29 fn query(&self) -> Query<T> {
30 Query::new(self)
31 }
32}
33
34impl<T: 'static> QueryExt<T> for [T] {
36 fn query(&self) -> Query<T> {
37 Query::new(self)
38 }
39}
40
41impl<T: 'static, const N: usize> QueryExt<T> for [T; N] {
43 fn query(&self) -> Query<T> {
44 Query::new(&self[..])
45 }
46}
47
48pub trait QueryableExt<T> {
64 fn lazy_query(&self) -> LazyQuery<T, Box<dyn Iterator<Item = &T> + '_>>;
69}
70
71impl<T: 'static, Q> QueryableExt<T> for Q
73where
74 Q: Queryable<T>,
75{
76 fn lazy_query(&self) -> LazyQuery<T, Box<dyn Iterator<Item = &T> + '_>> {
77 LazyQuery::from_iter(self.query_iter())
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use key_paths_derive::Keypaths;
85
86 #[derive(Debug, Clone, PartialEq, Keypaths)]
87 struct Product {
88 id: u32,
89 name: String,
90 price: f64,
91 category: String,
92 }
93
94 #[test]
95 fn test_vec_query_ext() {
96 let products = vec![
97 Product {
98 id: 1,
99 name: "Laptop".to_string(),
100 price: 999.99,
101 category: "Electronics".to_string(),
102 },
103 Product {
104 id: 2,
105 name: "Mouse".to_string(),
106 price: 29.99,
107 category: "Electronics".to_string(),
108 },
109 ];
110
111 let query = products
112 .query()
113 .where_(Product::price_r(), |&p| p > 50.0);
114 let results = query.all();
115
116 assert_eq!(results.len(), 1);
117 assert_eq!(results[0].name, "Laptop");
118 }
119
120 #[test]
121 fn test_vec_lazy_query_ext() {
122 let products = vec![
123 Product {
124 id: 1,
125 name: "Laptop".to_string(),
126 price: 999.99,
127 category: "Electronics".to_string(),
128 },
129 Product {
130 id: 2,
131 name: "Mouse".to_string(),
132 price: 29.99,
133 category: "Electronics".to_string(),
134 },
135 ];
136
137 let results: Vec<_> = products
138 .lazy_query()
139 .where_(Product::price_r(), |&p| p > 50.0)
140 .collect();
141
142 assert_eq!(results.len(), 1);
143 assert_eq!(results[0].name, "Laptop");
144 }
145
146 #[test]
147 fn test_array_query_ext() {
148 let products = [
149 Product {
150 id: 1,
151 name: "Laptop".to_string(),
152 price: 999.99,
153 category: "Electronics".to_string(),
154 },
155 Product {
156 id: 2,
157 name: "Mouse".to_string(),
158 price: 29.99,
159 category: "Electronics".to_string(),
160 },
161 ];
162
163 let results: Vec<_> = products
164 .lazy_query()
165 .where_(Product::price_r(), |&p| p < 100.0)
166 .collect();
167
168 assert_eq!(results.len(), 1);
169 assert_eq!(results[0].name, "Mouse");
170 }
171
172 #[test]
173 fn test_slice_query_ext() {
174 let products = vec![
175 Product {
176 id: 1,
177 name: "Laptop".to_string(),
178 price: 999.99,
179 category: "Electronics".to_string(),
180 },
181 Product {
182 id: 2,
183 name: "Mouse".to_string(),
184 price: 29.99,
185 category: "Electronics".to_string(),
186 },
187 ];
188
189 let slice = &products[..];
190 let query = slice
191 .query()
192 .where_(Product::category_r(), |cat| cat == "Electronics");
193 let results = query.count();
194
195 assert_eq!(results, 2);
196 }
197
198 #[test]
199 fn test_hashmap_queryable_ext() {
200 use std::collections::HashMap;
201
202 let mut map: HashMap<u32, Product> = HashMap::new();
203 map.insert(
204 1,
205 Product {
206 id: 1,
207 name: "Laptop".to_string(),
208 price: 999.99,
209 category: "Electronics".to_string(),
210 },
211 );
212 map.insert(
213 2,
214 Product {
215 id: 2,
216 name: "Mouse".to_string(),
217 price: 29.99,
218 category: "Electronics".to_string(),
219 },
220 );
221
222 let results: Vec<_> = map
224 .lazy_query()
225 .where_(Product::price_r(), |&p| p > 50.0)
226 .collect();
227
228 assert_eq!(results.len(), 1);
229 assert_eq!(results[0].name, "Laptop");
230 }
231
232 #[test]
233 fn test_btreemap_queryable_ext() {
234 use std::collections::BTreeMap;
235
236 let mut map: BTreeMap<u32, Product> = BTreeMap::new();
237 map.insert(
238 1,
239 Product {
240 id: 1,
241 name: "Laptop".to_string(),
242 price: 999.99,
243 category: "Electronics".to_string(),
244 },
245 );
246 map.insert(
247 2,
248 Product {
249 id: 2,
250 name: "Mouse".to_string(),
251 price: 29.99,
252 category: "Electronics".to_string(),
253 },
254 );
255
256 let count = map
258 .lazy_query()
259 .where_(Product::category_r(), |cat| cat == "Electronics")
260 .count();
261
262 assert_eq!(count, 2);
263 }
264
265 #[test]
266 fn test_vecdeque_queryable_ext() {
267 use std::collections::VecDeque;
268
269 let mut deque: VecDeque<Product> = VecDeque::new();
270 deque.push_back(Product {
271 id: 1,
272 name: "Laptop".to_string(),
273 price: 999.99,
274 category: "Electronics".to_string(),
275 });
276 deque.push_back(Product {
277 id: 2,
278 name: "Mouse".to_string(),
279 price: 29.99,
280 category: "Electronics".to_string(),
281 });
282
283 let results: Vec<_> = deque
285 .lazy_query()
286 .where_(Product::price_r(), |&p| p < 100.0)
287 .collect();
288
289 assert_eq!(results.len(), 1);
290 assert_eq!(results[0].name, "Mouse");
291 }
292
293 #[test]
294 fn test_linkedlist_queryable_ext() {
295 use std::collections::LinkedList;
296
297 let mut list: LinkedList<Product> = LinkedList::new();
298 list.push_back(Product {
299 id: 1,
300 name: "Laptop".to_string(),
301 price: 999.99,
302 category: "Electronics".to_string(),
303 });
304 list.push_back(Product {
305 id: 2,
306 name: "Mouse".to_string(),
307 price: 29.99,
308 category: "Electronics".to_string(),
309 });
310
311 let first = list
313 .lazy_query()
314 .where_(Product::price_r(), |&p| p > 900.0)
315 .first();
316
317 assert!(first.is_some());
318 assert_eq!(first.unwrap().name, "Laptop");
319 }
320
321 #[test]
322 fn test_queryable_ext_aggregations() {
323 use std::collections::VecDeque;
324
325 let mut deque: VecDeque<Product> = VecDeque::new();
326 deque.push_back(Product {
327 id: 1,
328 name: "Laptop".to_string(),
329 price: 999.99,
330 category: "Electronics".to_string(),
331 });
332 deque.push_back(Product {
333 id: 2,
334 name: "Mouse".to_string(),
335 price: 29.99,
336 category: "Electronics".to_string(),
337 });
338 deque.push_back(Product {
339 id: 3,
340 name: "Keyboard".to_string(),
341 price: 79.99,
342 category: "Electronics".to_string(),
343 });
344
345 let total = deque.lazy_query().sum_by(Product::price_r());
347 assert!((total - 1109.97).abs() < 0.01);
348
349 let avg = deque.lazy_query().avg_by(Product::price_r()).unwrap();
350 assert!((avg - 369.99).abs() < 0.01);
351
352 let min = deque.lazy_query().min_by_float(Product::price_r()).unwrap();
353 assert!((min - 29.99).abs() < 0.01);
354
355 let max = deque.lazy_query().max_by_float(Product::price_r()).unwrap();
356 assert!((max - 999.99).abs() < 0.01);
357 }
358
359 #[test]
360 fn test_queryable_ext_chaining() {
361 use std::collections::BTreeMap;
362
363 let mut map: BTreeMap<u32, Product> = BTreeMap::new();
364 map.insert(
365 1,
366 Product {
367 id: 1,
368 name: "Laptop".to_string(),
369 price: 999.99,
370 category: "Electronics".to_string(),
371 },
372 );
373 map.insert(
374 2,
375 Product {
376 id: 2,
377 name: "Mouse".to_string(),
378 price: 29.99,
379 category: "Electronics".to_string(),
380 },
381 );
382 map.insert(
383 3,
384 Product {
385 id: 3,
386 name: "Desk".to_string(),
387 price: 299.99,
388 category: "Furniture".to_string(),
389 },
390 );
391
392 let results: Vec<_> = map
394 .lazy_query()
395 .where_(Product::category_r(), |cat| cat == "Electronics")
396 .where_(Product::price_r(), |&p| p < 500.0)
397 .skip_lazy(0)
398 .take_lazy(10)
399 .collect();
400
401 assert_eq!(results.len(), 1);
402 assert_eq!(results[0].name, "Mouse");
403 }
404}