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