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(stripped, o.values().next().expect("len=1"), doc, vars);
349 }
350 }
351 }
352 let mut out = Map::new();
353 for (k, v) in o {
354 out.insert(k.clone(), eval_expr(v, doc, vars)?);
355 }
356 Ok(Value::Object(out))
357 }
358 other => Ok(other.clone()),
359 }
360}
361
362fn eval_operator(
363 op: &str,
364 arg: &Value,
365 doc: &Value,
366 vars: &Map<String, Value>,
367) -> Result<Value, String> {
368 match op {
369 "eq" => {
370 let (a, b) = two_operands("$eq", arg)?;
371 Ok(Value::Bool(values_equal(
372 &eval_expr(a, doc, vars)?,
373 &eval_expr(b, doc, vars)?,
374 )))
375 }
376 "and" => {
377 for e in array_operands("$and", arg)? {
378 if !truthy(&eval_expr(e, doc, vars)?) {
379 return Ok(Value::Bool(false));
380 }
381 }
382 Ok(Value::Bool(true))
383 }
384 "or" => {
385 for e in array_operands("$or", arg)? {
386 if truthy(&eval_expr(e, doc, vars)?) {
387 return Ok(Value::Bool(true));
388 }
389 }
390 Ok(Value::Bool(false))
391 }
392 "ifNull" => {
393 let (a, b) = two_operands("$ifNull", arg)?;
394 let v = eval_expr(a, doc, vars)?;
395 if v.is_null() {
396 eval_expr(b, doc, vars)
397 } else {
398 Ok(v)
399 }
400 }
401 "cond" => {
404 let (c, t, e) = cond_operands(arg)?;
405 if truthy(&eval_expr(c, doc, vars)?) {
406 eval_expr(t, doc, vars)
407 } else {
408 eval_expr(e, doc, vars)
409 }
410 }
411 "isArray" => Ok(Value::Bool(eval_expr(arg, doc, vars)?.is_array())),
412 "in" => {
414 let (needle, hay) = two_operands("$in", arg)?;
415 let needle = eval_expr(needle, doc, vars)?;
416 let hay = eval_expr(hay, doc, vars)?;
417 let items = hay
418 .as_array()
419 .ok_or_else(|| "$in 的第二个操作数必须是数组".to_string())?;
420 let hit = match &needle {
421 Value::Array(a) => a
422 .iter()
423 .any(|n| items.iter().any(|c| values_equal(n, c))),
424 other => items.iter().any(|c| values_equal(other, c)),
425 };
426 Ok(Value::Bool(hit))
427 }
428 "arrayElemAt" => {
430 let (arr_e, idx_e) = two_operands("$arrayElemAt", arg)?;
431 let arr = eval_expr(arr_e, doc, vars)?;
432 let idx_v = eval_expr(idx_e, doc, vars)?;
433 let idx = idx_v
434 .as_i64()
435 .ok_or_else(|| "$arrayElemAt 的下标必须是整数".to_string())?;
436 let items = arr
437 .as_array()
438 .ok_or_else(|| "$arrayElemAt 的第一个操作数必须是数组".to_string())?;
439 let len = items.len() as i64;
440 let i = if idx < 0 { len + idx } else { idx };
441 Ok(items.get(i as usize).cloned().unwrap_or(Value::Null))
443 }
444 "size" => {
446 let arr = eval_expr(arg, doc, vars)?;
447 let items = arr
448 .as_array()
449 .ok_or_else(|| format!("$size 的操作数必须是数组,收到 {}", value_type_name(&arr)))?;
450 Ok(Value::from(items.len() as i64))
451 }
452 "sum" | "avg" | "min" | "max" => {
457 let v = eval_expr(arg, doc, vars)?;
458 match v {
459 Value::Array(items) => accumulate_expr(op, &items),
460 other => accumulate_expr(op, std::slice::from_ref(&other)),
461 }
462 }
463 other => Err(format!(
464 "不支持的聚合表达式算子: ${other}(本地求值器仅支持 $eq/$and/$or/$ifNull/$cond/$isArray/$in/$arrayElemAt/$size/$sum/$avg/$min/$max,拒绝静默)"
465 )),
466 }
467}
468
469fn accumulate_expr(op: &str, items: &[Value]) -> Result<Value, String> {
472 match op {
473 "sum" => {
474 let mut sum = 0.0_f64;
475 for v in items {
476 if let Some(n) = as_number(v) {
477 sum += n;
478 }
479 }
480 Ok(number_of(sum))
481 }
482 "avg" => {
483 let (mut sum, mut count) = (0.0_f64, 0_usize);
484 for v in items {
485 if let Some(n) = as_number(v) {
486 sum += n;
487 count += 1;
488 }
489 }
490 Ok(if count == 0 {
491 Value::Null
492 } else {
493 float_of(sum / count as f64)
494 })
495 }
496 _ => {
497 let mut best: Option<&Value> = None;
498 for v in items {
499 if v.is_null() {
500 continue;
501 }
502 best = Some(match best {
503 None => v,
504 Some(cur) => {
505 let take = if op == "min" {
506 compare(v, cur) == Ordering::Less
507 } else {
508 compare(v, cur) == Ordering::Greater
509 };
510 if take {
511 v
512 } else {
513 cur
514 }
515 }
516 });
517 }
518 Ok(best.cloned().unwrap_or(Value::Null))
519 }
520 }
521}
522
523fn value_type_name(v: &Value) -> &'static str {
524 match v {
525 Value::Null => "null",
526 Value::Bool(_) => "bool",
527 Value::Number(_) => "number",
528 Value::String(_) => "string",
529 Value::Array(_) => "array",
530 Value::Object(_) => "object",
531 }
532}
533
534fn two_operands<'a>(name: &str, arg: &'a Value) -> Result<(&'a Value, &'a Value), String> {
535 let arr = arg
536 .as_array()
537 .ok_or_else(|| format!("{name} 需要操作数数组"))?;
538 if arr.len() != 2 {
539 return Err(format!("{name} 需要恰好两个操作数,收到 {}", arr.len()));
540 }
541 Ok((&arr[0], &arr[1]))
542}
543
544fn array_operands<'a>(name: &str, arg: &'a Value) -> Result<&'a [Value], String> {
545 arg.as_array()
546 .map(Vec::as_slice)
547 .ok_or_else(|| format!("{name} 需要操作数数组"))
548}
549
550fn cond_operands(arg: &Value) -> Result<(&Value, &Value, &Value), String> {
552 if let Some(a) = arg.as_array() {
553 if a.len() != 3 {
554 return Err(format!("$cond 数组形态需要 3 个操作数,收到 {}", a.len()));
555 }
556 return Ok((&a[0], &a[1], &a[2]));
557 }
558 if let Some(o) = arg.as_object() {
559 let pick = |k: &str| {
560 o.get(k)
561 .ok_or_else(|| format!("$cond 对象形态缺少 \"{k}\""))
562 };
563 return Ok((pick("if")?, pick("then")?, pick("else")?));
564 }
565 Err("$cond 需要数组 [if, then, else] 或对象 {if, then, else}".to_string())
566}
567
568fn truthy(v: &Value) -> bool {
570 match v {
571 Value::Null => false,
572 Value::Bool(b) => *b,
573 Value::Number(n) => n.as_f64().map(|x| x != 0.0).unwrap_or(true),
574 _ => true,
575 }
576}
577
578fn eval_ref(s: &str, doc: &Value, vars: &Map<String, Value>) -> Result<Value, String> {
580 if let Some(rest) = s.strip_prefix("$$") {
581 let (name, path) = match rest.split_once('.') {
582 Some((n, p)) => (n, p),
583 None => (rest, ""),
584 };
585 let base = vars.get(name).cloned().unwrap_or(Value::Null);
586 Ok(reference_path(&base, path))
587 } else if let Some(rest) = s.strip_prefix('$') {
588 Ok(get_path(doc, rest).cloned().unwrap_or(Value::Null))
589 } else {
590 Ok(Value::String(s.to_string()))
591 }
592}
593
594fn reference_path(base: &Value, path: &str) -> Value {
595 if path.is_empty() {
596 base.clone()
597 } else {
598 get_path(base, path).cloned().unwrap_or(Value::Null)
599 }
600}
601
602pub fn apply_projection(doc: &Value, projection: &Value) -> Result<Value, String> {
610 let obj = projection
611 .as_object()
612 .ok_or_else(|| format!("投影必须是对象,收到 {}", type_name(projection)))?;
613 if obj.is_empty() {
614 return Ok(doc.clone());
615 }
616
617 let mut include_paths: Vec<&String> = Vec::new();
618 let mut exclude_paths: Vec<&String> = Vec::new();
619 let mut id: Option<bool> = None;
620 for (k, v) in obj {
621 let flag = projection_flag(v)?;
622 if k == "_id" {
623 id = Some(flag);
624 } else if flag {
625 include_paths.push(k);
626 } else {
627 exclude_paths.push(k);
628 }
629 }
630 if !include_paths.is_empty() && !exclude_paths.is_empty() {
631 return Err("投影不允许同时包含与排除字段(`_id` 除外)".to_string());
632 }
633
634 let include_mode = if !include_paths.is_empty() {
635 true
636 } else if !exclude_paths.is_empty() {
637 false
638 } else {
639 id == Some(true)
641 };
642
643 if include_mode {
644 let mut out = Map::new();
645 if id != Some(false) {
646 if let Some(v) = doc.get("_id") {
647 out.insert("_id".to_string(), v.clone());
648 }
649 }
650 for path in &include_paths {
651 if let Some(v) = project_included(doc, &segments(path)) {
652 merge_into(&mut out, v);
653 }
654 }
655 Ok(Value::Object(out))
656 } else {
657 let mut out = doc.clone();
658 for path in &exclude_paths {
659 remove_segments(&mut out, &segments(path));
660 }
661 if id == Some(false) {
662 if let Value::Object(m) = &mut out {
663 m.remove("_id");
664 }
665 }
666 Ok(out)
667 }
668}
669
670fn projection_flag(v: &Value) -> Result<bool, String> {
672 match v {
673 Value::Bool(b) => Ok(*b),
674 Value::Number(n) => match (n.as_i64(), n.as_f64()) {
675 (Some(0), _) | (_, Some(0.0)) => Ok(false),
676 (Some(1), _) | (_, Some(1.0)) => Ok(true),
677 _ => Err(format!("投影值必须是 0/1 或 false/true,收到 {n}")),
678 },
679 other => Err(format!(
680 "不支持的投影形态: {other}(本地求值器仅支持包含/排除,拒绝静默)"
681 )),
682 }
683}
684
685fn project_included(doc: &Value, segs: &[&str]) -> Option<Value> {
688 if segs.is_empty() {
689 return Some(doc.clone());
690 }
691 match doc {
692 Value::Object(o) => {
693 let child = o.get(segs[0])?;
694 let sub = project_included(child, &segs[1..])?;
695 let mut m = Map::new();
696 m.insert(segs[0].to_string(), sub);
697 Some(Value::Object(m))
698 }
699 Value::Array(a) => {
700 let mut arr = Vec::with_capacity(a.len());
701 for el in a {
702 if let Some(v) = project_included(el, segs) {
703 arr.push(v);
704 }
705 }
706 Some(Value::Array(arr))
707 }
708 _ => None,
709 }
710}
711
712pub fn project_include(doc: &Value, path: &str) -> Option<Value> {
716 project_included(doc, &segments(path))
717}
718
719pub fn merge_into(dst: &mut Map<String, Value>, src: Value) {
721 let Value::Object(src) = src else {
722 return;
723 };
724 for (k, v) in src {
725 let nested = matches!(dst.get(&k), Some(Value::Object(_))) && v.is_object();
726 if nested {
727 if let Some(Value::Object(d)) = dst.get_mut(&k) {
728 merge_into(d, v);
729 }
730 } else {
731 dst.insert(k, v);
732 }
733 }
734}
735
736pub fn remove_path(doc: &mut Value, path: &str) {
738 remove_segments(doc, &segments(path));
739}
740
741pub fn set_path(doc: &mut Value, path: &str, val: Value) {
743 set_segments(doc, &segments(path), val);
744}
745
746fn set_segments(cur: &mut Value, segs: &[&str], val: Value) {
747 if segs.is_empty() {
748 *cur = val;
749 return;
750 }
751 if !cur.is_object() {
752 *cur = Value::Object(Map::new());
753 }
754 let Value::Object(o) = cur else { return };
755 if segs.len() == 1 {
756 o.insert(segs[0].to_string(), val);
757 return;
758 }
759 let entry = o
760 .entry(segs[0].to_string())
761 .or_insert_with(|| Value::Object(Map::new()));
762 set_segments(entry, &segs[1..], val);
763}
764
765fn remove_segments(doc: &mut Value, segs: &[&str]) {
766 if segs.is_empty() {
767 return;
768 }
769 match doc {
770 Value::Object(o) => {
771 if segs.len() == 1 {
772 o.remove(segs[0]);
773 } else if let Some(v) = o.get_mut(segs[0]) {
774 remove_segments(v, &segs[1..]);
775 }
776 }
777 Value::Array(a) => {
778 for el in a {
779 remove_segments(el, segs);
780 }
781 }
782 _ => {}
783 }
784}
785
786fn type_name(v: &Value) -> &'static str {
787 match v {
788 Value::Null => "null",
789 Value::Bool(_) => "bool",
790 Value::Number(_) => "number",
791 Value::String(_) => "string",
792 Value::Array(_) => "array",
793 Value::Object(_) => "object",
794 }
795}
796
797#[cfg(test)]
798mod tests {
799 use super::*;
800 use serde_json::json;
801
802 #[test]
803 fn max_docs_guard_constant() {
804 assert_eq!(MAX_LOCAL_COLLECTION_DOCS, 100_000);
805 }
806
807 #[test]
808 fn get_path_three_states() {
809 let doc = json!({ "a": null, "b": { "c": 1 } });
810 assert_eq!(get_path(&doc, "a"), Some(&Value::Null));
812 assert_eq!(get_path(&doc, "missing"), None);
813 assert_eq!(get_path(&doc, "b.missing"), None);
814 assert_eq!(get_path(&doc, "b.c"), Some(&json!(1)));
815 let arr = json!({ "a": [ { "b": 1 } ] });
817 assert_eq!(get_path(&arr, "a.b"), None);
818 }
819
820 #[test]
821 fn candidates_three_states_and_array_expansion() {
822 let doc = json!({ "a": null, "arr": [ { "b": 1 }, { "b": 2 } ] });
823 assert!(resolve_path_candidates(&doc, "missing").is_empty());
825 assert_eq!(resolve_path_candidates(&doc, "a"), vec![&Value::Null]);
826 assert_eq!(
828 resolve_path_candidates(&doc, "arr.b"),
829 vec![&json!(1), &json!(2)]
830 );
831 let tags = json!({ "tags": ["x", "y"] });
833 assert_eq!(
834 resolve_path_candidates(&tags, "tags"),
835 vec![&json!(["x", "y"])]
836 );
837 }
838
839 #[test]
840 fn bson_type_order_across_types() {
841 let min = json!({ "$minKey": 1 });
842 let null = Value::Null;
843 let num = json!(5);
844 let s = json!("abc");
845 let obj = json!({ "x": 1 });
846 let arr = json!([1, 2]);
847 let boolean = json!(true);
848 let date = json!({ "$date": 0 });
849 let max = json!({ "$maxKey": 1 });
850 let seq = [&min, &null, &num, &s, &obj, &arr, &boolean, &date, &max];
851 for (i, a) in seq.iter().enumerate() {
852 for (j, b) in seq.iter().enumerate() {
853 assert_eq!(compare(a, b), i.cmp(&j), "rank {i} vs {j}");
854 }
855 }
856 }
857
858 #[test]
859 fn number_order_across_int_and_float() {
860 assert_eq!(compare(&json!(1), &json!(1.0)), Ordering::Equal);
861 assert!(values_equal(&json!(1), &json!(1.0)));
862 assert_eq!(compare(&json!(2), &json!(1.5)), Ordering::Greater);
863 assert_eq!(compare(&json!(-1), &json!(0)), Ordering::Less);
864 assert!(values_equal(&json!({ "$numberLong": "3" }), &json!(3)));
866 }
867
868 #[test]
869 fn compare_object_and_array() {
870 assert_eq!(
871 compare(&json!({ "a": 1 }), &json!({ "a": 2 })),
872 Ordering::Less
873 );
874 assert_eq!(
876 compare(&json!({ "a": 2 }), &json!({ "a": 2, "b": 1 })),
877 Ordering::Less
878 );
879 assert_eq!(compare(&json!([1, 2]), &json!([1, 2, 3])), Ordering::Less);
880 assert_eq!(compare(&json!([1, 3]), &json!([1, 2])), Ordering::Greater);
881 }
882
883 #[test]
884 fn array_eq_hit_helper() {
885 assert!(matches_value(&json!(["x", "y"]), &json!("x")));
887 assert!(matches_value(&json!("x"), &json!("x")));
888 assert!(!matches_value(&json!(["y"]), &json!("x")));
889 }
890
891 #[test]
892 fn eval_expr_minimal() {
893 let doc = json!({ "x": 1, "y": 2 });
894 let vars = Map::new();
895 assert_eq!(
896 eval_expr(&json!({ "$eq": ["$x", 1] }), &doc, &vars).unwrap(),
897 json!(true)
898 );
899 assert_eq!(
900 eval_expr(&json!({ "$eq": ["$x", "$y"] }), &doc, &vars).unwrap(),
901 json!(false)
902 );
903 assert_eq!(
904 eval_expr(
905 &json!({ "$and": [ { "$eq": ["$x", 1] }, { "$eq": ["$y", 2] } ] }),
906 &doc,
907 &vars
908 )
909 .unwrap(),
910 json!(true)
911 );
912 assert_eq!(
914 eval_expr(&json!({ "$ifNull": ["$missing", "d"] }), &doc, &vars).unwrap(),
915 json!("d")
916 );
917 let mut vars2 = Map::new();
919 vars2.insert("v".to_string(), json!(42));
920 assert_eq!(eval_expr(&json!("$$v"), &doc, &vars2).unwrap(), json!(42));
921 assert_eq!(
922 eval_expr(&json!({ "$eq": ["$x", "$$v"] }), &doc, &vars2).unwrap(),
923 json!(false)
924 );
925 assert!(eval_expr(&json!({ "$mul": [1, 2] }), &doc, &vars).is_err());
927 }
928
929 #[test]
930 fn expr_size() {
931 let vars = Map::new();
932 let doc = json!({ "arr": [1, 2, 3], "empty": [], "n": 5 });
933 assert_eq!(eval_expr(&json!({ "$size": "$arr" }), &doc, &vars).unwrap(), json!(3));
934 assert_eq!(eval_expr(&json!({ "$size": "$empty" }), &doc, &vars).unwrap(), json!(0));
935 assert!(eval_expr(&json!({ "$size": "$n" }), &doc, &vars).is_err());
937 assert!(eval_expr(&json!({ "$size": "$missing" }), &doc, &vars).is_err());
938 }
939
940 #[test]
941 fn expr_sum_avg_min_max_array_form() {
942 let vars = Map::new();
943 let doc = json!({
944 "scores": [3, 7, 5],
945 "mixed": [1, "x", 4, null],
946 "empty": [],
947 "gone": null,
948 "one": 9
949 });
950 assert_eq!(eval_expr(&json!({ "$sum": "$scores" }), &doc, &vars).unwrap(), json!(15));
952 assert_eq!(eval_expr(&json!({ "$sum": "$mixed" }), &doc, &vars).unwrap(), json!(5));
954 assert_eq!(eval_expr(&json!({ "$sum": "$empty" }), &doc, &vars).unwrap(), json!(0));
955 assert_eq!(eval_expr(&json!({ "$sum": "$gone" }), &doc, &vars).unwrap(), json!(0));
956 assert_eq!(eval_expr(&json!({ "$sum": "$missing" }), &doc, &vars).unwrap(), json!(0));
957 assert_eq!(eval_expr(&json!({ "$avg": "$scores" }), &doc, &vars).unwrap(), json!(5.0));
959 assert_eq!(eval_expr(&json!({ "$avg": "$empty" }), &doc, &vars).unwrap(), Value::Null);
960 assert_eq!(eval_expr(&json!({ "$avg": "$missing" }), &doc, &vars).unwrap(), Value::Null);
961 assert_eq!(eval_expr(&json!({ "$min": "$scores" }), &doc, &vars).unwrap(), json!(3));
963 assert_eq!(eval_expr(&json!({ "$max": "$scores" }), &doc, &vars).unwrap(), json!(7));
964 assert_eq!(eval_expr(&json!({ "$min": "$mixed" }), &doc, &vars).unwrap(), json!(1));
965 assert_eq!(eval_expr(&json!({ "$min": "$empty" }), &doc, &vars).unwrap(), Value::Null);
966 assert_eq!(eval_expr(&json!({ "$sum": "$one" }), &doc, &vars).unwrap(), json!(9));
968 assert_eq!(eval_expr(&json!({ "$avg": "$one" }), &doc, &vars).unwrap(), json!(9.0));
969 assert_eq!(eval_expr(&json!({ "$min": "$one" }), &doc, &vars).unwrap(), json!(9));
970 }
971
972 #[test]
973 fn projection_include_nested() {
974 let doc = json!({ "_id": 7, "a": { "b": 1, "c": 2 }, "d": 3 });
975 assert_eq!(
977 apply_projection(&doc, &json!({ "a.b": 1 })).unwrap(),
978 json!({ "_id": 7, "a": { "b": 1 } })
979 );
980 assert_eq!(
982 apply_projection(&doc, &json!({ "d": 1 })).unwrap(),
983 json!({ "_id": 7, "d": 3 })
984 );
985 assert_eq!(
987 apply_projection(&doc, &json!({ "d": 1, "_id": 0 })).unwrap(),
988 json!({ "d": 3 })
989 );
990 }
991
992 #[test]
993 fn projection_exclude_and_errors() {
994 let doc = json!({ "_id": 7, "a": { "b": 1, "c": 2 }, "d": 3 });
995 assert_eq!(
997 apply_projection(&doc, &json!({ "a.b": 0 })).unwrap(),
998 json!({ "_id": 7, "a": { "c": 2 }, "d": 3 })
999 );
1000 assert_eq!(
1002 apply_projection(&doc, &json!({ "_id": 0 })).unwrap(),
1003 json!({ "a": { "b": 1, "c": 2 }, "d": 3 })
1004 );
1005 assert!(apply_projection(&doc, &json!({ "a": 1, "d": 0 })).is_err());
1007 assert!(apply_projection(&doc, &json!({ "a": 2 })).is_err());
1009 }
1010}