1use std::collections::HashMap;
8
9use regex::Regex;
10use serde::{Deserialize, Serialize};
11
12use rouchdb_core::adapter::Adapter;
13use rouchdb_core::collation::collate;
14use rouchdb_core::document::AllDocsOptions;
15use rouchdb_core::error::Result;
16
17#[derive(Debug, Clone, Default, Serialize, Deserialize)]
19pub struct FindOptions {
20 pub selector: serde_json::Value,
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub fields: Option<Vec<String>>,
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub sort: Option<Vec<SortField>>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub limit: Option<u64>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub skip: Option<u64>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
38#[serde(untagged)]
39pub enum SortField {
40 Simple(String),
42 WithDirection(HashMap<String, String>),
44}
45
46impl SortField {
47 fn field_and_direction(&self) -> (&str, SortDirection) {
48 match self {
49 SortField::Simple(f) => (f.as_str(), SortDirection::Asc),
50 SortField::WithDirection(map) => {
51 let (field, dir) = map.iter().next().unwrap();
52 let direction = if dir == "desc" {
53 SortDirection::Desc
54 } else {
55 SortDirection::Asc
56 };
57 (field.as_str(), direction)
58 }
59 }
60 }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq)]
64enum SortDirection {
65 Asc,
66 Desc,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct FindResponse {
72 pub docs: Vec<serde_json::Value>,
73}
74
75pub async fn find(adapter: &dyn Adapter, opts: FindOptions) -> Result<FindResponse> {
77 let all = adapter
79 .all_docs(AllDocsOptions {
80 include_docs: true,
81 ..AllDocsOptions::new()
82 })
83 .await?;
84
85 let mut matched: Vec<serde_json::Value> = Vec::new();
86
87 for row in &all.rows {
88 if let Some(ref doc_json) = row.doc
89 && matches_selector(doc_json, &opts.selector) {
90 matched.push(doc_json.clone());
91 }
92 }
93
94 if let Some(ref sort_fields) = opts.sort {
96 matched.sort_by(|a, b| {
97 for sf in sort_fields {
98 let (field, direction) = sf.field_and_direction();
99 let va = get_nested_field(a, field);
100 let vb = get_nested_field(b, field);
101 let va = va.unwrap_or(&serde_json::Value::Null);
102 let vb = vb.unwrap_or(&serde_json::Value::Null);
103 let cmp = collate(va, vb);
104 let cmp = if direction == SortDirection::Desc {
105 cmp.reverse()
106 } else {
107 cmp
108 };
109 if cmp != std::cmp::Ordering::Equal {
110 return cmp;
111 }
112 }
113 std::cmp::Ordering::Equal
114 });
115 }
116
117 if let Some(skip) = opts.skip {
119 matched = matched.into_iter().skip(skip as usize).collect();
120 }
121
122 if let Some(limit) = opts.limit {
124 matched.truncate(limit as usize);
125 }
126
127 if let Some(ref fields) = opts.fields {
129 matched = matched
130 .into_iter()
131 .map(|doc| project(doc, fields))
132 .collect();
133 }
134
135 Ok(FindResponse { docs: matched })
136}
137
138pub fn matches_selector(doc: &serde_json::Value, selector: &serde_json::Value) -> bool {
140 match selector {
141 serde_json::Value::Object(map) => {
142 for (key, condition) in map {
143 if !match_condition(doc, key, condition) {
144 return false;
145 }
146 }
147 true
148 }
149 _ => false,
150 }
151}
152
153fn match_condition(doc: &serde_json::Value, key: &str, condition: &serde_json::Value) -> bool {
154 match key {
156 "$and" => return match_and(doc, condition),
157 "$or" => return match_or(doc, condition),
158 "$not" => return match_not(doc, condition),
159 "$nor" => return match_nor(doc, condition),
160 _ => {}
161 }
162
163 let field_value = get_nested_field(doc, key);
164
165 match condition {
166 serde_json::Value::Object(ops) => {
168 for (op, operand) in ops {
169 if !match_operator(field_value, op, operand) {
170 return false;
171 }
172 }
173 true
174 }
175 other => match_operator(field_value, "$eq", other),
177 }
178}
179
180fn match_operator(
181 field_value: Option<&serde_json::Value>,
182 op: &str,
183 operand: &serde_json::Value,
184) -> bool {
185 match op {
186 "$eq" => field_value.is_some_and(|v| collate(v, operand) == std::cmp::Ordering::Equal),
187 "$ne" => field_value.is_none_or(|v| collate(v, operand) != std::cmp::Ordering::Equal),
188 "$gt" => field_value.is_some_and(|v| {
189 collate(v, operand) == std::cmp::Ordering::Greater
190 }),
191 "$gte" => field_value.is_some_and(|v| collate(v, operand) != std::cmp::Ordering::Less),
192 "$lt" => field_value.is_some_and(|v| collate(v, operand) == std::cmp::Ordering::Less),
193 "$lte" => field_value.is_some_and(|v| {
194 collate(v, operand) != std::cmp::Ordering::Greater
195 }),
196 "$in" => {
197 if let Some(arr) = operand.as_array() {
198 field_value.is_some_and(|v| {
199 arr.iter()
200 .any(|item| collate(v, item) == std::cmp::Ordering::Equal)
201 })
202 } else {
203 false
204 }
205 }
206 "$nin" => {
207 if let Some(arr) = operand.as_array() {
208 field_value.is_none_or(|v| {
209 !arr.iter()
210 .any(|item| collate(v, item) == std::cmp::Ordering::Equal)
211 })
212 } else {
213 true
214 }
215 }
216 "$exists" => {
217 let should_exist = operand.as_bool().unwrap_or(true);
218 if should_exist {
219 field_value.is_some()
220 } else {
221 field_value.is_none()
222 }
223 }
224 "$type" => {
225 if let Some(type_name) = operand.as_str() {
226 field_value.is_some_and(|v| json_type_name(v) == type_name)
227 } else {
228 false
229 }
230 }
231 "$regex" => {
232 if let Some(pattern) = operand.as_str() {
233 field_value.is_some_and(|v| {
234 if let Some(s) = v.as_str() {
235 Regex::new(pattern).is_ok_and(|re| re.is_match(s))
236 } else {
237 false
238 }
239 })
240 } else {
241 false
242 }
243 }
244 "$size" => {
245 if let Some(expected_size) = operand.as_u64() {
246 field_value.is_some_and(|v| {
247 v.as_array()
248 .is_some_and(|arr| arr.len() as u64 == expected_size)
249 })
250 } else {
251 false
252 }
253 }
254 "$all" => {
255 if let Some(required) = operand.as_array() {
256 field_value.is_some_and(|v| {
257 if let Some(arr) = v.as_array() {
258 required.iter().all(|req| {
259 arr.iter()
260 .any(|item| collate(item, req) == std::cmp::Ordering::Equal)
261 })
262 } else {
263 false
264 }
265 })
266 } else {
267 false
268 }
269 }
270 "$elemMatch" => field_value.is_some_and(|v| {
271 if let Some(arr) = v.as_array() {
272 arr.iter().any(|elem| matches_selector(elem, operand))
273 } else {
274 false
275 }
276 }),
277 "$not" => {
278 if let Some(ops) = operand.as_object() {
280 for (sub_op, sub_operand) in ops {
281 if match_operator(field_value, sub_op, sub_operand) {
282 return false;
283 }
284 }
285 true
286 } else {
287 !match_operator(field_value, "$eq", operand)
289 }
290 }
291 "$mod" => {
292 if let Some(arr) = operand.as_array() {
293 if arr.len() == 2 {
294 let divisor = arr[0].as_i64();
295 let remainder = arr[1].as_i64();
296 if let (Some(d), Some(r)) = (divisor, remainder) {
297 field_value.is_some_and(|v| {
298 v.as_i64().is_some_and(|n| d != 0 && n % d == r)
299 })
300 } else {
301 false
302 }
303 } else {
304 false
305 }
306 } else {
307 false
308 }
309 }
310 _ => false,
311 }
312}
313
314fn match_and(doc: &serde_json::Value, condition: &serde_json::Value) -> bool {
315 if let Some(arr) = condition.as_array() {
316 arr.iter().all(|sub| matches_selector(doc, sub))
317 } else {
318 false
319 }
320}
321
322fn match_or(doc: &serde_json::Value, condition: &serde_json::Value) -> bool {
323 if let Some(arr) = condition.as_array() {
324 arr.iter().any(|sub| matches_selector(doc, sub))
325 } else {
326 false
327 }
328}
329
330fn match_not(doc: &serde_json::Value, condition: &serde_json::Value) -> bool {
331 !matches_selector(doc, condition)
332}
333
334fn match_nor(doc: &serde_json::Value, condition: &serde_json::Value) -> bool {
335 if let Some(arr) = condition.as_array() {
336 !arr.iter().any(|sub| matches_selector(doc, sub))
337 } else {
338 false
339 }
340}
341
342fn get_nested_field<'a>(doc: &'a serde_json::Value, path: &str) -> Option<&'a serde_json::Value> {
344 let mut current = doc;
345 for part in path.split('.') {
346 match current.get(part) {
347 Some(v) => current = v,
348 None => return None,
349 }
350 }
351 Some(current)
352}
353
354fn json_type_name(value: &serde_json::Value) -> &'static str {
356 match value {
357 serde_json::Value::Null => "null",
358 serde_json::Value::Bool(_) => "boolean",
359 serde_json::Value::Number(_) => "number",
360 serde_json::Value::String(_) => "string",
361 serde_json::Value::Array(_) => "array",
362 serde_json::Value::Object(_) => "object",
363 }
364}
365
366fn project(doc: serde_json::Value, fields: &[String]) -> serde_json::Value {
368 let mut result = serde_json::Map::new();
369
370 if let serde_json::Value::Object(map) = &doc {
371 for field in fields {
372 if let Some(val) = map.get(field) {
374 result.insert(field.clone(), val.clone());
375 }
376 }
377 if let Some(id) = map.get("_id") {
379 result
380 .entry("_id".to_string())
381 .or_insert_with(|| id.clone());
382 }
383 }
384
385 serde_json::Value::Object(result)
386}
387
388#[cfg(test)]
393mod tests {
394 use super::*;
395
396 fn doc(json: serde_json::Value) -> serde_json::Value {
397 json
398 }
399
400 #[test]
403 fn eq_implicit() {
404 let d = doc(serde_json::json!({"name": "Alice", "age": 30}));
405 assert!(matches_selector(&d, &serde_json::json!({"name": "Alice"})));
406 assert!(!matches_selector(&d, &serde_json::json!({"name": "Bob"})));
407 }
408
409 #[test]
410 fn eq_explicit() {
411 let d = doc(serde_json::json!({"age": 30}));
412 assert!(matches_selector(
413 &d,
414 &serde_json::json!({"age": {"$eq": 30}})
415 ));
416 }
417
418 #[test]
419 fn ne() {
420 let d = doc(serde_json::json!({"age": 30}));
421 assert!(matches_selector(
422 &d,
423 &serde_json::json!({"age": {"$ne": 25}})
424 ));
425 assert!(!matches_selector(
426 &d,
427 &serde_json::json!({"age": {"$ne": 30}})
428 ));
429 }
430
431 #[test]
432 fn gt_gte_lt_lte() {
433 let d = doc(serde_json::json!({"age": 30}));
434
435 assert!(matches_selector(
436 &d,
437 &serde_json::json!({"age": {"$gt": 20}})
438 ));
439 assert!(!matches_selector(
440 &d,
441 &serde_json::json!({"age": {"$gt": 30}})
442 ));
443
444 assert!(matches_selector(
445 &d,
446 &serde_json::json!({"age": {"$gte": 30}})
447 ));
448 assert!(!matches_selector(
449 &d,
450 &serde_json::json!({"age": {"$gte": 31}})
451 ));
452
453 assert!(matches_selector(
454 &d,
455 &serde_json::json!({"age": {"$lt": 40}})
456 ));
457 assert!(!matches_selector(
458 &d,
459 &serde_json::json!({"age": {"$lt": 30}})
460 ));
461
462 assert!(matches_selector(
463 &d,
464 &serde_json::json!({"age": {"$lte": 30}})
465 ));
466 assert!(!matches_selector(
467 &d,
468 &serde_json::json!({"age": {"$lte": 29}})
469 ));
470 }
471
472 #[test]
473 fn in_nin() {
474 let d = doc(serde_json::json!({"color": "red"}));
475
476 assert!(matches_selector(
477 &d,
478 &serde_json::json!({"color": {"$in": ["red", "blue"]}})
479 ));
480 assert!(!matches_selector(
481 &d,
482 &serde_json::json!({"color": {"$in": ["green", "blue"]}})
483 ));
484
485 assert!(matches_selector(
486 &d,
487 &serde_json::json!({"color": {"$nin": ["green", "blue"]}})
488 ));
489 assert!(!matches_selector(
490 &d,
491 &serde_json::json!({"color": {"$nin": ["red", "blue"]}})
492 ));
493 }
494
495 #[test]
496 fn exists() {
497 let d = doc(serde_json::json!({"name": "Alice"}));
498
499 assert!(matches_selector(
500 &d,
501 &serde_json::json!({"name": {"$exists": true}})
502 ));
503 assert!(!matches_selector(
504 &d,
505 &serde_json::json!({"age": {"$exists": true}})
506 ));
507 assert!(matches_selector(
508 &d,
509 &serde_json::json!({"age": {"$exists": false}})
510 ));
511 }
512
513 #[test]
514 fn type_check() {
515 let d = doc(serde_json::json!({"name": "Alice", "age": 30, "active": true}));
516
517 assert!(matches_selector(
518 &d,
519 &serde_json::json!({"name": {"$type": "string"}})
520 ));
521 assert!(matches_selector(
522 &d,
523 &serde_json::json!({"age": {"$type": "number"}})
524 ));
525 assert!(matches_selector(
526 &d,
527 &serde_json::json!({"active": {"$type": "boolean"}})
528 ));
529 }
530
531 #[test]
532 fn regex_match() {
533 let d = doc(serde_json::json!({"name": "Alice"}));
534
535 assert!(matches_selector(
536 &d,
537 &serde_json::json!({"name": {"$regex": "^Ali"}})
538 ));
539 assert!(!matches_selector(
540 &d,
541 &serde_json::json!({"name": {"$regex": "^Bob"}})
542 ));
543 }
544
545 #[test]
546 fn size_operator() {
547 let d = doc(serde_json::json!({"tags": ["a", "b", "c"]}));
548
549 assert!(matches_selector(
550 &d,
551 &serde_json::json!({"tags": {"$size": 3}})
552 ));
553 assert!(!matches_selector(
554 &d,
555 &serde_json::json!({"tags": {"$size": 2}})
556 ));
557 }
558
559 #[test]
560 fn all_operator() {
561 let d = doc(serde_json::json!({"tags": ["a", "b", "c"]}));
562
563 assert!(matches_selector(
564 &d,
565 &serde_json::json!({"tags": {"$all": ["a", "c"]}})
566 ));
567 assert!(!matches_selector(
568 &d,
569 &serde_json::json!({"tags": {"$all": ["a", "d"]}})
570 ));
571 }
572
573 #[test]
574 fn elem_match() {
575 let d = doc(serde_json::json!({
576 "scores": [
577 {"subject": "math", "grade": 90},
578 {"subject": "english", "grade": 75}
579 ]
580 }));
581
582 assert!(matches_selector(
583 &d,
584 &serde_json::json!({"scores": {"$elemMatch": {"subject": "math", "grade": {"$gt": 80}}}})
585 ));
586 assert!(!matches_selector(
587 &d,
588 &serde_json::json!({"scores": {"$elemMatch": {"subject": "math", "grade": {"$gt": 95}}}})
589 ));
590 }
591
592 #[test]
593 fn mod_operator() {
594 let d = doc(serde_json::json!({"n": 10}));
595
596 assert!(matches_selector(
597 &d,
598 &serde_json::json!({"n": {"$mod": [3, 1]}})
599 ));
600 assert!(!matches_selector(
601 &d,
602 &serde_json::json!({"n": {"$mod": [3, 0]}})
603 ));
604 }
605
606 #[test]
609 fn and_operator() {
610 let d = doc(serde_json::json!({"age": 30, "active": true}));
611
612 assert!(matches_selector(
613 &d,
614 &serde_json::json!({"$and": [{"age": {"$gte": 20}}, {"active": true}]})
615 ));
616 assert!(!matches_selector(
617 &d,
618 &serde_json::json!({"$and": [{"age": {"$gte": 20}}, {"active": false}]})
619 ));
620 }
621
622 #[test]
623 fn or_operator() {
624 let d = doc(serde_json::json!({"age": 30}));
625
626 assert!(matches_selector(
627 &d,
628 &serde_json::json!({"$or": [{"age": 30}, {"age": 40}]})
629 ));
630 assert!(!matches_selector(
631 &d,
632 &serde_json::json!({"$or": [{"age": 20}, {"age": 40}]})
633 ));
634 }
635
636 #[test]
637 fn not_operator() {
638 let d = doc(serde_json::json!({"age": 30}));
639
640 assert!(matches_selector(
641 &d,
642 &serde_json::json!({"$not": {"age": 40}})
643 ));
644 assert!(!matches_selector(
645 &d,
646 &serde_json::json!({"$not": {"age": 30}})
647 ));
648 }
649
650 #[test]
651 fn nor_operator() {
652 let d = doc(serde_json::json!({"age": 30}));
653
654 assert!(matches_selector(
655 &d,
656 &serde_json::json!({"$nor": [{"age": 20}, {"age": 40}]})
657 ));
658 assert!(!matches_selector(
659 &d,
660 &serde_json::json!({"$nor": [{"age": 30}, {"age": 40}]})
661 ));
662 }
663
664 #[test]
667 fn nested_field_access() {
668 let d = doc(serde_json::json!({"address": {"city": "NYC", "zip": "10001"}}));
669
670 assert!(matches_selector(
671 &d,
672 &serde_json::json!({"address.city": "NYC"})
673 ));
674 assert!(!matches_selector(
675 &d,
676 &serde_json::json!({"address.city": "LA"})
677 ));
678 }
679
680 #[test]
683 fn multiple_field_conditions() {
684 let d = doc(serde_json::json!({"name": "Alice", "age": 30}));
685
686 assert!(matches_selector(
688 &d,
689 &serde_json::json!({"name": "Alice", "age": {"$gte": 25}})
690 ));
691 assert!(!matches_selector(
692 &d,
693 &serde_json::json!({"name": "Alice", "age": {"$gte": 35}})
694 ));
695 }
696
697 #[test]
698 fn combined_operators_on_field() {
699 let d = doc(serde_json::json!({"age": 30}));
700
701 assert!(matches_selector(
703 &d,
704 &serde_json::json!({"age": {"$gt": 20, "$lt": 40}})
705 ));
706 assert!(!matches_selector(
707 &d,
708 &serde_json::json!({"age": {"$gt": 30, "$lt": 40}})
709 ));
710 }
711
712 #[test]
715 fn project_fields() {
716 let d = serde_json::json!({"_id": "doc1", "_rev": "1-abc", "name": "Alice", "age": 30});
717 let projected = project(d, &["name".to_string()]);
718
719 assert_eq!(projected["_id"], "doc1");
720 assert_eq!(projected["name"], "Alice");
721 assert!(projected.get("age").is_none());
722 }
723
724 #[test]
727 fn missing_field_ne_matches() {
728 let d = doc(serde_json::json!({"name": "Alice"}));
730 assert!(matches_selector(
731 &d,
732 &serde_json::json!({"age": {"$ne": 30}})
733 ));
734 }
735
736 #[test]
737 fn missing_field_eq_fails() {
738 let d = doc(serde_json::json!({"name": "Alice"}));
739 assert!(!matches_selector(
740 &d,
741 &serde_json::json!({"age": {"$eq": 30}})
742 ));
743 }
744}