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