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> {
335 match expr {
336 Value::String(s) => eval_ref(s, doc, vars),
337 Value::Array(a) => a
338 .iter()
339 .map(|e| eval_expr(e, doc, vars))
340 .collect::<Result<Vec<_>, _>>()
341 .map(Value::Array),
342 Value::Object(o) => {
343 if bson::is_extended(expr) {
345 return Ok(expr.clone());
346 }
347 if o.len() == 1 {
348 if let Some(op) = o.keys().next().map(String::as_str) {
349 if let Some(stripped) = op.strip_prefix('$') {
350 return eval_operator(
351 stripped,
352 o.values().next().expect("len=1"),
353 doc,
354 vars,
355 );
356 }
357 }
358 }
359 let mut out = Map::new();
360 for (k, v) in o {
361 out.insert(k.clone(), eval_expr(v, doc, vars)?);
362 }
363 Ok(Value::Object(out))
364 }
365 other => Ok(other.clone()),
366 }
367}
368
369fn eval_operator(
370 op: &str,
371 arg: &Value,
372 doc: &Value,
373 vars: &Map<String, Value>,
374) -> Result<Value, String> {
375 match op {
376 "eq" => {
377 let (a, b) = two_operands("$eq", arg)?;
378 Ok(Value::Bool(values_equal(
379 &eval_expr(a, doc, vars)?,
380 &eval_expr(b, doc, vars)?,
381 )))
382 }
383 "and" => {
384 for e in array_operands("$and", arg)? {
385 if !truthy(&eval_expr(e, doc, vars)?) {
386 return Ok(Value::Bool(false));
387 }
388 }
389 Ok(Value::Bool(true))
390 }
391 "or" => {
392 for e in array_operands("$or", arg)? {
393 if truthy(&eval_expr(e, doc, vars)?) {
394 return Ok(Value::Bool(true));
395 }
396 }
397 Ok(Value::Bool(false))
398 }
399 "ifNull" => {
400 let (a, b) = two_operands("$ifNull", arg)?;
401 let v = eval_expr(a, doc, vars)?;
402 if v.is_null() {
403 eval_expr(b, doc, vars)
404 } else {
405 Ok(v)
406 }
407 }
408 "cond" => {
411 let (c, t, e) = cond_operands(arg)?;
412 if truthy(&eval_expr(c, doc, vars)?) {
413 eval_expr(t, doc, vars)
414 } else {
415 eval_expr(e, doc, vars)
416 }
417 }
418 "isArray" => Ok(Value::Bool(eval_expr(arg, doc, vars)?.is_array())),
419 "in" => {
421 let (needle, hay) = two_operands("$in", arg)?;
422 let needle = eval_expr(needle, doc, vars)?;
423 let hay = eval_expr(hay, doc, vars)?;
424 let items = hay
425 .as_array()
426 .ok_or_else(|| "$in 的第二个操作数必须是数组".to_string())?;
427 let hit = match &needle {
428 Value::Array(a) => a
429 .iter()
430 .any(|n| items.iter().any(|c| values_equal(n, c))),
431 other => items.iter().any(|c| values_equal(other, c)),
432 };
433 Ok(Value::Bool(hit))
434 }
435 "arrayElemAt" => {
437 let (arr_e, idx_e) = two_operands("$arrayElemAt", arg)?;
438 let arr = eval_expr(arr_e, doc, vars)?;
439 let idx_v = eval_expr(idx_e, doc, vars)?;
440 let idx = idx_v
441 .as_i64()
442 .ok_or_else(|| "$arrayElemAt 的下标必须是整数".to_string())?;
443 let items = arr
444 .as_array()
445 .ok_or_else(|| "$arrayElemAt 的第一个操作数必须是数组".to_string())?;
446 let len = items.len() as i64;
447 let i = if idx < 0 { len + idx } else { idx };
448 Ok(items.get(i as usize).cloned().unwrap_or(Value::Null))
450 }
451 "ne" => {
455 let (a, b) = two_operands("$ne", arg)?;
456 Ok(Value::Bool(!values_equal(
457 &eval_expr(a, doc, vars)?,
458 &eval_expr(b, doc, vars)?,
459 )))
460 }
461 "filter" => {
462 let obj = arg
463 .as_object()
464 .ok_or("$filter 的参数必须是对象 {input, as?, cond}")?;
465 let input = obj.get("input").ok_or("$filter 缺少 input")?;
466 let cond = obj.get("cond").ok_or("$filter 缺少 cond")?;
467 let as_name = obj.get("as").and_then(|v| v.as_str()).unwrap_or("this");
468 let arr = eval_expr(input, doc, vars)?;
469 let items = arr.as_array().ok_or_else(|| {
470 format!(
471 "$filter 的 input 必须是数组,收到 {}",
472 value_type_name(&arr)
473 )
474 })?;
475 let mut out = Vec::with_capacity(items.len());
476 for item in items {
477 let mut inner_vars = vars.clone();
478 inner_vars.insert(as_name.to_string(), item.clone());
479 if truthy(&eval_expr(cond, doc, &inner_vars)?) {
480 out.push(item.clone());
481 }
482 }
483 Ok(Value::Array(out))
484 }
485 "setUnion" => {
486 let mut out: Vec<Value> = Vec::new();
489 for e in array_operands("$setUnion", arg)? {
490 let v = eval_expr(e, doc, vars)?;
491 let items = v.as_array().ok_or_else(|| {
492 format!(
493 "$setUnion 的操作数必须是数组,收到 {}",
494 value_type_name(&v)
495 )
496 })?;
497 for item in items {
498 if !out.iter().any(|c| values_equal(item, c)) {
499 out.push(item.clone());
500 }
501 }
502 }
503 Ok(Value::Array(out))
504 }
505 "size" => {
507 let arr = eval_expr(arg, doc, vars)?;
508 let items = arr
509 .as_array()
510 .ok_or_else(|| format!("$size 的操作数必须是数组,收到 {}", value_type_name(&arr)))?;
511 Ok(Value::from(items.len() as i64))
512 }
513 "sum" | "avg" | "min" | "max" => {
518 let v = eval_expr(arg, doc, vars)?;
519 match v {
520 Value::Array(items) => accumulate_expr(op, &items),
521 other => accumulate_expr(op, std::slice::from_ref(&other)),
522 }
523 }
524 other => Err(format!(
525 "不支持的聚合表达式算子: ${other}(本地求值器仅支持 $eq/$and/$or/$ifNull/$cond/$isArray/$in/$arrayElemAt/$size/$sum/$avg/$min/$max/$ne/$filter/$setUnion,拒绝静默)"
526 )),
527 }
528}
529
530fn accumulate_expr(op: &str, items: &[Value]) -> Result<Value, String> {
533 match op {
534 "sum" => {
535 let mut sum = 0.0_f64;
536 for v in items {
537 if let Some(n) = as_number(v) {
538 sum += n;
539 }
540 }
541 Ok(number_of(sum))
542 }
543 "avg" => {
544 let (mut sum, mut count) = (0.0_f64, 0_usize);
545 for v in items {
546 if let Some(n) = as_number(v) {
547 sum += n;
548 count += 1;
549 }
550 }
551 Ok(if count == 0 {
552 Value::Null
553 } else {
554 float_of(sum / count as f64)
555 })
556 }
557 _ => {
558 let mut best: Option<&Value> = None;
559 for v in items {
560 if v.is_null() {
561 continue;
562 }
563 best = Some(match best {
564 None => v,
565 Some(cur) => {
566 let take = if op == "min" {
567 compare(v, cur) == Ordering::Less
568 } else {
569 compare(v, cur) == Ordering::Greater
570 };
571 if take {
572 v
573 } else {
574 cur
575 }
576 }
577 });
578 }
579 Ok(best.cloned().unwrap_or(Value::Null))
580 }
581 }
582}
583
584fn value_type_name(v: &Value) -> &'static str {
585 match v {
586 Value::Null => "null",
587 Value::Bool(_) => "bool",
588 Value::Number(_) => "number",
589 Value::String(_) => "string",
590 Value::Array(_) => "array",
591 Value::Object(_) => "object",
592 }
593}
594
595fn two_operands<'a>(name: &str, arg: &'a Value) -> Result<(&'a Value, &'a Value), String> {
596 let arr = arg
597 .as_array()
598 .ok_or_else(|| format!("{name} 需要操作数数组"))?;
599 if arr.len() != 2 {
600 return Err(format!("{name} 需要恰好两个操作数,收到 {}", arr.len()));
601 }
602 Ok((&arr[0], &arr[1]))
603}
604
605fn array_operands<'a>(name: &str, arg: &'a Value) -> Result<&'a [Value], String> {
606 arg.as_array()
607 .map(Vec::as_slice)
608 .ok_or_else(|| format!("{name} 需要操作数数组"))
609}
610
611fn cond_operands(arg: &Value) -> Result<(&Value, &Value, &Value), String> {
613 if let Some(a) = arg.as_array() {
614 if a.len() != 3 {
615 return Err(format!("$cond 数组形态需要 3 个操作数,收到 {}", a.len()));
616 }
617 return Ok((&a[0], &a[1], &a[2]));
618 }
619 if let Some(o) = arg.as_object() {
620 let pick = |k: &str| {
621 o.get(k)
622 .ok_or_else(|| format!("$cond 对象形态缺少 \"{k}\""))
623 };
624 return Ok((pick("if")?, pick("then")?, pick("else")?));
625 }
626 Err("$cond 需要数组 [if, then, else] 或对象 {if, then, else}".to_string())
627}
628
629fn truthy(v: &Value) -> bool {
631 match v {
632 Value::Null => false,
633 Value::Bool(b) => *b,
634 Value::Number(n) => n.as_f64().map(|x| x != 0.0).unwrap_or(true),
635 _ => true,
636 }
637}
638
639fn eval_ref(s: &str, doc: &Value, vars: &Map<String, Value>) -> Result<Value, String> {
641 if let Some(rest) = s.strip_prefix("$$") {
642 let (name, path) = match rest.split_once('.') {
643 Some((n, p)) => (n, p),
644 None => (rest, ""),
645 };
646 let base = vars.get(name).cloned().unwrap_or(Value::Null);
647 Ok(reference_path(&base, path))
648 } else if let Some(rest) = s.strip_prefix('$') {
649 Ok(eval_field_path(doc, rest))
650 } else {
651 Ok(Value::String(s.to_string()))
652 }
653}
654
655fn eval_field_path(doc: &Value, path: &str) -> Value {
667 let mut cur: Vec<&Value> = vec![doc];
668 let mut fanout = false;
669 for seg in segments(path) {
670 let mut next: Vec<&Value> = Vec::new();
671 let mut array_hit = false;
672 for base in &cur {
673 match base {
674 Value::Object(o) => {
675 if let Some(v) = o.get(seg) {
676 next.push(v);
677 }
678 }
679 Value::Array(a) => {
680 array_hit = true;
681 for el in a {
682 if let Value::Object(o) = el {
683 if let Some(v) = o.get(seg) {
684 next.push(v);
685 }
686 }
687 }
688 }
689 _ => {}
690 }
691 }
692 if array_hit {
693 fanout = true;
694 }
695 cur = next;
696 if cur.is_empty() {
697 break;
698 }
699 }
700 if fanout {
701 Value::Array(cur.into_iter().cloned().collect())
702 } else {
703 cur.into_iter().next().cloned().unwrap_or(Value::Null)
704 }
705}
706
707fn reference_path(base: &Value, path: &str) -> Value {
708 if path.is_empty() {
709 base.clone()
710 } else {
711 get_path(base, path).cloned().unwrap_or(Value::Null)
712 }
713}
714
715pub fn apply_projection(doc: &Value, projection: &Value) -> Result<Value, String> {
723 let obj = projection
724 .as_object()
725 .ok_or_else(|| format!("投影必须是对象,收到 {}", type_name(projection)))?;
726 if obj.is_empty() {
727 return Ok(doc.clone());
728 }
729
730 let mut include_paths: Vec<&String> = Vec::new();
731 let mut exclude_paths: Vec<&String> = Vec::new();
732 let mut id: Option<bool> = None;
733 for (k, v) in obj {
734 let flag = projection_flag(v)?;
735 if k == "_id" {
736 id = Some(flag);
737 } else if flag {
738 include_paths.push(k);
739 } else {
740 exclude_paths.push(k);
741 }
742 }
743 if !include_paths.is_empty() && !exclude_paths.is_empty() {
744 return Err("投影不允许同时包含与排除字段(`_id` 除外)".to_string());
745 }
746
747 let include_mode = if !include_paths.is_empty() {
748 true
749 } else if !exclude_paths.is_empty() {
750 false
751 } else {
752 id == Some(true)
754 };
755
756 if include_mode {
757 let mut out = Map::new();
758 if id != Some(false) {
759 if let Some(v) = doc.get("_id") {
760 out.insert("_id".to_string(), v.clone());
761 }
762 }
763 for path in &include_paths {
764 if let Some(v) = project_included(doc, &segments(path)) {
765 merge_into(&mut out, v);
766 }
767 }
768 Ok(Value::Object(out))
769 } else {
770 let mut out = doc.clone();
771 for path in &exclude_paths {
772 remove_segments(&mut out, &segments(path));
773 }
774 if id == Some(false) {
775 if let Value::Object(m) = &mut out {
776 m.remove("_id");
777 }
778 }
779 Ok(out)
780 }
781}
782
783fn projection_flag(v: &Value) -> Result<bool, String> {
785 match v {
786 Value::Bool(b) => Ok(*b),
787 Value::Number(n) => match (n.as_i64(), n.as_f64()) {
788 (Some(0), _) | (_, Some(0.0)) => Ok(false),
789 (Some(1), _) | (_, Some(1.0)) => Ok(true),
790 _ => Err(format!("投影值必须是 0/1 或 false/true,收到 {n}")),
791 },
792 other => Err(format!(
793 "不支持的投影形态: {other}(本地求值器仅支持包含/排除,拒绝静默)"
794 )),
795 }
796}
797
798fn project_included(doc: &Value, segs: &[&str]) -> Option<Value> {
801 if segs.is_empty() {
802 return Some(doc.clone());
803 }
804 match doc {
805 Value::Object(o) => {
806 let child = o.get(segs[0])?;
807 let sub = project_included(child, &segs[1..])?;
808 let mut m = Map::new();
809 m.insert(segs[0].to_string(), sub);
810 Some(Value::Object(m))
811 }
812 Value::Array(a) => {
813 let mut arr = Vec::with_capacity(a.len());
814 for el in a {
815 if let Some(v) = project_included(el, segs) {
816 arr.push(v);
817 }
818 }
819 Some(Value::Array(arr))
820 }
821 _ => None,
822 }
823}
824
825pub fn project_include(doc: &Value, path: &str) -> Option<Value> {
829 project_included(doc, &segments(path))
830}
831
832pub fn merge_into(dst: &mut Map<String, Value>, src: Value) {
834 let Value::Object(src) = src else {
835 return;
836 };
837 for (k, v) in src {
838 let nested = matches!(dst.get(&k), Some(Value::Object(_))) && v.is_object();
839 if nested {
840 if let Some(Value::Object(d)) = dst.get_mut(&k) {
841 merge_into(d, v);
842 }
843 } else {
844 dst.insert(k, v);
845 }
846 }
847}
848
849pub fn remove_path(doc: &mut Value, path: &str) {
851 remove_segments(doc, &segments(path));
852}
853
854pub fn set_path(doc: &mut Value, path: &str, val: Value) {
856 set_segments(doc, &segments(path), val);
857}
858
859fn set_segments(cur: &mut Value, segs: &[&str], val: Value) {
860 if segs.is_empty() {
861 *cur = val;
862 return;
863 }
864 if !cur.is_object() {
865 *cur = Value::Object(Map::new());
866 }
867 let Value::Object(o) = cur else { return };
868 if segs.len() == 1 {
869 o.insert(segs[0].to_string(), val);
870 return;
871 }
872 let entry = o
873 .entry(segs[0].to_string())
874 .or_insert_with(|| Value::Object(Map::new()));
875 set_segments(entry, &segs[1..], val);
876}
877
878fn remove_segments(doc: &mut Value, segs: &[&str]) {
879 if segs.is_empty() {
880 return;
881 }
882 match doc {
883 Value::Object(o) => {
884 if segs.len() == 1 {
885 o.remove(segs[0]);
886 } else if let Some(v) = o.get_mut(segs[0]) {
887 remove_segments(v, &segs[1..]);
888 }
889 }
890 Value::Array(a) => {
891 for el in a {
892 remove_segments(el, segs);
893 }
894 }
895 _ => {}
896 }
897}
898
899fn type_name(v: &Value) -> &'static str {
900 match v {
901 Value::Null => "null",
902 Value::Bool(_) => "bool",
903 Value::Number(_) => "number",
904 Value::String(_) => "string",
905 Value::Array(_) => "array",
906 Value::Object(_) => "object",
907 }
908}
909
910#[cfg(test)]
911mod tests {
912 use super::*;
913 use serde_json::json;
914
915 #[test]
916 fn max_docs_guard_constant() {
917 assert_eq!(MAX_LOCAL_COLLECTION_DOCS, 100_000);
918 }
919
920 #[test]
921 fn get_path_three_states() {
922 let doc = json!({ "a": null, "b": { "c": 1 } });
923 assert_eq!(get_path(&doc, "a"), Some(&Value::Null));
925 assert_eq!(get_path(&doc, "missing"), None);
926 assert_eq!(get_path(&doc, "b.missing"), None);
927 assert_eq!(get_path(&doc, "b.c"), Some(&json!(1)));
928 let arr = json!({ "a": [ { "b": 1 } ] });
930 assert_eq!(get_path(&arr, "a.b"), None);
931 }
932
933 #[test]
934 fn candidates_three_states_and_array_expansion() {
935 let doc = json!({ "a": null, "arr": [ { "b": 1 }, { "b": 2 } ] });
936 assert!(resolve_path_candidates(&doc, "missing").is_empty());
938 assert_eq!(resolve_path_candidates(&doc, "a"), vec![&Value::Null]);
939 assert_eq!(
941 resolve_path_candidates(&doc, "arr.b"),
942 vec![&json!(1), &json!(2)]
943 );
944 let tags = json!({ "tags": ["x", "y"] });
946 assert_eq!(
947 resolve_path_candidates(&tags, "tags"),
948 vec![&json!(["x", "y"])]
949 );
950 }
951
952 #[test]
953 fn bson_type_order_across_types() {
954 let min = json!({ "$minKey": 1 });
955 let null = Value::Null;
956 let num = json!(5);
957 let s = json!("abc");
958 let obj = json!({ "x": 1 });
959 let arr = json!([1, 2]);
960 let boolean = json!(true);
961 let date = json!({ "$date": 0 });
962 let max = json!({ "$maxKey": 1 });
963 let seq = [&min, &null, &num, &s, &obj, &arr, &boolean, &date, &max];
964 for (i, a) in seq.iter().enumerate() {
965 for (j, b) in seq.iter().enumerate() {
966 assert_eq!(compare(a, b), i.cmp(&j), "rank {i} vs {j}");
967 }
968 }
969 }
970
971 #[test]
972 fn number_order_across_int_and_float() {
973 assert_eq!(compare(&json!(1), &json!(1.0)), Ordering::Equal);
974 assert!(values_equal(&json!(1), &json!(1.0)));
975 assert_eq!(compare(&json!(2), &json!(1.5)), Ordering::Greater);
976 assert_eq!(compare(&json!(-1), &json!(0)), Ordering::Less);
977 assert!(values_equal(&json!({ "$numberLong": "3" }), &json!(3)));
979 }
980
981 #[test]
982 fn compare_object_and_array() {
983 assert_eq!(
984 compare(&json!({ "a": 1 }), &json!({ "a": 2 })),
985 Ordering::Less
986 );
987 assert_eq!(
989 compare(&json!({ "a": 2 }), &json!({ "a": 2, "b": 1 })),
990 Ordering::Less
991 );
992 assert_eq!(compare(&json!([1, 2]), &json!([1, 2, 3])), Ordering::Less);
993 assert_eq!(compare(&json!([1, 3]), &json!([1, 2])), Ordering::Greater);
994 }
995
996 #[test]
997 fn array_eq_hit_helper() {
998 assert!(matches_value(&json!(["x", "y"]), &json!("x")));
1000 assert!(matches_value(&json!("x"), &json!("x")));
1001 assert!(!matches_value(&json!(["y"]), &json!("x")));
1002 }
1003
1004 #[test]
1005 fn eval_expr_minimal() {
1006 let doc = json!({ "x": 1, "y": 2 });
1007 let vars = Map::new();
1008 assert_eq!(
1009 eval_expr(&json!({ "$eq": ["$x", 1] }), &doc, &vars).unwrap(),
1010 json!(true)
1011 );
1012 assert_eq!(
1013 eval_expr(&json!({ "$eq": ["$x", "$y"] }), &doc, &vars).unwrap(),
1014 json!(false)
1015 );
1016 assert_eq!(
1017 eval_expr(
1018 &json!({ "$and": [ { "$eq": ["$x", 1] }, { "$eq": ["$y", 2] } ] }),
1019 &doc,
1020 &vars
1021 )
1022 .unwrap(),
1023 json!(true)
1024 );
1025 assert_eq!(
1027 eval_expr(&json!({ "$ifNull": ["$missing", "d"] }), &doc, &vars).unwrap(),
1028 json!("d")
1029 );
1030 let mut vars2 = Map::new();
1032 vars2.insert("v".to_string(), json!(42));
1033 assert_eq!(eval_expr(&json!("$$v"), &doc, &vars2).unwrap(), json!(42));
1034 assert_eq!(
1035 eval_expr(&json!({ "$eq": ["$x", "$$v"] }), &doc, &vars2).unwrap(),
1036 json!(false)
1037 );
1038 assert!(eval_expr(&json!({ "$mul": [1, 2] }), &doc, &vars).is_err());
1040 }
1041
1042 #[test]
1043 fn expr_size() {
1044 let vars = Map::new();
1045 let doc = json!({ "arr": [1, 2, 3], "empty": [], "n": 5 });
1046 assert_eq!(
1047 eval_expr(&json!({ "$size": "$arr" }), &doc, &vars).unwrap(),
1048 json!(3)
1049 );
1050 assert_eq!(
1051 eval_expr(&json!({ "$size": "$empty" }), &doc, &vars).unwrap(),
1052 json!(0)
1053 );
1054 assert!(eval_expr(&json!({ "$size": "$n" }), &doc, &vars).is_err());
1056 assert!(eval_expr(&json!({ "$size": "$missing" }), &doc, &vars).is_err());
1057 }
1058
1059 #[test]
1060 fn expr_sum_avg_min_max_array_form() {
1061 let vars = Map::new();
1062 let doc = json!({
1063 "scores": [3, 7, 5],
1064 "mixed": [1, "x", 4, null],
1065 "empty": [],
1066 "gone": null,
1067 "one": 9
1068 });
1069 assert_eq!(
1071 eval_expr(&json!({ "$sum": "$scores" }), &doc, &vars).unwrap(),
1072 json!(15)
1073 );
1074 assert_eq!(
1076 eval_expr(&json!({ "$sum": "$mixed" }), &doc, &vars).unwrap(),
1077 json!(5)
1078 );
1079 assert_eq!(
1080 eval_expr(&json!({ "$sum": "$empty" }), &doc, &vars).unwrap(),
1081 json!(0)
1082 );
1083 assert_eq!(
1084 eval_expr(&json!({ "$sum": "$gone" }), &doc, &vars).unwrap(),
1085 json!(0)
1086 );
1087 assert_eq!(
1088 eval_expr(&json!({ "$sum": "$missing" }), &doc, &vars).unwrap(),
1089 json!(0)
1090 );
1091 assert_eq!(
1093 eval_expr(&json!({ "$avg": "$scores" }), &doc, &vars).unwrap(),
1094 json!(5.0)
1095 );
1096 assert_eq!(
1097 eval_expr(&json!({ "$avg": "$empty" }), &doc, &vars).unwrap(),
1098 Value::Null
1099 );
1100 assert_eq!(
1101 eval_expr(&json!({ "$avg": "$missing" }), &doc, &vars).unwrap(),
1102 Value::Null
1103 );
1104 assert_eq!(
1106 eval_expr(&json!({ "$min": "$scores" }), &doc, &vars).unwrap(),
1107 json!(3)
1108 );
1109 assert_eq!(
1110 eval_expr(&json!({ "$max": "$scores" }), &doc, &vars).unwrap(),
1111 json!(7)
1112 );
1113 assert_eq!(
1114 eval_expr(&json!({ "$min": "$mixed" }), &doc, &vars).unwrap(),
1115 json!(1)
1116 );
1117 assert_eq!(
1118 eval_expr(&json!({ "$min": "$empty" }), &doc, &vars).unwrap(),
1119 Value::Null
1120 );
1121 assert_eq!(
1123 eval_expr(&json!({ "$sum": "$one" }), &doc, &vars).unwrap(),
1124 json!(9)
1125 );
1126 assert_eq!(
1127 eval_expr(&json!({ "$avg": "$one" }), &doc, &vars).unwrap(),
1128 json!(9.0)
1129 );
1130 assert_eq!(
1131 eval_expr(&json!({ "$min": "$one" }), &doc, &vars).unwrap(),
1132 json!(9)
1133 );
1134 }
1135
1136 #[test]
1137 fn projection_include_nested() {
1138 let doc = json!({ "_id": 7, "a": { "b": 1, "c": 2 }, "d": 3 });
1139 assert_eq!(
1141 apply_projection(&doc, &json!({ "a.b": 1 })).unwrap(),
1142 json!({ "_id": 7, "a": { "b": 1 } })
1143 );
1144 assert_eq!(
1146 apply_projection(&doc, &json!({ "d": 1 })).unwrap(),
1147 json!({ "_id": 7, "d": 3 })
1148 );
1149 assert_eq!(
1151 apply_projection(&doc, &json!({ "d": 1, "_id": 0 })).unwrap(),
1152 json!({ "d": 3 })
1153 );
1154 }
1155
1156 #[test]
1157 fn projection_exclude_and_errors() {
1158 let doc = json!({ "_id": 7, "a": { "b": 1, "c": 2 }, "d": 3 });
1159 assert_eq!(
1161 apply_projection(&doc, &json!({ "a.b": 0 })).unwrap(),
1162 json!({ "_id": 7, "a": { "c": 2 }, "d": 3 })
1163 );
1164 assert_eq!(
1166 apply_projection(&doc, &json!({ "_id": 0 })).unwrap(),
1167 json!({ "a": { "b": 1, "c": 2 }, "d": 3 })
1168 );
1169 assert!(apply_projection(&doc, &json!({ "a": 1, "d": 0 })).is_err());
1171 assert!(apply_projection(&doc, &json!({ "a": 2 })).is_err());
1173 }
1174
1175 #[test]
1178 fn ne_filter_set_union_eval() {
1179 let vars = Map::new();
1180 let empty = json!({});
1181 assert_eq!(
1183 eval_expr(&json!({ "$ne": [1, 2] }), &empty, &vars).unwrap(),
1184 json!(true)
1185 );
1186 assert_eq!(
1187 eval_expr(&json!({ "$ne": [null, null] }), &empty, &vars).unwrap(),
1188 json!(false)
1189 );
1190
1191 let doc = json!({ "arr": ["a", null, "b", null] });
1193 assert_eq!(
1194 eval_expr(
1195 &json!({
1196 "$filter": {
1197 "input": "$arr",
1198 "as": "v",
1199 "cond": { "$ne": ["$$v", null] }
1200 }
1201 }),
1202 &doc,
1203 &vars
1204 )
1205 .unwrap(),
1206 json!(["a", "b"])
1207 );
1208
1209 assert_eq!(
1211 eval_expr(
1212 &json!({ "$setUnion": [["a", "b"], ["b", "c"], []] }),
1213 &empty,
1214 &vars
1215 )
1216 .unwrap(),
1217 json!(["a", "b", "c"])
1218 );
1219
1220 let shape = |path: &str| {
1222 json!({
1223 "$size": {
1224 "$setUnion": [
1225 {
1226 "$filter": {
1227 "input": { "$ifNull": [path, []] },
1228 "as": "v",
1229 "cond": { "$ne": ["$$v", null] }
1230 }
1231 },
1232 []
1233 ]
1234 }
1235 })
1236 };
1237 let doc = json!({ "tags": ["x", "y", "x", null] });
1238 assert_eq!(eval_expr(&shape("$tags"), &doc, &vars).unwrap(), json!(2));
1239 let no_elems = json!({ "tags": [] });
1240 assert_eq!(
1241 eval_expr(&shape("$tags"), &no_elems, &vars).unwrap(),
1242 json!(0)
1243 );
1244 let missing = json!({});
1245 assert_eq!(
1246 eval_expr(&shape("$tags"), &missing, &vars).unwrap(),
1247 json!(0)
1248 );
1249 }
1250
1251 #[test]
1255 fn field_path_array_fanout_eval() {
1256 let vars = Map::new();
1257 let doc = json!({ "bidders": [
1259 { "bidderId": "u1", "amount": 100 },
1260 { "bidderId": "u2" },
1261 { "bidderId": "u1", "amount": 300 }
1262 ] });
1263 assert_eq!(
1264 eval_expr(&json!({ "$max": "$bidders.amount" }), &doc, &vars).unwrap(),
1265 json!(300)
1266 );
1267 assert_eq!(
1268 eval_expr(&json!({ "$sum": "$bidders.amount" }), &doc, &vars).unwrap(),
1269 json!(400)
1270 );
1271 assert_eq!(
1273 eval_expr(
1274 &json!({ "$filter": {
1275 "input": { "$ifNull": ["$bidders.bidderId", []] },
1276 "as": "v",
1277 "cond": { "$ne": ["$$v", null] }
1278 } }),
1279 &doc,
1280 &vars
1281 )
1282 .unwrap(),
1283 json!(["u1", "u2", "u1"])
1284 );
1285 let empty = json!({ "bidders": [] });
1287 assert_eq!(
1288 eval_expr(&json!("$bidders.amount"), &empty, &vars).unwrap(),
1289 json!([])
1290 );
1291 let missing = json!({});
1293 assert_eq!(
1294 eval_expr(&json!("$bidders.amount"), &missing, &vars).unwrap(),
1295 Value::Null
1296 );
1297 let plain = json!({ "a": { "b": [1, 2] } });
1299 assert_eq!(
1300 eval_expr(&json!("$a.b"), &plain, &vars).unwrap(),
1301 json!([1, 2])
1302 );
1303 }
1304}