1use std::cmp::Ordering;
10
11use serde_json::{Map, Value};
12
13use crate::bson;
14
15use super::pipeline::{float_of, number_of};
16
17pub const MAX_LOCAL_COLLECTION_DOCS: usize = 100_000;
19
20const RANK_MINKEY: u8 = 1;
25const RANK_NULL: u8 = 2;
26const RANK_NUMBER: u8 = 3;
27const RANK_STRING: u8 = 4;
28const RANK_OBJECT: u8 = 5;
29const RANK_ARRAY: u8 = 6;
30const RANK_BINARY: u8 = 7;
31const RANK_OID: u8 = 8;
32const RANK_BOOL: u8 = 9;
33const RANK_DATE: u8 = 10;
34const RANK_TIMESTAMP: u8 = 11;
35const RANK_REGEX: u8 = 12;
36const RANK_MAXKEY: u8 = 13;
37
38fn segments(path: &str) -> Vec<&str> {
40 if path.is_empty() {
41 Vec::new()
42 } else {
43 path.split('.').collect()
44 }
45}
46
47pub fn get_path<'a>(doc: &'a Value, path: &str) -> Option<&'a Value> {
56 let mut cur = doc;
57 for seg in segments(path) {
58 cur = match cur {
59 Value::Object(o) => o.get(seg)?,
60 _ => return None,
62 };
63 }
64 Some(cur)
65}
66
67pub fn resolve_path_candidates<'a>(doc: &'a Value, path: &str) -> Vec<&'a Value> {
77 let mut out = Vec::new();
78 collect_candidates(doc, &segments(path), &mut out);
79 out
80}
81
82fn collect_candidates<'a>(v: &'a Value, segs: &[&str], out: &mut Vec<&'a Value>) {
83 if segs.is_empty() {
84 out.push(v);
85 return;
86 }
87 match v {
88 Value::Object(o) => {
89 if let Some(next) = o.get(segs[0]) {
90 collect_candidates(next, &segs[1..], out);
91 }
92 }
93 Value::Array(a) => {
94 for el in a {
95 collect_candidates(el, segs, out);
96 }
97 }
98 _ => {}
99 }
100}
101
102pub fn bson_rank(v: &Value) -> u8 {
111 match v {
112 Value::Null => RANK_NULL,
113 Value::Bool(_) => RANK_BOOL,
114 Value::Number(_) => RANK_NUMBER,
115 Value::String(_) => RANK_STRING,
116 Value::Array(_) => RANK_ARRAY,
117 Value::Object(o) => extended_kind(o).unwrap_or(RANK_OBJECT),
118 }
119}
120
121fn extended_kind(o: &Map<String, Value>) -> Option<u8> {
123 if o.len() != 1 {
124 return None;
125 }
126 match o.keys().next()?.as_str() {
127 "$minKey" => Some(RANK_MINKEY),
128 "$maxKey" => Some(RANK_MAXKEY),
129 "$numberDecimal" | "$numberLong" => Some(RANK_NUMBER),
130 "$oid" => Some(RANK_OID),
131 "$date" => Some(RANK_DATE),
132 "$timestamp" => Some(RANK_TIMESTAMP),
133 "$binary" => Some(RANK_BINARY),
134 "$regularExpression" => Some(RANK_REGEX),
135 _ => None,
136 }
137}
138
139pub fn compare(a: &Value, b: &Value) -> Ordering {
144 let (ra, rb) = (bson_rank(a), bson_rank(b));
145 if ra != rb {
146 return ra.cmp(&rb);
147 }
148 match ra {
149 RANK_NUMBER => compare_numbers(a, b),
150 RANK_STRING => a.as_str().unwrap_or("").cmp(b.as_str().unwrap_or("")),
151 RANK_BOOL => bool_rank(a).cmp(&bool_rank(b)),
152 RANK_OBJECT => compare_objects(
153 a.as_object().expect("rank=object"),
154 b.as_object().expect("rank=object"),
155 ),
156 RANK_ARRAY => compare_arrays(
157 a.as_array().expect("rank=array"),
158 b.as_array().expect("rank=array"),
159 ),
160 RANK_OID => oid_str(a).cmp(oid_str(b)),
161 RANK_DATE => date_ms(a).cmp(&date_ms(b)),
162 RANK_TIMESTAMP => ts_parts(a).cmp(&ts_parts(b)),
163 RANK_BINARY => compare_binary(a, b),
164 RANK_REGEX => regex_parts(a).cmp(®ex_parts(b)),
165 _ => Ordering::Equal,
167 }
168}
169
170pub fn values_equal(a: &Value, b: &Value) -> bool {
172 compare(a, b) == Ordering::Equal
173}
174
175pub fn matches_value(actual: &Value, expected: &Value) -> bool {
179 if values_equal(actual, expected) {
180 return true;
181 }
182 match actual {
183 Value::Array(a) => a.iter().any(|el| values_equal(el, expected)),
184 _ => false,
185 }
186}
187
188fn compare_numbers(a: &Value, b: &Value) -> Ordering {
189 numeric_value(a)
190 .partial_cmp(&numeric_value(b))
191 .unwrap_or(Ordering::Equal)
192}
193
194pub fn as_number(v: &Value) -> Option<f64> {
199 match v {
200 Value::Number(n) => n.as_f64(),
201 Value::Object(o) => {
202 if let Some(s) = o.get("$numberLong").and_then(Value::as_str) {
203 s.parse::<f64>().ok()
204 } else {
205 o.get("$numberDecimal")
206 .and_then(Value::as_str)
207 .and_then(|s| s.parse::<f64>().ok())
208 }
209 }
210 _ => None,
211 }
212}
213
214fn numeric_value(v: &Value) -> f64 {
216 as_number(v).unwrap_or(0.0)
217}
218
219fn bool_rank(v: &Value) -> u8 {
220 u8::from(v.as_bool().unwrap_or(false))
221}
222
223fn compare_objects(a: &Map<String, Value>, b: &Map<String, Value>) -> Ordering {
224 let mut ai = a.iter();
225 let mut bi = b.iter();
226 loop {
227 match (ai.next(), bi.next()) {
228 (None, None) => return Ordering::Equal,
229 (None, Some(_)) => return Ordering::Less,
230 (Some(_), None) => return Ordering::Greater,
231 (Some((ka, va)), Some((kb, vb))) => {
232 let key_cmp = ka.cmp(kb);
233 if key_cmp != Ordering::Equal {
234 return key_cmp;
235 }
236 let val_cmp = compare(va, vb);
237 if val_cmp != Ordering::Equal {
238 return val_cmp;
239 }
240 }
241 }
242 }
243}
244
245fn compare_arrays(a: &[Value], b: &[Value]) -> Ordering {
246 for (x, y) in a.iter().zip(b.iter()) {
247 let c = compare(x, y);
248 if c != Ordering::Equal {
249 return c;
250 }
251 }
252 a.len().cmp(&b.len())
253}
254
255fn oid_str(v: &Value) -> &str {
256 v.get("$oid").and_then(Value::as_str).unwrap_or("")
257}
258
259fn date_ms(v: &Value) -> i64 {
260 v.get("$date").and_then(Value::as_i64).unwrap_or(0)
261}
262
263fn ts_parts(v: &Value) -> (i64, i64) {
264 match v.get("$timestamp").and_then(Value::as_object) {
265 Some(o) => (
266 o.get("t").and_then(Value::as_i64).unwrap_or(0),
267 o.get("i").and_then(Value::as_i64).unwrap_or(0),
268 ),
269 None => (0, 0),
270 }
271}
272
273fn compare_binary(a: &Value, b: &Value) -> Ordering {
274 let (a_b64, a_sub) = binary_parts(a);
276 let (b_b64, b_sub) = binary_parts(b);
277 a_b64
278 .len()
279 .cmp(&b_b64.len())
280 .then_with(|| a_sub.cmp(&b_sub))
281 .then_with(|| a_b64.cmp(&b_b64))
282}
283
284fn binary_parts(v: &Value) -> (String, String) {
285 match v.get("$binary").and_then(Value::as_object) {
286 Some(o) => (
287 o.get("base64")
288 .and_then(Value::as_str)
289 .unwrap_or("")
290 .to_string(),
291 o.get("subType")
292 .and_then(Value::as_str)
293 .unwrap_or("")
294 .to_string(),
295 ),
296 None => (String::new(), String::new()),
297 }
298}
299
300fn regex_parts(v: &Value) -> (String, String) {
301 match v.get("$regularExpression").and_then(Value::as_object) {
302 Some(o) => (
303 o.get("pattern")
304 .and_then(Value::as_str)
305 .unwrap_or("")
306 .to_string(),
307 o.get("options")
308 .and_then(Value::as_str)
309 .unwrap_or("")
310 .to_string(),
311 ),
312 None => (String::new(), String::new()),
313 }
314}
315
316pub fn eval_expr(expr: &Value, doc: &Value, vars: &Map<String, Value>) -> Result<Value, String> {
333 match expr {
334 Value::String(s) => eval_ref(s, doc, vars),
335 Value::Array(a) => a
336 .iter()
337 .map(|e| eval_expr(e, doc, vars))
338 .collect::<Result<Vec<_>, _>>()
339 .map(Value::Array),
340 Value::Object(o) => {
341 if bson::is_extended(expr) {
343 return Ok(expr.clone());
344 }
345 if o.len() == 1 {
346 if let Some(op) = o.keys().next().map(String::as_str) {
347 if let Some(stripped) = op.strip_prefix('$') {
348 return eval_operator(
349 stripped,
350 o.values().next().expect("len=1"),
351 doc,
352 vars,
353 );
354 }
355 }
356 }
357 let mut out = Map::new();
358 for (k, v) in o {
359 out.insert(k.clone(), eval_expr(v, doc, vars)?);
360 }
361 Ok(Value::Object(out))
362 }
363 other => Ok(other.clone()),
364 }
365}
366
367fn eval_operator(
368 op: &str,
369 arg: &Value,
370 doc: &Value,
371 vars: &Map<String, Value>,
372) -> Result<Value, String> {
373 match op {
374 "eq" => {
375 let (a, b) = two_operands("$eq", arg)?;
376 Ok(Value::Bool(values_equal(
377 &eval_expr(a, doc, vars)?,
378 &eval_expr(b, doc, vars)?,
379 )))
380 }
381 "and" => {
382 for e in array_operands("$and", arg)? {
383 if !truthy(&eval_expr(e, doc, vars)?) {
384 return Ok(Value::Bool(false));
385 }
386 }
387 Ok(Value::Bool(true))
388 }
389 "or" => {
390 for e in array_operands("$or", arg)? {
391 if truthy(&eval_expr(e, doc, vars)?) {
392 return Ok(Value::Bool(true));
393 }
394 }
395 Ok(Value::Bool(false))
396 }
397 "ifNull" => {
398 let (a, b) = two_operands("$ifNull", arg)?;
399 let v = eval_expr(a, doc, vars)?;
400 if v.is_null() {
401 eval_expr(b, doc, vars)
402 } else {
403 Ok(v)
404 }
405 }
406 "cond" => {
409 let (c, t, e) = cond_operands(arg)?;
410 if truthy(&eval_expr(c, doc, vars)?) {
411 eval_expr(t, doc, vars)
412 } else {
413 eval_expr(e, doc, vars)
414 }
415 }
416 "isArray" => Ok(Value::Bool(eval_expr(arg, doc, vars)?.is_array())),
417 "in" => {
419 let (needle, hay) = two_operands("$in", arg)?;
420 let needle = eval_expr(needle, doc, vars)?;
421 let hay = eval_expr(hay, doc, vars)?;
422 let items = hay
423 .as_array()
424 .ok_or_else(|| "$in 的第二个操作数必须是数组".to_string())?;
425 let hit = match &needle {
426 Value::Array(a) => a
427 .iter()
428 .any(|n| items.iter().any(|c| values_equal(n, c))),
429 other => items.iter().any(|c| values_equal(other, c)),
430 };
431 Ok(Value::Bool(hit))
432 }
433 "arrayElemAt" => {
435 let (arr_e, idx_e) = two_operands("$arrayElemAt", arg)?;
436 let arr = eval_expr(arr_e, doc, vars)?;
437 let idx_v = eval_expr(idx_e, doc, vars)?;
438 let idx = idx_v
439 .as_i64()
440 .ok_or_else(|| "$arrayElemAt 的下标必须是整数".to_string())?;
441 let items = arr
442 .as_array()
443 .ok_or_else(|| "$arrayElemAt 的第一个操作数必须是数组".to_string())?;
444 let len = items.len() as i64;
445 let i = if idx < 0 { len + idx } else { idx };
446 Ok(items.get(i as usize).cloned().unwrap_or(Value::Null))
448 }
449 "size" => {
451 let arr = eval_expr(arg, doc, vars)?;
452 let items = arr
453 .as_array()
454 .ok_or_else(|| format!("$size 的操作数必须是数组,收到 {}", value_type_name(&arr)))?;
455 Ok(Value::from(items.len() as i64))
456 }
457 "sum" | "avg" | "min" | "max" => {
462 let v = eval_expr(arg, doc, vars)?;
463 match v {
464 Value::Array(items) => accumulate_expr(op, &items),
465 other => accumulate_expr(op, std::slice::from_ref(&other)),
466 }
467 }
468 other => Err(format!(
469 "不支持的聚合表达式算子: ${other}(本地求值器仅支持 $eq/$and/$or/$ifNull/$cond/$isArray/$in/$arrayElemAt/$size/$sum/$avg/$min/$max,拒绝静默)"
470 )),
471 }
472}
473
474fn accumulate_expr(op: &str, items: &[Value]) -> Result<Value, String> {
477 match op {
478 "sum" => {
479 let mut sum = 0.0_f64;
480 for v in items {
481 if let Some(n) = as_number(v) {
482 sum += n;
483 }
484 }
485 Ok(number_of(sum))
486 }
487 "avg" => {
488 let (mut sum, mut count) = (0.0_f64, 0_usize);
489 for v in items {
490 if let Some(n) = as_number(v) {
491 sum += n;
492 count += 1;
493 }
494 }
495 Ok(if count == 0 {
496 Value::Null
497 } else {
498 float_of(sum / count as f64)
499 })
500 }
501 _ => {
502 let mut best: Option<&Value> = None;
503 for v in items {
504 if v.is_null() {
505 continue;
506 }
507 best = Some(match best {
508 None => v,
509 Some(cur) => {
510 let take = if op == "min" {
511 compare(v, cur) == Ordering::Less
512 } else {
513 compare(v, cur) == Ordering::Greater
514 };
515 if take {
516 v
517 } else {
518 cur
519 }
520 }
521 });
522 }
523 Ok(best.cloned().unwrap_or(Value::Null))
524 }
525 }
526}
527
528fn value_type_name(v: &Value) -> &'static str {
529 match v {
530 Value::Null => "null",
531 Value::Bool(_) => "bool",
532 Value::Number(_) => "number",
533 Value::String(_) => "string",
534 Value::Array(_) => "array",
535 Value::Object(_) => "object",
536 }
537}
538
539fn two_operands<'a>(name: &str, arg: &'a Value) -> Result<(&'a Value, &'a Value), String> {
540 let arr = arg
541 .as_array()
542 .ok_or_else(|| format!("{name} 需要操作数数组"))?;
543 if arr.len() != 2 {
544 return Err(format!("{name} 需要恰好两个操作数,收到 {}", arr.len()));
545 }
546 Ok((&arr[0], &arr[1]))
547}
548
549fn array_operands<'a>(name: &str, arg: &'a Value) -> Result<&'a [Value], String> {
550 arg.as_array()
551 .map(Vec::as_slice)
552 .ok_or_else(|| format!("{name} 需要操作数数组"))
553}
554
555fn cond_operands(arg: &Value) -> Result<(&Value, &Value, &Value), String> {
557 if let Some(a) = arg.as_array() {
558 if a.len() != 3 {
559 return Err(format!("$cond 数组形态需要 3 个操作数,收到 {}", a.len()));
560 }
561 return Ok((&a[0], &a[1], &a[2]));
562 }
563 if let Some(o) = arg.as_object() {
564 let pick = |k: &str| {
565 o.get(k)
566 .ok_or_else(|| format!("$cond 对象形态缺少 \"{k}\""))
567 };
568 return Ok((pick("if")?, pick("then")?, pick("else")?));
569 }
570 Err("$cond 需要数组 [if, then, else] 或对象 {if, then, else}".to_string())
571}
572
573fn truthy(v: &Value) -> bool {
575 match v {
576 Value::Null => false,
577 Value::Bool(b) => *b,
578 Value::Number(n) => n.as_f64().map(|x| x != 0.0).unwrap_or(true),
579 _ => true,
580 }
581}
582
583fn eval_ref(s: &str, doc: &Value, vars: &Map<String, Value>) -> Result<Value, String> {
585 if let Some(rest) = s.strip_prefix("$$") {
586 let (name, path) = match rest.split_once('.') {
587 Some((n, p)) => (n, p),
588 None => (rest, ""),
589 };
590 let base = vars.get(name).cloned().unwrap_or(Value::Null);
591 Ok(reference_path(&base, path))
592 } else if let Some(rest) = s.strip_prefix('$') {
593 Ok(get_path(doc, rest).cloned().unwrap_or(Value::Null))
594 } else {
595 Ok(Value::String(s.to_string()))
596 }
597}
598
599fn reference_path(base: &Value, path: &str) -> Value {
600 if path.is_empty() {
601 base.clone()
602 } else {
603 get_path(base, path).cloned().unwrap_or(Value::Null)
604 }
605}
606
607pub fn apply_projection(doc: &Value, projection: &Value) -> Result<Value, String> {
615 let obj = projection
616 .as_object()
617 .ok_or_else(|| format!("投影必须是对象,收到 {}", type_name(projection)))?;
618 if obj.is_empty() {
619 return Ok(doc.clone());
620 }
621
622 let mut include_paths: Vec<&String> = Vec::new();
623 let mut exclude_paths: Vec<&String> = Vec::new();
624 let mut id: Option<bool> = None;
625 for (k, v) in obj {
626 let flag = projection_flag(v)?;
627 if k == "_id" {
628 id = Some(flag);
629 } else if flag {
630 include_paths.push(k);
631 } else {
632 exclude_paths.push(k);
633 }
634 }
635 if !include_paths.is_empty() && !exclude_paths.is_empty() {
636 return Err("投影不允许同时包含与排除字段(`_id` 除外)".to_string());
637 }
638
639 let include_mode = if !include_paths.is_empty() {
640 true
641 } else if !exclude_paths.is_empty() {
642 false
643 } else {
644 id == Some(true)
646 };
647
648 if include_mode {
649 let mut out = Map::new();
650 if id != Some(false) {
651 if let Some(v) = doc.get("_id") {
652 out.insert("_id".to_string(), v.clone());
653 }
654 }
655 for path in &include_paths {
656 if let Some(v) = project_included(doc, &segments(path)) {
657 merge_into(&mut out, v);
658 }
659 }
660 Ok(Value::Object(out))
661 } else {
662 let mut out = doc.clone();
663 for path in &exclude_paths {
664 remove_segments(&mut out, &segments(path));
665 }
666 if id == Some(false) {
667 if let Value::Object(m) = &mut out {
668 m.remove("_id");
669 }
670 }
671 Ok(out)
672 }
673}
674
675fn projection_flag(v: &Value) -> Result<bool, String> {
677 match v {
678 Value::Bool(b) => Ok(*b),
679 Value::Number(n) => match (n.as_i64(), n.as_f64()) {
680 (Some(0), _) | (_, Some(0.0)) => Ok(false),
681 (Some(1), _) | (_, Some(1.0)) => Ok(true),
682 _ => Err(format!("投影值必须是 0/1 或 false/true,收到 {n}")),
683 },
684 other => Err(format!(
685 "不支持的投影形态: {other}(本地求值器仅支持包含/排除,拒绝静默)"
686 )),
687 }
688}
689
690fn project_included(doc: &Value, segs: &[&str]) -> Option<Value> {
693 if segs.is_empty() {
694 return Some(doc.clone());
695 }
696 match doc {
697 Value::Object(o) => {
698 let child = o.get(segs[0])?;
699 let sub = project_included(child, &segs[1..])?;
700 let mut m = Map::new();
701 m.insert(segs[0].to_string(), sub);
702 Some(Value::Object(m))
703 }
704 Value::Array(a) => {
705 let mut arr = Vec::with_capacity(a.len());
706 for el in a {
707 if let Some(v) = project_included(el, segs) {
708 arr.push(v);
709 }
710 }
711 Some(Value::Array(arr))
712 }
713 _ => None,
714 }
715}
716
717pub fn project_include(doc: &Value, path: &str) -> Option<Value> {
721 project_included(doc, &segments(path))
722}
723
724pub fn merge_into(dst: &mut Map<String, Value>, src: Value) {
726 let Value::Object(src) = src else {
727 return;
728 };
729 for (k, v) in src {
730 let nested = matches!(dst.get(&k), Some(Value::Object(_))) && v.is_object();
731 if nested {
732 if let Some(Value::Object(d)) = dst.get_mut(&k) {
733 merge_into(d, v);
734 }
735 } else {
736 dst.insert(k, v);
737 }
738 }
739}
740
741pub fn remove_path(doc: &mut Value, path: &str) {
743 remove_segments(doc, &segments(path));
744}
745
746pub fn set_path(doc: &mut Value, path: &str, val: Value) {
748 set_segments(doc, &segments(path), val);
749}
750
751fn set_segments(cur: &mut Value, segs: &[&str], val: Value) {
752 if segs.is_empty() {
753 *cur = val;
754 return;
755 }
756 if !cur.is_object() {
757 *cur = Value::Object(Map::new());
758 }
759 let Value::Object(o) = cur else { return };
760 if segs.len() == 1 {
761 o.insert(segs[0].to_string(), val);
762 return;
763 }
764 let entry = o
765 .entry(segs[0].to_string())
766 .or_insert_with(|| Value::Object(Map::new()));
767 set_segments(entry, &segs[1..], val);
768}
769
770fn remove_segments(doc: &mut Value, segs: &[&str]) {
771 if segs.is_empty() {
772 return;
773 }
774 match doc {
775 Value::Object(o) => {
776 if segs.len() == 1 {
777 o.remove(segs[0]);
778 } else if let Some(v) = o.get_mut(segs[0]) {
779 remove_segments(v, &segs[1..]);
780 }
781 }
782 Value::Array(a) => {
783 for el in a {
784 remove_segments(el, segs);
785 }
786 }
787 _ => {}
788 }
789}
790
791fn type_name(v: &Value) -> &'static str {
792 match v {
793 Value::Null => "null",
794 Value::Bool(_) => "bool",
795 Value::Number(_) => "number",
796 Value::String(_) => "string",
797 Value::Array(_) => "array",
798 Value::Object(_) => "object",
799 }
800}
801
802#[cfg(test)]
803mod tests {
804 use super::*;
805 use serde_json::json;
806
807 #[test]
808 fn max_docs_guard_constant() {
809 assert_eq!(MAX_LOCAL_COLLECTION_DOCS, 100_000);
810 }
811
812 #[test]
813 fn get_path_three_states() {
814 let doc = json!({ "a": null, "b": { "c": 1 } });
815 assert_eq!(get_path(&doc, "a"), Some(&Value::Null));
817 assert_eq!(get_path(&doc, "missing"), None);
818 assert_eq!(get_path(&doc, "b.missing"), None);
819 assert_eq!(get_path(&doc, "b.c"), Some(&json!(1)));
820 let arr = json!({ "a": [ { "b": 1 } ] });
822 assert_eq!(get_path(&arr, "a.b"), None);
823 }
824
825 #[test]
826 fn candidates_three_states_and_array_expansion() {
827 let doc = json!({ "a": null, "arr": [ { "b": 1 }, { "b": 2 } ] });
828 assert!(resolve_path_candidates(&doc, "missing").is_empty());
830 assert_eq!(resolve_path_candidates(&doc, "a"), vec![&Value::Null]);
831 assert_eq!(
833 resolve_path_candidates(&doc, "arr.b"),
834 vec![&json!(1), &json!(2)]
835 );
836 let tags = json!({ "tags": ["x", "y"] });
838 assert_eq!(
839 resolve_path_candidates(&tags, "tags"),
840 vec![&json!(["x", "y"])]
841 );
842 }
843
844 #[test]
845 fn bson_type_order_across_types() {
846 let min = json!({ "$minKey": 1 });
847 let null = Value::Null;
848 let num = json!(5);
849 let s = json!("abc");
850 let obj = json!({ "x": 1 });
851 let arr = json!([1, 2]);
852 let boolean = json!(true);
853 let date = json!({ "$date": 0 });
854 let max = json!({ "$maxKey": 1 });
855 let seq = [&min, &null, &num, &s, &obj, &arr, &boolean, &date, &max];
856 for (i, a) in seq.iter().enumerate() {
857 for (j, b) in seq.iter().enumerate() {
858 assert_eq!(compare(a, b), i.cmp(&j), "rank {i} vs {j}");
859 }
860 }
861 }
862
863 #[test]
864 fn number_order_across_int_and_float() {
865 assert_eq!(compare(&json!(1), &json!(1.0)), Ordering::Equal);
866 assert!(values_equal(&json!(1), &json!(1.0)));
867 assert_eq!(compare(&json!(2), &json!(1.5)), Ordering::Greater);
868 assert_eq!(compare(&json!(-1), &json!(0)), Ordering::Less);
869 assert!(values_equal(&json!({ "$numberLong": "3" }), &json!(3)));
871 }
872
873 #[test]
874 fn compare_object_and_array() {
875 assert_eq!(
876 compare(&json!({ "a": 1 }), &json!({ "a": 2 })),
877 Ordering::Less
878 );
879 assert_eq!(
881 compare(&json!({ "a": 2 }), &json!({ "a": 2, "b": 1 })),
882 Ordering::Less
883 );
884 assert_eq!(compare(&json!([1, 2]), &json!([1, 2, 3])), Ordering::Less);
885 assert_eq!(compare(&json!([1, 3]), &json!([1, 2])), Ordering::Greater);
886 }
887
888 #[test]
889 fn array_eq_hit_helper() {
890 assert!(matches_value(&json!(["x", "y"]), &json!("x")));
892 assert!(matches_value(&json!("x"), &json!("x")));
893 assert!(!matches_value(&json!(["y"]), &json!("x")));
894 }
895
896 #[test]
897 fn eval_expr_minimal() {
898 let doc = json!({ "x": 1, "y": 2 });
899 let vars = Map::new();
900 assert_eq!(
901 eval_expr(&json!({ "$eq": ["$x", 1] }), &doc, &vars).unwrap(),
902 json!(true)
903 );
904 assert_eq!(
905 eval_expr(&json!({ "$eq": ["$x", "$y"] }), &doc, &vars).unwrap(),
906 json!(false)
907 );
908 assert_eq!(
909 eval_expr(
910 &json!({ "$and": [ { "$eq": ["$x", 1] }, { "$eq": ["$y", 2] } ] }),
911 &doc,
912 &vars
913 )
914 .unwrap(),
915 json!(true)
916 );
917 assert_eq!(
919 eval_expr(&json!({ "$ifNull": ["$missing", "d"] }), &doc, &vars).unwrap(),
920 json!("d")
921 );
922 let mut vars2 = Map::new();
924 vars2.insert("v".to_string(), json!(42));
925 assert_eq!(eval_expr(&json!("$$v"), &doc, &vars2).unwrap(), json!(42));
926 assert_eq!(
927 eval_expr(&json!({ "$eq": ["$x", "$$v"] }), &doc, &vars2).unwrap(),
928 json!(false)
929 );
930 assert!(eval_expr(&json!({ "$mul": [1, 2] }), &doc, &vars).is_err());
932 }
933
934 #[test]
935 fn expr_size() {
936 let vars = Map::new();
937 let doc = json!({ "arr": [1, 2, 3], "empty": [], "n": 5 });
938 assert_eq!(
939 eval_expr(&json!({ "$size": "$arr" }), &doc, &vars).unwrap(),
940 json!(3)
941 );
942 assert_eq!(
943 eval_expr(&json!({ "$size": "$empty" }), &doc, &vars).unwrap(),
944 json!(0)
945 );
946 assert!(eval_expr(&json!({ "$size": "$n" }), &doc, &vars).is_err());
948 assert!(eval_expr(&json!({ "$size": "$missing" }), &doc, &vars).is_err());
949 }
950
951 #[test]
952 fn expr_sum_avg_min_max_array_form() {
953 let vars = Map::new();
954 let doc = json!({
955 "scores": [3, 7, 5],
956 "mixed": [1, "x", 4, null],
957 "empty": [],
958 "gone": null,
959 "one": 9
960 });
961 assert_eq!(
963 eval_expr(&json!({ "$sum": "$scores" }), &doc, &vars).unwrap(),
964 json!(15)
965 );
966 assert_eq!(
968 eval_expr(&json!({ "$sum": "$mixed" }), &doc, &vars).unwrap(),
969 json!(5)
970 );
971 assert_eq!(
972 eval_expr(&json!({ "$sum": "$empty" }), &doc, &vars).unwrap(),
973 json!(0)
974 );
975 assert_eq!(
976 eval_expr(&json!({ "$sum": "$gone" }), &doc, &vars).unwrap(),
977 json!(0)
978 );
979 assert_eq!(
980 eval_expr(&json!({ "$sum": "$missing" }), &doc, &vars).unwrap(),
981 json!(0)
982 );
983 assert_eq!(
985 eval_expr(&json!({ "$avg": "$scores" }), &doc, &vars).unwrap(),
986 json!(5.0)
987 );
988 assert_eq!(
989 eval_expr(&json!({ "$avg": "$empty" }), &doc, &vars).unwrap(),
990 Value::Null
991 );
992 assert_eq!(
993 eval_expr(&json!({ "$avg": "$missing" }), &doc, &vars).unwrap(),
994 Value::Null
995 );
996 assert_eq!(
998 eval_expr(&json!({ "$min": "$scores" }), &doc, &vars).unwrap(),
999 json!(3)
1000 );
1001 assert_eq!(
1002 eval_expr(&json!({ "$max": "$scores" }), &doc, &vars).unwrap(),
1003 json!(7)
1004 );
1005 assert_eq!(
1006 eval_expr(&json!({ "$min": "$mixed" }), &doc, &vars).unwrap(),
1007 json!(1)
1008 );
1009 assert_eq!(
1010 eval_expr(&json!({ "$min": "$empty" }), &doc, &vars).unwrap(),
1011 Value::Null
1012 );
1013 assert_eq!(
1015 eval_expr(&json!({ "$sum": "$one" }), &doc, &vars).unwrap(),
1016 json!(9)
1017 );
1018 assert_eq!(
1019 eval_expr(&json!({ "$avg": "$one" }), &doc, &vars).unwrap(),
1020 json!(9.0)
1021 );
1022 assert_eq!(
1023 eval_expr(&json!({ "$min": "$one" }), &doc, &vars).unwrap(),
1024 json!(9)
1025 );
1026 }
1027
1028 #[test]
1029 fn projection_include_nested() {
1030 let doc = json!({ "_id": 7, "a": { "b": 1, "c": 2 }, "d": 3 });
1031 assert_eq!(
1033 apply_projection(&doc, &json!({ "a.b": 1 })).unwrap(),
1034 json!({ "_id": 7, "a": { "b": 1 } })
1035 );
1036 assert_eq!(
1038 apply_projection(&doc, &json!({ "d": 1 })).unwrap(),
1039 json!({ "_id": 7, "d": 3 })
1040 );
1041 assert_eq!(
1043 apply_projection(&doc, &json!({ "d": 1, "_id": 0 })).unwrap(),
1044 json!({ "d": 3 })
1045 );
1046 }
1047
1048 #[test]
1049 fn projection_exclude_and_errors() {
1050 let doc = json!({ "_id": 7, "a": { "b": 1, "c": 2 }, "d": 3 });
1051 assert_eq!(
1053 apply_projection(&doc, &json!({ "a.b": 0 })).unwrap(),
1054 json!({ "_id": 7, "a": { "c": 2 }, "d": 3 })
1055 );
1056 assert_eq!(
1058 apply_projection(&doc, &json!({ "_id": 0 })).unwrap(),
1059 json!({ "a": { "b": 1, "c": 2 }, "d": 3 })
1060 );
1061 assert!(apply_projection(&doc, &json!({ "a": 1, "d": 0 })).is_err());
1063 assert!(apply_projection(&doc, &json!({ "a": 2 })).is_err());
1065 }
1066}