Skip to main content

jpx_core/extensions/
array.rs

1//! Array manipulation functions.
2
3use std::collections::HashSet;
4
5use serde_json::{Number, Value};
6
7use crate::functions::{Function, custom_error};
8use crate::interpreter::SearchResult;
9use crate::registry::register_if_enabled;
10use crate::{Context, Runtime, arg, defn};
11
12/// Register only the array functions that are in the enabled set.
13pub fn register_filtered(runtime: &mut Runtime, enabled: &HashSet<&str>) {
14    register_if_enabled(runtime, "unique", enabled, Box::new(UniqueFn::new()));
15    register_if_enabled(runtime, "zip", enabled, Box::new(ZipFn::new()));
16    register_if_enabled(runtime, "chunk", enabled, Box::new(ChunkFn::new()));
17    register_if_enabled(runtime, "take", enabled, Box::new(TakeFn::new()));
18    register_if_enabled(runtime, "drop", enabled, Box::new(DropFn::new()));
19    register_if_enabled(
20        runtime,
21        "flatten_deep",
22        enabled,
23        Box::new(FlattenDeepFn::new()),
24    );
25    register_if_enabled(runtime, "flatten", enabled, Box::new(FlattenFn::new()));
26    register_if_enabled(runtime, "compact", enabled, Box::new(CompactFn::new()));
27    register_if_enabled(runtime, "range", enabled, Box::new(RangeFn::new()));
28    register_if_enabled(runtime, "index_at", enabled, Box::new(IndexAtFn::new()));
29    register_if_enabled(runtime, "includes", enabled, Box::new(IncludesFn::new()));
30    register_if_enabled(runtime, "find_index", enabled, Box::new(FindIndexFn::new()));
31    register_if_enabled(runtime, "first", enabled, Box::new(FirstFn::new()));
32    register_if_enabled(runtime, "last", enabled, Box::new(LastFn::new()));
33    register_if_enabled(runtime, "group_by", enabled, Box::new(GroupByFn::new()));
34    register_if_enabled(runtime, "index_by", enabled, Box::new(IndexByFn::new()));
35    register_if_enabled(runtime, "nth", enabled, Box::new(NthFn::new()));
36    register_if_enabled(
37        runtime,
38        "interleave",
39        enabled,
40        Box::new(InterleaveFn::new()),
41    );
42    register_if_enabled(runtime, "rotate", enabled, Box::new(RotateFn::new()));
43    register_if_enabled(runtime, "partition", enabled, Box::new(PartitionFn::new()));
44    register_if_enabled(
45        runtime,
46        "difference",
47        enabled,
48        Box::new(DifferenceFn::new()),
49    );
50    register_if_enabled(
51        runtime,
52        "intersection",
53        enabled,
54        Box::new(IntersectionFn::new()),
55    );
56    register_if_enabled(runtime, "union", enabled, Box::new(UnionFn::new()));
57    register_if_enabled(
58        runtime,
59        "frequencies",
60        enabled,
61        Box::new(FrequenciesFn::new()),
62    );
63    register_if_enabled(runtime, "mode", enabled, Box::new(ModeFn::new()));
64    register_if_enabled(runtime, "cartesian", enabled, Box::new(CartesianFn::new()));
65    register_if_enabled(runtime, "initial", enabled, Box::new(InitialFn::new()));
66    // Alias for initial (Clojure-style name)
67    register_if_enabled(runtime, "butlast", enabled, Box::new(InitialFn::new()));
68    // Clojure-inspired functions
69    register_if_enabled(runtime, "interpose", enabled, Box::new(InterposeFn::new()));
70    register_if_enabled(runtime, "zipmap", enabled, Box::new(ZipmapFn::new()));
71    register_if_enabled(
72        runtime,
73        "partition_by",
74        enabled,
75        Box::new(PartitionByFn::new()),
76    );
77    register_if_enabled(runtime, "dedupe", enabled, Box::new(DedupeFn::new()));
78    register_if_enabled(runtime, "tail", enabled, Box::new(TailFn::new()));
79    register_if_enabled(runtime, "without", enabled, Box::new(WithoutFn::new()));
80    register_if_enabled(runtime, "xor", enabled, Box::new(XorFn::new()));
81    register_if_enabled(runtime, "fill", enabled, Box::new(FillFn::new()));
82    register_if_enabled(runtime, "pull_at", enabled, Box::new(PullAtFn::new()));
83    register_if_enabled(runtime, "window", enabled, Box::new(WindowFn::new()));
84    register_if_enabled(
85        runtime,
86        "combinations",
87        enabled,
88        Box::new(CombinationsFn::new()),
89    );
90    register_if_enabled(runtime, "transpose", enabled, Box::new(TransposeFn::new()));
91    register_if_enabled(runtime, "pairwise", enabled, Box::new(PairwiseFn::new()));
92    // Alias for window (sliding_window is a common name)
93    register_if_enabled(
94        runtime,
95        "sliding_window",
96        enabled,
97        Box::new(WindowFn::new()),
98    );
99    // jq-parity functions
100    register_if_enabled(
101        runtime,
102        "indices_array",
103        enabled,
104        Box::new(IndicesArrayFn::new()),
105    );
106    register_if_enabled(
107        runtime,
108        "inside_array",
109        enabled,
110        Box::new(InsideArrayFn::new()),
111    );
112    register_if_enabled(runtime, "bsearch", enabled, Box::new(BsearchFn::new()));
113    // Clojure-inspired functions (Phase 3)
114    register_if_enabled(
115        runtime,
116        "repeat_array",
117        enabled,
118        Box::new(RepeatArrayFn::new()),
119    );
120    register_if_enabled(runtime, "cycle", enabled, Box::new(CycleFn::new()));
121    register_if_enabled(runtime, "lag", enabled, Box::new(LagFn::new()));
122    register_if_enabled(runtime, "lead", enabled, Box::new(LeadFn::new()));
123}
124
125// =============================================================================
126// unique(array) -> array
127// =============================================================================
128
129defn!(UniqueFn, vec![arg!(array)], None);
130
131impl Function for UniqueFn {
132    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
133        self.signature.validate(args, ctx)?;
134
135        let arr = args[0]
136            .as_array()
137            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
138
139        let mut seen = HashSet::new();
140        let mut result = Vec::new();
141
142        for item in arr {
143            let key = serde_json::to_string(item).unwrap_or_default();
144            if seen.insert(key) {
145                result.push(item.clone());
146            }
147        }
148
149        Ok(Value::Array(result))
150    }
151}
152
153// =============================================================================
154// zip(array1, array2) -> array of pairs
155// =============================================================================
156
157defn!(ZipFn, vec![arg!(array), arg!(array)], None);
158
159impl Function for ZipFn {
160    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
161        self.signature.validate(args, ctx)?;
162
163        let arr1 = args[0]
164            .as_array()
165            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
166
167        let arr2 = args[1]
168            .as_array()
169            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
170
171        let result: Vec<Value> = arr1
172            .iter()
173            .zip(arr2.iter())
174            .map(|(a, b)| Value::Array(vec![a.clone(), b.clone()]))
175            .collect();
176
177        Ok(Value::Array(result))
178    }
179}
180
181// =============================================================================
182// chunk(array, size) -> array of arrays
183// =============================================================================
184
185defn!(ChunkFn, vec![arg!(array), arg!(number)], None);
186
187impl Function for ChunkFn {
188    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
189        self.signature.validate(args, ctx)?;
190
191        let arr = args[0]
192            .as_array()
193            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
194
195        let size = args[1]
196            .as_f64()
197            .map(|n| n as usize)
198            .ok_or_else(|| custom_error(ctx, "Expected positive number for size"))?;
199
200        if size == 0 {
201            return Ok(Value::Array(vec![]));
202        }
203
204        let chunks: Vec<Value> = arr
205            .chunks(size)
206            .map(|chunk| Value::Array(chunk.to_vec()))
207            .collect();
208
209        Ok(Value::Array(chunks))
210    }
211}
212
213// =============================================================================
214// take(array, n) -> array (first n elements)
215// =============================================================================
216
217defn!(TakeFn, vec![arg!(array), arg!(number)], None);
218
219impl Function for TakeFn {
220    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
221        self.signature.validate(args, ctx)?;
222
223        let arr = args[0]
224            .as_array()
225            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
226
227        let n = args[1]
228            .as_f64()
229            .map(|n| n as usize)
230            .ok_or_else(|| custom_error(ctx, "Expected positive number"))?;
231
232        let result: Vec<Value> = arr.iter().take(n).cloned().collect();
233
234        Ok(Value::Array(result))
235    }
236}
237
238// =============================================================================
239// drop(array, n) -> array (skip first n elements)
240// =============================================================================
241
242defn!(DropFn, vec![arg!(array), arg!(number)], None);
243
244impl Function for DropFn {
245    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
246        self.signature.validate(args, ctx)?;
247
248        let arr = args[0]
249            .as_array()
250            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
251
252        let n = args[1]
253            .as_f64()
254            .map(|n| n as usize)
255            .ok_or_else(|| custom_error(ctx, "Expected positive number"))?;
256
257        let result: Vec<Value> = arr.iter().skip(n).cloned().collect();
258
259        Ok(Value::Array(result))
260    }
261}
262
263// =============================================================================
264// flatten_deep(array) -> array (recursively flatten)
265// =============================================================================
266
267defn!(FlattenDeepFn, vec![arg!(array)], None);
268
269fn flatten_recursive(arr: &[Value]) -> Vec<Value> {
270    let mut result = Vec::new();
271    for item in arr {
272        if let Some(inner) = item.as_array() {
273            result.extend(flatten_recursive(inner));
274        } else {
275            result.push(item.clone());
276        }
277    }
278    result
279}
280
281impl Function for FlattenDeepFn {
282    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
283        self.signature.validate(args, ctx)?;
284
285        let arr = args[0]
286            .as_array()
287            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
288
289        Ok(Value::Array(flatten_recursive(arr)))
290    }
291}
292
293// =============================================================================
294// flatten(array) -> array (single-level flatten)
295// =============================================================================
296
297defn!(FlattenFn, vec![arg!(array)], None);
298
299impl Function for FlattenFn {
300    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
301        self.signature.validate(args, ctx)?;
302
303        let arr = args[0]
304            .as_array()
305            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
306
307        let mut result = Vec::new();
308        for item in arr {
309            if let Some(inner) = item.as_array() {
310                result.extend(inner.iter().cloned());
311            } else {
312                result.push(item.clone());
313            }
314        }
315
316        Ok(Value::Array(result))
317    }
318}
319
320// =============================================================================
321// compact(array) -> array (remove null/false values)
322// =============================================================================
323
324defn!(CompactFn, vec![arg!(array)], None);
325
326impl Function for CompactFn {
327    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
328        self.signature.validate(args, ctx)?;
329
330        let arr = args[0]
331            .as_array()
332            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
333
334        let result: Vec<Value> = arr
335            .iter()
336            .filter(|v| !v.is_null() && !matches!(v, Value::Bool(false)))
337            .cloned()
338            .collect();
339
340        Ok(Value::Array(result))
341    }
342}
343
344// =============================================================================
345// range(start, end, step?) -> array
346// =============================================================================
347
348defn!(
349    RangeFn,
350    vec![arg!(number), arg!(number)],
351    Some(arg!(number))
352);
353
354impl Function for RangeFn {
355    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
356        self.signature.validate(args, ctx)?;
357
358        let start = args[0]
359            .as_f64()
360            .map(|n| n as i64)
361            .ok_or_else(|| custom_error(ctx, "Expected start number"))?;
362
363        let end = args[1]
364            .as_f64()
365            .map(|n| n as i64)
366            .ok_or_else(|| custom_error(ctx, "Expected end number"))?;
367
368        let step = if args.len() > 2 {
369            args[2]
370                .as_f64()
371                .map(|n| n as i64)
372                .ok_or_else(|| custom_error(ctx, "Expected step number"))?
373        } else {
374            1
375        };
376
377        if step == 0 {
378            return Err(custom_error(ctx, "Step cannot be zero"));
379        }
380
381        let mut result = Vec::new();
382        let mut current = start;
383
384        const MAX_RANGE: usize = 10000;
385
386        if step > 0 {
387            while current < end && result.len() < MAX_RANGE {
388                result.push(Value::Number(Number::from(current)));
389                current += step;
390            }
391        } else {
392            while current > end && result.len() < MAX_RANGE {
393                result.push(Value::Number(Number::from(current)));
394                current += step;
395            }
396        }
397
398        Ok(Value::Array(result))
399    }
400}
401
402// =============================================================================
403// index_at(array, index) -> element (supports negative index)
404// =============================================================================
405
406defn!(IndexAtFn, vec![arg!(array), arg!(number)], None);
407
408impl Function for IndexAtFn {
409    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
410        self.signature.validate(args, ctx)?;
411
412        let arr = args[0]
413            .as_array()
414            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
415
416        let index = args[1]
417            .as_f64()
418            .map(|n| n as i64)
419            .ok_or_else(|| custom_error(ctx, "Expected number for index"))?;
420
421        let len = arr.len() as i64;
422        let actual_index = if index < 0 {
423            (len + index) as usize
424        } else {
425            index as usize
426        };
427
428        if actual_index < arr.len() {
429            Ok(arr[actual_index].clone())
430        } else {
431            Ok(Value::Null)
432        }
433    }
434}
435
436// =============================================================================
437// includes(array, value) -> boolean
438// =============================================================================
439
440defn!(IncludesFn, vec![arg!(array), arg!(any)], None);
441
442impl Function for IncludesFn {
443    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
444        self.signature.validate(args, ctx)?;
445
446        let arr = args[0]
447            .as_array()
448            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
449
450        let search_key = serde_json::to_string(&args[1]).unwrap_or_default();
451
452        let found = arr.iter().any(|item| {
453            let item_key = serde_json::to_string(item).unwrap_or_default();
454            item_key == search_key
455        });
456
457        Ok(Value::Bool(found))
458    }
459}
460
461// =============================================================================
462// find_index(array, value) -> number (-1 if not found)
463// =============================================================================
464
465defn!(FindIndexFn, vec![arg!(array), arg!(any)], None);
466
467impl Function for FindIndexFn {
468    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
469        self.signature.validate(args, ctx)?;
470
471        let arr = args[0]
472            .as_array()
473            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
474
475        let search_key = serde_json::to_string(&args[1]).unwrap_or_default();
476
477        let index = arr
478            .iter()
479            .position(|item| {
480                let item_key = serde_json::to_string(item).unwrap_or_default();
481                item_key == search_key
482            })
483            .map(|i| i as i64)
484            .unwrap_or(-1);
485
486        Ok(Value::Number(Number::from(index)))
487    }
488}
489
490// =============================================================================
491// first(array) -> any (first element or null)
492// =============================================================================
493
494defn!(FirstFn, vec![arg!(array)], None);
495
496impl Function for FirstFn {
497    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
498        self.signature.validate(args, ctx)?;
499
500        let arr = args[0]
501            .as_array()
502            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
503
504        Ok(arr.first().cloned().unwrap_or(Value::Null))
505    }
506}
507
508// =============================================================================
509// last(array) -> any (last element or null)
510// =============================================================================
511
512defn!(LastFn, vec![arg!(array)], None);
513
514impl Function for LastFn {
515    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
516        self.signature.validate(args, ctx)?;
517
518        let arr = args[0]
519            .as_array()
520            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
521
522        Ok(arr.last().cloned().unwrap_or(Value::Null))
523    }
524}
525
526// =============================================================================
527// group_by(array, field_name) -> object
528// =============================================================================
529
530defn!(GroupByFn, vec![arg!(array), arg!(string)], None);
531
532impl Function for GroupByFn {
533    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
534        self.signature.validate(args, ctx)?;
535
536        let arr = args[0]
537            .as_array()
538            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
539
540        let field_name = args[1]
541            .as_str()
542            .ok_or_else(|| custom_error(ctx, "Expected field name string"))?;
543
544        let mut groups: std::collections::BTreeMap<String, Vec<Value>> =
545            std::collections::BTreeMap::new();
546
547        for item in arr {
548            let key = if let Some(obj) = item.as_object() {
549                if let Some(field_value) = obj.get(field_name) {
550                    match field_value {
551                        Value::String(s) => s.clone(),
552                        Value::Number(n) => n.to_string(),
553                        Value::Bool(b) => b.to_string(),
554                        Value::Null => "null".to_string(),
555                        _ => continue,
556                    }
557                } else {
558                    "null".to_string()
559                }
560            } else {
561                continue;
562            };
563            groups.entry(key).or_default().push(item.clone());
564        }
565
566        let mut result = serde_json::Map::new();
567        for (k, v) in groups {
568            result.insert(k, Value::Array(v));
569        }
570
571        Ok(Value::Object(result))
572    }
573}
574
575// =============================================================================
576// index_by(array, field_name) -> object (last value wins for duplicates)
577// =============================================================================
578
579defn!(IndexByFn, vec![arg!(array), arg!(string)], None);
580
581impl Function for IndexByFn {
582    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
583        self.signature.validate(args, ctx)?;
584
585        let arr = args[0]
586            .as_array()
587            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
588
589        let field_name = args[1]
590            .as_str()
591            .ok_or_else(|| custom_error(ctx, "Expected field name string"))?;
592
593        let mut result = serde_json::Map::new();
594
595        for item in arr {
596            let key = if let Some(obj) = item.as_object() {
597                if let Some(field_value) = obj.get(field_name) {
598                    match field_value {
599                        Value::String(s) => s.clone(),
600                        Value::Number(n) => n.to_string(),
601                        Value::Bool(b) => b.to_string(),
602                        Value::Null => "null".to_string(),
603                        _ => continue,
604                    }
605                } else {
606                    // Skip items without the key field
607                    continue;
608                }
609            } else {
610                continue;
611            };
612            // Last value wins for duplicate keys
613            result.insert(key, item.clone());
614        }
615
616        Ok(Value::Object(result))
617    }
618}
619
620// =============================================================================
621// nth(array, n) -> array (every nth element)
622// =============================================================================
623
624defn!(NthFn, vec![arg!(array), arg!(number)], None);
625
626impl Function for NthFn {
627    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
628        self.signature.validate(args, ctx)?;
629
630        let arr = args[0]
631            .as_array()
632            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
633
634        let n = args[1]
635            .as_f64()
636            .ok_or_else(|| custom_error(ctx, "Expected number argument"))? as usize;
637
638        if n == 0 {
639            return Ok(Value::Null);
640        }
641
642        let result: Vec<Value> = arr.iter().step_by(n).cloned().collect();
643        Ok(Value::Array(result))
644    }
645}
646
647// =============================================================================
648// interleave(array1, array2) -> array (alternate elements)
649// =============================================================================
650
651defn!(InterleaveFn, vec![arg!(array), arg!(array)], None);
652
653impl Function for InterleaveFn {
654    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
655        self.signature.validate(args, ctx)?;
656
657        let arr1 = args[0]
658            .as_array()
659            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
660
661        let arr2 = args[1]
662            .as_array()
663            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
664
665        let mut result = Vec::with_capacity(arr1.len() + arr2.len());
666        let mut iter1 = arr1.iter();
667        let mut iter2 = arr2.iter();
668
669        loop {
670            match (iter1.next(), iter2.next()) {
671                (Some(a), Some(b)) => {
672                    result.push(a.clone());
673                    result.push(b.clone());
674                }
675                (Some(a), None) => {
676                    result.push(a.clone());
677                    result.extend(iter1.cloned());
678                    break;
679                }
680                (None, Some(b)) => {
681                    result.push(b.clone());
682                    result.extend(iter2.cloned());
683                    break;
684                }
685                (None, None) => break,
686            }
687        }
688
689        Ok(Value::Array(result))
690    }
691}
692
693// =============================================================================
694// rotate(array, n) -> array (rotate elements by n positions)
695// =============================================================================
696
697defn!(RotateFn, vec![arg!(array), arg!(number)], None);
698
699impl Function for RotateFn {
700    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
701        self.signature.validate(args, ctx)?;
702
703        let arr = args[0]
704            .as_array()
705            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
706
707        if arr.is_empty() {
708            return Ok(Value::Array(vec![]));
709        }
710
711        let n = args[1]
712            .as_f64()
713            .ok_or_else(|| custom_error(ctx, "Expected number argument"))? as i64;
714
715        let len = arr.len() as i64;
716        let rotation = ((n % len) + len) % len;
717        let rotation = rotation as usize;
718
719        let mut result = Vec::with_capacity(arr.len());
720        result.extend(arr[rotation..].iter().cloned());
721        result.extend(arr[..rotation].iter().cloned());
722
723        Ok(Value::Array(result))
724    }
725}
726
727// =============================================================================
728// partition(array, n) -> array (split into n equal parts)
729// =============================================================================
730
731defn!(PartitionFn, vec![arg!(array), arg!(number)], None);
732
733impl Function for PartitionFn {
734    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
735        self.signature.validate(args, ctx)?;
736
737        let arr = args[0]
738            .as_array()
739            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
740
741        let n = args[1]
742            .as_f64()
743            .ok_or_else(|| custom_error(ctx, "Expected number argument"))? as usize;
744
745        if n == 0 {
746            return Ok(Value::Null);
747        }
748
749        let len = arr.len();
750        let base_size = len / n;
751        let remainder = len % n;
752
753        let mut result = Vec::with_capacity(n);
754        let mut start = 0;
755
756        for i in 0..n {
757            let size = base_size + if i < remainder { 1 } else { 0 };
758            if size > 0 {
759                result.push(Value::Array(arr[start..start + size].to_vec()));
760            } else {
761                result.push(Value::Array(vec![]));
762            }
763            start += size;
764        }
765
766        Ok(Value::Array(result))
767    }
768}
769
770// =============================================================================
771// difference(arr1, arr2) -> array (set difference)
772// =============================================================================
773
774defn!(DifferenceFn, vec![arg!(array), arg!(array)], None);
775
776impl Function for DifferenceFn {
777    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
778        self.signature.validate(args, ctx)?;
779
780        let arr1 = args[0]
781            .as_array()
782            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
783
784        let arr2 = args[1]
785            .as_array()
786            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
787
788        let set2: HashSet<String> = arr2
789            .iter()
790            .map(|v| serde_json::to_string(v).unwrap_or_default())
791            .collect();
792
793        let result: Vec<Value> = arr1
794            .iter()
795            .filter(|v| {
796                let key = serde_json::to_string(*v).unwrap_or_default();
797                !set2.contains(&key)
798            })
799            .cloned()
800            .collect();
801
802        Ok(Value::Array(result))
803    }
804}
805
806// =============================================================================
807// intersection(arr1, arr2) -> array (set intersection)
808// =============================================================================
809
810defn!(IntersectionFn, vec![arg!(array), arg!(array)], None);
811
812impl Function for IntersectionFn {
813    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
814        self.signature.validate(args, ctx)?;
815
816        let arr1 = args[0]
817            .as_array()
818            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
819
820        let arr2 = args[1]
821            .as_array()
822            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
823
824        let set2: HashSet<String> = arr2
825            .iter()
826            .map(|v| serde_json::to_string(v).unwrap_or_default())
827            .collect();
828
829        let mut seen: HashSet<String> = HashSet::new();
830        let result: Vec<Value> = arr1
831            .iter()
832            .filter(|v| {
833                let key = serde_json::to_string(*v).unwrap_or_default();
834                set2.contains(&key) && seen.insert(key)
835            })
836            .cloned()
837            .collect();
838
839        Ok(Value::Array(result))
840    }
841}
842
843// =============================================================================
844// union(arr1, arr2) -> array (set union)
845// =============================================================================
846
847defn!(UnionFn, vec![arg!(array), arg!(array)], None);
848
849impl Function for UnionFn {
850    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
851        self.signature.validate(args, ctx)?;
852
853        let arr1 = args[0]
854            .as_array()
855            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
856
857        let arr2 = args[1]
858            .as_array()
859            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
860
861        let mut seen: HashSet<String> = HashSet::new();
862        let mut result: Vec<Value> = Vec::new();
863
864        for item in arr1.iter().chain(arr2.iter()) {
865            let key = serde_json::to_string(item).unwrap_or_default();
866            if seen.insert(key) {
867                result.push(item.clone());
868            }
869        }
870
871        Ok(Value::Array(result))
872    }
873}
874
875// =============================================================================
876// frequencies(array) -> object (count occurrences)
877// =============================================================================
878
879defn!(FrequenciesFn, vec![arg!(array)], None);
880
881impl Function for FrequenciesFn {
882    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
883        self.signature.validate(args, ctx)?;
884
885        let arr = args[0]
886            .as_array()
887            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
888
889        let mut counts: std::collections::HashMap<String, i64> = std::collections::HashMap::new();
890
891        for item in arr {
892            let key = match item {
893                Value::String(s) => s.clone(),
894                Value::Number(n) => n.to_string(),
895                Value::Bool(b) => b.to_string(),
896                Value::Null => "null".to_string(),
897                _ => serde_json::to_string(item).unwrap_or_else(|_| "null".to_string()),
898            };
899            *counts.entry(key).or_insert(0) += 1;
900        }
901
902        let mut result = serde_json::Map::new();
903        // Use BTreeMap for sorted output
904        let sorted: std::collections::BTreeMap<String, i64> = counts.into_iter().collect();
905        for (k, v) in sorted {
906            result.insert(k, Value::Number(Number::from(v)));
907        }
908
909        Ok(Value::Object(result))
910    }
911}
912
913// =============================================================================
914// mode(array) -> any (most frequent value)
915// =============================================================================
916
917defn!(ModeFn, vec![arg!(array)], None);
918
919impl Function for ModeFn {
920    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
921        self.signature.validate(args, ctx)?;
922
923        let arr = args[0]
924            .as_array()
925            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
926
927        if arr.is_empty() {
928            return Ok(Value::Null);
929        }
930
931        let mut counts: std::collections::HashMap<String, (i64, Value)> =
932            std::collections::HashMap::new();
933
934        for item in arr {
935            let key = serde_json::to_string(item).unwrap_or_default();
936            counts
937                .entry(key)
938                .and_modify(|(count, _)| *count += 1)
939                .or_insert((1, item.clone()));
940        }
941
942        let (_, (_, mode_value)) = counts
943            .into_iter()
944            .max_by_key(|(_, (count, _))| *count)
945            .unwrap();
946
947        Ok(mode_value)
948    }
949}
950
951// =============================================================================
952// cartesian(arr1, arr2) -> array (cartesian product of 2 arrays)
953// cartesian(array_of_arrays) -> array (cartesian product of N arrays, jq parity)
954// =============================================================================
955
956defn!(CartesianFn, vec![arg!(array)], Some(arg!(array)));
957
958impl Function for CartesianFn {
959    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
960        self.signature.validate(args, ctx)?;
961
962        let first = args[0]
963            .as_array()
964            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
965
966        // Two modes:
967        // 1. cartesian(arr1, arr2) - two separate arrays (original behavior)
968        // 2. cartesian(array_of_arrays) - single array containing arrays (jq-style)
969
970        if args.len() == 2 {
971            // Original two-argument mode
972            let arr2 = args[1]
973                .as_array()
974                .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
975
976            let mut result = Vec::with_capacity(first.len() * arr2.len());
977            for a in first {
978                for b in arr2 {
979                    result.push(Value::Array(vec![a.clone(), b.clone()]));
980                }
981            }
982            Ok(Value::Array(result))
983        } else {
984            // Single argument mode - check if it's an array of arrays
985            // If all elements are arrays, do N-way cartesian product
986            let arrays: Vec<&Vec<Value>> =
987                first.iter().filter_map(|item| item.as_array()).collect();
988
989            if arrays.len() != first.len() || arrays.is_empty() {
990                // Not all elements are arrays, or empty - return empty
991                return Ok(Value::Array(vec![]));
992            }
993
994            // N-way cartesian product
995            let result = cartesian_product_n(&arrays);
996            Ok(Value::Array(result))
997        }
998    }
999}
1000
1001/// Compute N-way cartesian product of arrays.
1002fn cartesian_product_n(arrays: &[&Vec<Value>]) -> Vec<Value> {
1003    if arrays.is_empty() {
1004        return vec![];
1005    }
1006
1007    if arrays.len() == 1 {
1008        // Single array - each element becomes a 1-element tuple
1009        return arrays[0]
1010            .iter()
1011            .map(|item| Value::Array(vec![item.clone()]))
1012            .collect();
1013    }
1014
1015    // Calculate total size for pre-allocation
1016    let total_size: usize = arrays.iter().map(|a| a.len()).product();
1017    if total_size == 0 {
1018        return vec![];
1019    }
1020
1021    let mut result = Vec::with_capacity(total_size);
1022
1023    // Iterative cartesian product using indices
1024    let mut indices = vec![0usize; arrays.len()];
1025
1026    loop {
1027        // Build current combination
1028        let combo: Vec<Value> = indices
1029            .iter()
1030            .enumerate()
1031            .map(|(arr_idx, &elem_idx)| arrays[arr_idx][elem_idx].clone())
1032            .collect();
1033        result.push(Value::Array(combo));
1034
1035        // Increment indices (like counting in mixed radix)
1036        let mut carry = true;
1037        for i in (0..arrays.len()).rev() {
1038            if carry {
1039                indices[i] += 1;
1040                if indices[i] >= arrays[i].len() {
1041                    indices[i] = 0;
1042                } else {
1043                    carry = false;
1044                }
1045            }
1046        }
1047
1048        // If we carried all the way through, we're done
1049        if carry {
1050            break;
1051        }
1052    }
1053
1054    result
1055}
1056
1057// =============================================================================
1058// initial(array) -> array (all elements except the last)
1059// =============================================================================
1060
1061defn!(InitialFn, vec![arg!(array)], None);
1062
1063impl Function for InitialFn {
1064    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1065        self.signature.validate(args, ctx)?;
1066
1067        let arr = args[0]
1068            .as_array()
1069            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1070
1071        if arr.is_empty() {
1072            return Ok(Value::Array(vec![]));
1073        }
1074
1075        let result: Vec<Value> = arr[..arr.len() - 1].to_vec();
1076        Ok(Value::Array(result))
1077    }
1078}
1079
1080// =============================================================================
1081// interpose(array, separator) -> array (insert separator between elements)
1082// =============================================================================
1083
1084defn!(InterposeFn, vec![arg!(array), arg!(any)], None);
1085
1086impl Function for InterposeFn {
1087    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1088        self.signature.validate(args, ctx)?;
1089
1090        let arr = args[0]
1091            .as_array()
1092            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1093
1094        let separator = args[1].clone();
1095
1096        if arr.is_empty() {
1097            return Ok(Value::Array(vec![]));
1098        }
1099
1100        if arr.len() == 1 {
1101            return Ok(Value::Array(arr.clone()));
1102        }
1103
1104        let mut result = Vec::with_capacity(arr.len() * 2 - 1);
1105        for (i, item) in arr.iter().enumerate() {
1106            if i > 0 {
1107                result.push(separator.clone());
1108            }
1109            result.push(item.clone());
1110        }
1111
1112        Ok(Value::Array(result))
1113    }
1114}
1115
1116// =============================================================================
1117// zipmap(keys, values) -> object (create object from parallel arrays)
1118// =============================================================================
1119
1120defn!(ZipmapFn, vec![arg!(array), arg!(array)], None);
1121
1122impl Function for ZipmapFn {
1123    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1124        self.signature.validate(args, ctx)?;
1125
1126        let keys = args[0]
1127            .as_array()
1128            .ok_or_else(|| custom_error(ctx, "Expected array argument for keys"))?;
1129
1130        let values = args[1]
1131            .as_array()
1132            .ok_or_else(|| custom_error(ctx, "Expected array argument for values"))?;
1133
1134        let len = keys.len().min(values.len());
1135        let mut result = serde_json::Map::new();
1136
1137        for i in 0..len {
1138            let key = keys[i]
1139                .as_str()
1140                .ok_or_else(|| custom_error(ctx, "Keys must be strings"))?;
1141            result.insert(key.to_string(), values[i].clone());
1142        }
1143
1144        Ok(Value::Object(result))
1145    }
1146}
1147
1148// =============================================================================
1149// partition_by(array, field_name) -> array (split when field value changes)
1150// =============================================================================
1151
1152defn!(PartitionByFn, vec![arg!(array), arg!(string)], None);
1153
1154impl Function for PartitionByFn {
1155    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1156        self.signature.validate(args, ctx)?;
1157
1158        let arr = args[0]
1159            .as_array()
1160            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1161
1162        let field_name = args[1]
1163            .as_str()
1164            .ok_or_else(|| custom_error(ctx, "Expected field name string"))?;
1165
1166        if arr.is_empty() {
1167            return Ok(Value::Array(vec![]));
1168        }
1169
1170        let mut result: Vec<Value> = Vec::new();
1171        let mut current_partition: Vec<Value> = Vec::new();
1172        let mut last_key: Option<String> = None;
1173
1174        for item in arr {
1175            // Extract key from object field, or serialize the item itself for primitives
1176            let key = if let Some(obj) = item.as_object() {
1177                if let Some(field_value) = obj.get(field_name) {
1178                    serde_json::to_string(field_value).unwrap_or_default()
1179                } else {
1180                    "null".to_string()
1181                }
1182            } else {
1183                // For non-objects, use the value itself as the key
1184                serde_json::to_string(item).unwrap_or_default()
1185            };
1186
1187            match &last_key {
1188                Some(prev_key) if *prev_key == key => {
1189                    current_partition.push(item.clone());
1190                }
1191                _ => {
1192                    if !current_partition.is_empty() {
1193                        result.push(Value::Array(current_partition));
1194                    }
1195                    current_partition = vec![item.clone()];
1196                    last_key = Some(key);
1197                }
1198            }
1199        }
1200
1201        // Don't forget the last partition
1202        if !current_partition.is_empty() {
1203            result.push(Value::Array(current_partition));
1204        }
1205
1206        Ok(Value::Array(result))
1207    }
1208}
1209
1210// =============================================================================
1211// dedupe(array) -> array (remove consecutive duplicates)
1212// =============================================================================
1213
1214defn!(DedupeFn, vec![arg!(array)], None);
1215
1216impl Function for DedupeFn {
1217    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1218        self.signature.validate(args, ctx)?;
1219
1220        let arr = args[0]
1221            .as_array()
1222            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1223
1224        if arr.is_empty() {
1225            return Ok(Value::Array(vec![]));
1226        }
1227
1228        let mut result: Vec<Value> = Vec::with_capacity(arr.len());
1229        let mut last_key: Option<String> = None;
1230
1231        for item in arr {
1232            let key = serde_json::to_string(item).unwrap_or_default();
1233            match &last_key {
1234                Some(prev_key) if *prev_key == key => {
1235                    // Skip consecutive duplicate
1236                }
1237                _ => {
1238                    result.push(item.clone());
1239                    last_key = Some(key);
1240                }
1241            }
1242        }
1243
1244        Ok(Value::Array(result))
1245    }
1246}
1247
1248// =============================================================================
1249// tail(array) -> array (all elements except the first)
1250// =============================================================================
1251
1252defn!(TailFn, vec![arg!(array)], None);
1253
1254impl Function for TailFn {
1255    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1256        self.signature.validate(args, ctx)?;
1257
1258        let arr = args[0]
1259            .as_array()
1260            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1261
1262        if arr.is_empty() {
1263            return Ok(Value::Array(vec![]));
1264        }
1265
1266        let result: Vec<Value> = arr[1..].to_vec();
1267        Ok(Value::Array(result))
1268    }
1269}
1270
1271// =============================================================================
1272// without(array, values_array) -> array (remove specified values)
1273// =============================================================================
1274
1275defn!(WithoutFn, vec![arg!(array), arg!(array)], None);
1276
1277impl Function for WithoutFn {
1278    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1279        self.signature.validate(args, ctx)?;
1280
1281        let arr = args[0]
1282            .as_array()
1283            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1284
1285        let exclude = args[1]
1286            .as_array()
1287            .ok_or_else(|| custom_error(ctx, "Expected array argument for values to exclude"))?;
1288
1289        // Create a set of serialized values to exclude for efficient lookup
1290        let exclude_set: HashSet<String> = exclude
1291            .iter()
1292            .map(|v| serde_json::to_string(v).unwrap_or_default())
1293            .collect();
1294
1295        let result: Vec<Value> = arr
1296            .iter()
1297            .filter(|item| {
1298                let key = serde_json::to_string(*item).unwrap_or_default();
1299                !exclude_set.contains(&key)
1300            })
1301            .cloned()
1302            .collect();
1303
1304        Ok(Value::Array(result))
1305    }
1306}
1307
1308// =============================================================================
1309// xor(array1, array2) -> array (symmetric difference)
1310// =============================================================================
1311
1312defn!(XorFn, vec![arg!(array), arg!(array)], None);
1313
1314impl Function for XorFn {
1315    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1316        self.signature.validate(args, ctx)?;
1317
1318        let arr1 = args[0]
1319            .as_array()
1320            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1321
1322        let arr2 = args[1]
1323            .as_array()
1324            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1325
1326        // Create sets of serialized values
1327        let set1: HashSet<String> = arr1
1328            .iter()
1329            .map(|v| serde_json::to_string(v).unwrap_or_default())
1330            .collect();
1331
1332        let set2: HashSet<String> = arr2
1333            .iter()
1334            .map(|v| serde_json::to_string(v).unwrap_or_default())
1335            .collect();
1336
1337        let mut result = Vec::new();
1338
1339        // Add elements from arr1 that are not in arr2
1340        for item in arr1 {
1341            let key = serde_json::to_string(item).unwrap_or_default();
1342            if !set2.contains(&key) {
1343                result.push(item.clone());
1344            }
1345        }
1346
1347        // Add elements from arr2 that are not in arr1
1348        for item in arr2 {
1349            let key = serde_json::to_string(item).unwrap_or_default();
1350            if !set1.contains(&key) {
1351                result.push(item.clone());
1352            }
1353        }
1354
1355        Ok(Value::Array(result))
1356    }
1357}
1358
1359// =============================================================================
1360// window(array, size, step?) -> array (sliding window)
1361// =============================================================================
1362
1363defn!(
1364    WindowFn,
1365    vec![arg!(array), arg!(number)],
1366    Some(arg!(number))
1367);
1368
1369impl Function for WindowFn {
1370    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1371        self.signature.validate(args, ctx)?;
1372
1373        let arr = args[0]
1374            .as_array()
1375            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1376
1377        let size = args[1]
1378            .as_f64()
1379            .ok_or_else(|| custom_error(ctx, "Expected number for window size"))?
1380            as usize;
1381
1382        if size == 0 {
1383            return Ok(Value::Array(vec![]));
1384        }
1385
1386        // Default step is 1
1387        let step = if args.len() > 2 {
1388            args[2]
1389                .as_f64()
1390                .ok_or_else(|| custom_error(ctx, "Expected number for step"))? as usize
1391        } else {
1392            1
1393        };
1394
1395        if step == 0 {
1396            return Err(custom_error(ctx, "Step cannot be zero"));
1397        }
1398
1399        let len = arr.len();
1400        if len < size {
1401            return Ok(Value::Array(vec![]));
1402        }
1403
1404        let mut result = Vec::new();
1405        let mut i = 0;
1406
1407        while i + size <= len {
1408            let window: Vec<Value> = arr[i..i + size].to_vec();
1409            result.push(Value::Array(window));
1410            i += step;
1411        }
1412
1413        Ok(Value::Array(result))
1414    }
1415}
1416
1417// =============================================================================
1418// combinations(array, k) -> array (k-combinations of array)
1419// =============================================================================
1420
1421defn!(CombinationsFn, vec![arg!(array), arg!(number)], None);
1422
1423fn generate_combinations(arr: &[Value], k: usize) -> Vec<Vec<Value>> {
1424    if k == 0 {
1425        return vec![vec![]];
1426    }
1427    if arr.len() < k {
1428        return vec![];
1429    }
1430
1431    let mut result = Vec::new();
1432
1433    // Include first element in combination
1434    let first = arr[0].clone();
1435    let rest = &arr[1..];
1436    for mut combo in generate_combinations(rest, k - 1) {
1437        let mut new_combo = vec![first.clone()];
1438        new_combo.append(&mut combo);
1439        result.push(new_combo);
1440    }
1441
1442    // Exclude first element
1443    result.extend(generate_combinations(rest, k));
1444
1445    result
1446}
1447
1448impl Function for CombinationsFn {
1449    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1450        self.signature.validate(args, ctx)?;
1451
1452        let arr = args[0]
1453            .as_array()
1454            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1455
1456        let k = args[1]
1457            .as_f64()
1458            .ok_or_else(|| custom_error(ctx, "Expected number for k"))? as usize;
1459
1460        // Limit to prevent excessive computation
1461        const MAX_COMBINATIONS: usize = 10000;
1462
1463        // Quick check: if C(n, k) would be too large, return error
1464        let n = arr.len();
1465        if n > 20 && k > 3 && k < n - 3 {
1466            return Err(custom_error(ctx, "Combination size too large"));
1467        }
1468
1469        let combinations = generate_combinations(arr, k);
1470
1471        if combinations.len() > MAX_COMBINATIONS {
1472            return Err(custom_error(ctx, "Too many combinations generated"));
1473        }
1474
1475        let result: Vec<Value> = combinations.into_iter().map(Value::Array).collect();
1476
1477        Ok(Value::Array(result))
1478    }
1479}
1480
1481// =============================================================================
1482// fill(array, value, start?, end?) -> array (fill range with value)
1483// =============================================================================
1484
1485defn!(FillFn, vec![arg!(array), arg!(any)], Some(arg!(number)));
1486
1487impl Function for FillFn {
1488    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1489        self.signature.validate(args, ctx)?;
1490
1491        let arr = args[0]
1492            .as_array()
1493            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1494
1495        let fill_value = args[1].clone();
1496
1497        let len = arr.len();
1498        if len == 0 {
1499            return Ok(Value::Array(vec![]));
1500        }
1501
1502        // Default start is 0, default end is array length
1503        let start = if args.len() > 2 {
1504            let s = args[2]
1505                .as_f64()
1506                .ok_or_else(|| custom_error(ctx, "Expected number for start index"))?
1507                as i64;
1508            // Handle negative indices
1509            if s < 0 {
1510                (len as i64 + s).max(0) as usize
1511            } else {
1512                (s as usize).min(len)
1513            }
1514        } else {
1515            0
1516        };
1517
1518        let end = if args.len() > 3 {
1519            let e = args[3]
1520                .as_f64()
1521                .ok_or_else(|| custom_error(ctx, "Expected number for end index"))?
1522                as i64;
1523            // Handle negative indices
1524            if e < 0 {
1525                (len as i64 + e).max(0) as usize
1526            } else {
1527                (e as usize).min(len)
1528            }
1529        } else {
1530            len
1531        };
1532
1533        let mut result: Vec<Value> = arr.clone();
1534
1535        for item in result.iter_mut().take(end.min(len)).skip(start) {
1536            *item = fill_value.clone();
1537        }
1538
1539        Ok(Value::Array(result))
1540    }
1541}
1542
1543// =============================================================================
1544// pull_at(array, indices_array) -> array (get elements at specified indices)
1545// =============================================================================
1546
1547defn!(PullAtFn, vec![arg!(array), arg!(array)], None);
1548
1549impl Function for PullAtFn {
1550    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1551        self.signature.validate(args, ctx)?;
1552
1553        let arr = args[0]
1554            .as_array()
1555            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1556
1557        let indices = args[1]
1558            .as_array()
1559            .ok_or_else(|| custom_error(ctx, "Expected array of indices"))?;
1560
1561        let len = arr.len();
1562        let mut result = Vec::new();
1563
1564        for idx_var in indices {
1565            let idx = idx_var
1566                .as_f64()
1567                .ok_or_else(|| custom_error(ctx, "Expected number in indices array"))?
1568                as i64;
1569
1570            // Handle negative indices
1571            let actual_idx = if idx < 0 {
1572                (len as i64 + idx).max(0) as usize
1573            } else {
1574                idx as usize
1575            };
1576
1577            if actual_idx < len {
1578                result.push(arr[actual_idx].clone());
1579            }
1580        }
1581
1582        Ok(Value::Array(result))
1583    }
1584}
1585
1586// =============================================================================
1587// transpose(array) -> array
1588// =============================================================================
1589
1590defn!(TransposeFn, vec![arg!(array)], None);
1591
1592impl Function for TransposeFn {
1593    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1594        self.signature.validate(args, ctx)?;
1595
1596        let arr = args[0]
1597            .as_array()
1598            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1599
1600        if arr.is_empty() {
1601            return Ok(Value::Array(vec![]));
1602        }
1603
1604        // Get all inner arrays and find the minimum length
1605        let mut inner_arrays: Vec<&Vec<Value>> = Vec::new();
1606        let mut min_len = usize::MAX;
1607
1608        for item in arr {
1609            if let Some(inner) = item.as_array() {
1610                min_len = min_len.min(inner.len());
1611                inner_arrays.push(inner);
1612            } else {
1613                // If any element is not an array, return empty
1614                return Ok(Value::Array(vec![]));
1615            }
1616        }
1617
1618        if inner_arrays.is_empty() || min_len == 0 {
1619            return Ok(Value::Array(vec![]));
1620        }
1621
1622        // Transpose: create new arrays where each contains the i-th element from each inner array
1623        let mut result = Vec::with_capacity(min_len);
1624        for i in 0..min_len {
1625            let mut row = Vec::with_capacity(inner_arrays.len());
1626            for inner in &inner_arrays {
1627                row.push(inner[i].clone());
1628            }
1629            result.push(Value::Array(row));
1630        }
1631
1632        Ok(Value::Array(result))
1633    }
1634}
1635
1636// =============================================================================
1637// pairwise(array) -> array
1638// =============================================================================
1639
1640defn!(PairwiseFn, vec![arg!(array)], None);
1641
1642impl Function for PairwiseFn {
1643    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1644        self.signature.validate(args, ctx)?;
1645
1646        let arr = args[0]
1647            .as_array()
1648            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1649
1650        if arr.len() < 2 {
1651            return Ok(Value::Array(vec![]));
1652        }
1653
1654        let mut result = Vec::with_capacity(arr.len() - 1);
1655        for i in 0..arr.len() - 1 {
1656            let pair = vec![arr[i].clone(), arr[i + 1].clone()];
1657            result.push(Value::Array(pair));
1658        }
1659
1660        Ok(Value::Array(result))
1661    }
1662}
1663
1664// =============================================================================
1665// indices_array(array, value) -> array of indices
1666// =============================================================================
1667
1668defn!(IndicesArrayFn, vec![arg!(array), arg!(any)], None);
1669
1670impl Function for IndicesArrayFn {
1671    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1672        self.signature.validate(args, ctx)?;
1673
1674        let arr = args[0]
1675            .as_array()
1676            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1677
1678        let search_key = serde_json::to_string(&args[1]).unwrap_or_default();
1679
1680        let mut indices: Vec<Value> = Vec::new();
1681        for (i, item) in arr.iter().enumerate() {
1682            let item_key = serde_json::to_string(item).unwrap_or_default();
1683            if item_key == search_key {
1684                indices.push(Value::Number(Number::from(i as i64)));
1685            }
1686        }
1687
1688        Ok(Value::Array(indices))
1689    }
1690}
1691
1692// =============================================================================
1693// inside_array(needle, haystack) -> boolean
1694// =============================================================================
1695
1696defn!(InsideArrayFn, vec![arg!(array), arg!(array)], None);
1697
1698impl Function for InsideArrayFn {
1699    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1700        self.signature.validate(args, ctx)?;
1701
1702        let needle = args[0]
1703            .as_array()
1704            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1705
1706        let haystack = args[1]
1707            .as_array()
1708            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1709
1710        // Build a set of serialized haystack values for efficient lookup
1711        let haystack_set: HashSet<String> = haystack
1712            .iter()
1713            .map(|item| serde_json::to_string(item).unwrap_or_default())
1714            .collect();
1715
1716        // Check if all needle elements are in the haystack
1717        let result = needle.iter().all(|item| {
1718            let item_key = serde_json::to_string(item).unwrap_or_default();
1719            haystack_set.contains(&item_key)
1720        });
1721
1722        Ok(Value::Bool(result))
1723    }
1724}
1725
1726// =============================================================================
1727// bsearch(sorted_array, value) -> number
1728// =============================================================================
1729
1730defn!(BsearchFn, vec![arg!(array), arg!(any)], None);
1731
1732impl Function for BsearchFn {
1733    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1734        self.signature.validate(args, ctx)?;
1735
1736        let arr = args[0]
1737            .as_array()
1738            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1739
1740        let target = &args[1];
1741
1742        if arr.is_empty() {
1743            return Ok(Value::Number(Number::from(-1)));
1744        }
1745
1746        // Helper to compare two Value values
1747        // Returns Ordering based on type-aware comparison
1748        fn compare_values(a: &Value, b: &Value) -> std::cmp::Ordering {
1749            match (a, b) {
1750                // Numbers: compare numerically
1751                (Value::Number(n1), Value::Number(n2)) => {
1752                    let f1 = n1.as_f64().unwrap_or(0.0);
1753                    let f2 = n2.as_f64().unwrap_or(0.0);
1754                    f1.partial_cmp(&f2).unwrap_or(std::cmp::Ordering::Equal)
1755                }
1756                // Strings: compare lexicographically
1757                (Value::String(s1), Value::String(s2)) => s1.cmp(s2),
1758                // Booleans: false < true
1759                (Value::Bool(b1), Value::Bool(b2)) => b1.cmp(b2),
1760                // Different types or complex types: fall back to JSON string comparison
1761                _ => {
1762                    let s1 = serde_json::to_string(a).unwrap_or_default();
1763                    let s2 = serde_json::to_string(b).unwrap_or_default();
1764                    s1.cmp(&s2)
1765                }
1766            }
1767        }
1768
1769        let mut left = 0i64;
1770        let mut right = arr.len() as i64 - 1;
1771
1772        while left <= right {
1773            let mid = left + (right - left) / 2;
1774
1775            match compare_values(&arr[mid as usize], target) {
1776                std::cmp::Ordering::Equal => {
1777                    return Ok(Value::Number(Number::from(mid)));
1778                }
1779                std::cmp::Ordering::Less => {
1780                    left = mid + 1;
1781                }
1782                std::cmp::Ordering::Greater => {
1783                    right = mid - 1;
1784                }
1785            }
1786        }
1787
1788        // Not found - return -(insertion_point) - 1
1789        // At this point, left is the insertion point
1790        let result = -(left) - 1;
1791        Ok(Value::Number(Number::from(result)))
1792    }
1793}
1794
1795// =============================================================================
1796// repeat_array(value, n) -> array (create array with value repeated n times)
1797// =============================================================================
1798
1799defn!(RepeatArrayFn, vec![arg!(any), arg!(number)], None);
1800
1801impl Function for RepeatArrayFn {
1802    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1803        self.signature.validate(args, ctx)?;
1804
1805        let value = &args[0];
1806        let n = args[1]
1807            .as_f64()
1808            .ok_or_else(|| custom_error(ctx, "Expected number for count argument"))?
1809            as i64;
1810
1811        if n < 0 {
1812            return Err(custom_error(ctx, "Count must be non-negative"));
1813        }
1814
1815        let result: Vec<Value> = (0..n).map(|_| value.clone()).collect();
1816        Ok(Value::Array(result))
1817    }
1818}
1819
1820// =============================================================================
1821// cycle(array, n) -> array (cycle through array n times)
1822// =============================================================================
1823
1824defn!(CycleFn, vec![arg!(array), arg!(number)], None);
1825
1826impl Function for CycleFn {
1827    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1828        self.signature.validate(args, ctx)?;
1829
1830        let arr = args[0]
1831            .as_array()
1832            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1833
1834        let n = args[1]
1835            .as_f64()
1836            .ok_or_else(|| custom_error(ctx, "Expected number for count argument"))?
1837            as i64;
1838
1839        if n < 0 {
1840            return Err(custom_error(ctx, "Count must be non-negative"));
1841        }
1842
1843        if arr.is_empty() || n == 0 {
1844            return Ok(Value::Array(vec![]));
1845        }
1846
1847        let mut result: Vec<Value> = Vec::with_capacity(arr.len() * n as usize);
1848        for _ in 0..n {
1849            result.extend(arr.iter().cloned());
1850        }
1851        Ok(Value::Array(result))
1852    }
1853}
1854
1855// =============================================================================
1856// lag(array, n) -> array
1857// =============================================================================
1858
1859defn!(LagFn, vec![arg!(array), arg!(number)], None);
1860
1861impl Function for LagFn {
1862    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1863        self.signature.validate(args, ctx)?;
1864        let arr = args[0].as_array().unwrap();
1865        let n = args[1].as_f64().unwrap() as usize;
1866        let len = arr.len();
1867        let mut result = Vec::with_capacity(len);
1868        for _ in 0..n.min(len) {
1869            result.push(Value::Null);
1870        }
1871        if n < len {
1872            result.extend_from_slice(&arr[..len - n]);
1873        }
1874        Ok(Value::Array(result))
1875    }
1876}
1877
1878// =============================================================================
1879// lead(array, n) -> array
1880// =============================================================================
1881
1882defn!(LeadFn, vec![arg!(array), arg!(number)], None);
1883
1884impl Function for LeadFn {
1885    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1886        self.signature.validate(args, ctx)?;
1887        let arr = args[0].as_array().unwrap();
1888        let n = args[1].as_f64().unwrap() as usize;
1889        let len = arr.len();
1890        let mut result = Vec::with_capacity(len);
1891        if n < len {
1892            result.extend_from_slice(&arr[n..]);
1893        }
1894        let remaining = len.saturating_sub(result.len());
1895        for _ in 0..remaining {
1896            result.push(Value::Null);
1897        }
1898        Ok(Value::Array(result))
1899    }
1900}
1901
1902#[cfg(test)]
1903mod tests {
1904    use crate::Runtime;
1905    use serde_json::json;
1906
1907    fn setup_runtime() -> Runtime {
1908        Runtime::builder()
1909            .with_standard()
1910            .with_all_extensions()
1911            .build()
1912    }
1913
1914    #[test]
1915    fn test_unique() {
1916        let runtime = setup_runtime();
1917        let expr = runtime.compile("unique(@)").unwrap();
1918        let data = json!([1, 2, 1]);
1919        let result = expr.search(&data).unwrap();
1920        let arr = result.as_array().unwrap();
1921        assert_eq!(arr.len(), 2);
1922    }
1923
1924    #[test]
1925    fn test_first() {
1926        let runtime = setup_runtime();
1927        let expr = runtime.compile("first(@)").unwrap();
1928        let data = json!([1, 2]);
1929        let result = expr.search(&data).unwrap();
1930        assert_eq!(result.as_f64().unwrap() as i64, 1);
1931    }
1932
1933    #[test]
1934    fn test_last() {
1935        let runtime = setup_runtime();
1936        let expr = runtime.compile("last(@)").unwrap();
1937        let data = json!([1, 2]);
1938        let result = expr.search(&data).unwrap();
1939        assert_eq!(result.as_f64().unwrap() as i64, 2);
1940    }
1941
1942    #[test]
1943    fn test_range() {
1944        let runtime = setup_runtime();
1945        let expr = runtime.compile("range(`0`, `5`)").unwrap();
1946        let data = json!(null);
1947        let result = expr.search(&data).unwrap();
1948        let arr = result.as_array().unwrap();
1949        assert_eq!(arr.len(), 5);
1950    }
1951
1952    #[test]
1953    fn test_butlast() {
1954        // butlast is an alias for initial
1955        let runtime = setup_runtime();
1956        let expr = runtime.compile("butlast(@)").unwrap();
1957        let data = json!([1, 2, 3]);
1958        let result = expr.search(&data).unwrap();
1959        let arr = result.as_array().unwrap();
1960        assert_eq!(arr.len(), 2);
1961        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
1962        assert_eq!(arr[1].as_f64().unwrap() as i64, 2);
1963    }
1964
1965    #[test]
1966    fn test_interpose() {
1967        let runtime = setup_runtime();
1968        let expr = runtime.compile("interpose(@, `0`)").unwrap();
1969        let data = json!([1, 2, 3]);
1970        let result = expr.search(&data).unwrap();
1971        let arr = result.as_array().unwrap();
1972        assert_eq!(arr.len(), 5);
1973        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
1974        assert_eq!(arr[1].as_f64().unwrap() as i64, 0);
1975        assert_eq!(arr[2].as_f64().unwrap() as i64, 2);
1976        assert_eq!(arr[3].as_f64().unwrap() as i64, 0);
1977        assert_eq!(arr[4].as_f64().unwrap() as i64, 3);
1978    }
1979
1980    #[test]
1981    fn test_interpose_empty() {
1982        let runtime = setup_runtime();
1983        let expr = runtime.compile("interpose(@, `0`)").unwrap();
1984        let data = json!([]);
1985        let result = expr.search(&data).unwrap();
1986        let arr = result.as_array().unwrap();
1987        assert_eq!(arr.len(), 0);
1988    }
1989
1990    #[test]
1991    fn test_interpose_single() {
1992        let runtime = setup_runtime();
1993        let expr = runtime.compile("interpose(@, `0`)").unwrap();
1994        let data = json!([1]);
1995        let result = expr.search(&data).unwrap();
1996        let arr = result.as_array().unwrap();
1997        assert_eq!(arr.len(), 1);
1998        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
1999    }
2000
2001    #[test]
2002    fn test_interpose_string_separator() {
2003        let runtime = setup_runtime();
2004        let expr = runtime.compile("interpose(@, `\"-\"`)").unwrap();
2005        let data = json!(["a", "b", "c"]);
2006        let result = expr.search(&data).unwrap();
2007        let arr = result.as_array().unwrap();
2008        assert_eq!(arr.len(), 5);
2009        assert_eq!(arr[0].as_str().unwrap(), "a");
2010        assert_eq!(arr[1].as_str().unwrap(), "-");
2011        assert_eq!(arr[2].as_str().unwrap(), "b");
2012        assert_eq!(arr[3].as_str().unwrap(), "-");
2013        assert_eq!(arr[4].as_str().unwrap(), "c");
2014    }
2015
2016    #[test]
2017    fn test_zipmap() {
2018        let runtime = setup_runtime();
2019        let expr = runtime
2020            .compile("zipmap(`[\"a\", \"b\", \"c\"]`, `[1, 2, 3]`)")
2021            .unwrap();
2022        let data = json!(null);
2023        let result = expr.search(&data).unwrap();
2024        let obj = result.as_object().unwrap();
2025        assert_eq!(obj.len(), 3);
2026        assert_eq!(obj.get("a").unwrap().as_f64().unwrap() as i64, 1);
2027        assert_eq!(obj.get("b").unwrap().as_f64().unwrap() as i64, 2);
2028        assert_eq!(obj.get("c").unwrap().as_f64().unwrap() as i64, 3);
2029    }
2030
2031    #[test]
2032    fn test_zipmap_unequal_lengths() {
2033        let runtime = setup_runtime();
2034        // Keys shorter than values
2035        let expr = runtime
2036            .compile("zipmap(`[\"x\", \"y\"]`, `[10, 20, 30]`)")
2037            .unwrap();
2038        let data = json!(null);
2039        let result = expr.search(&data).unwrap();
2040        let obj = result.as_object().unwrap();
2041        assert_eq!(obj.len(), 2);
2042        assert_eq!(obj.get("x").unwrap().as_f64().unwrap() as i64, 10);
2043        assert_eq!(obj.get("y").unwrap().as_f64().unwrap() as i64, 20);
2044    }
2045
2046    #[test]
2047    fn test_zipmap_empty() {
2048        let runtime = setup_runtime();
2049        let expr = runtime.compile("zipmap(`[]`, `[]`)").unwrap();
2050        let data = json!(null);
2051        let result = expr.search(&data).unwrap();
2052        let obj = result.as_object().unwrap();
2053        assert_eq!(obj.len(), 0);
2054    }
2055
2056    #[test]
2057    fn test_partition_by() {
2058        let runtime = setup_runtime();
2059        // Test with objects - partition by "type" field
2060        let expr = runtime.compile(r#"partition_by(@, `"type"`)"#).unwrap();
2061        let data: serde_json::Value = serde_json::from_str(
2062            r#"[{"type": "a", "v": 1}, {"type": "a", "v": 2}, {"type": "b", "v": 3}, {"type": "a", "v": 4}]"#,
2063        )
2064        .unwrap();
2065        let result = expr.search(&data).unwrap();
2066        let arr = result.as_array().unwrap();
2067        assert_eq!(arr.len(), 3);
2068
2069        let partition1 = arr[0].as_array().unwrap();
2070        assert_eq!(partition1.len(), 2); // Two "a" items
2071
2072        let partition2 = arr[1].as_array().unwrap();
2073        assert_eq!(partition2.len(), 1); // One "b" item
2074
2075        let partition3 = arr[2].as_array().unwrap();
2076        assert_eq!(partition3.len(), 1); // One more "a" item
2077    }
2078
2079    #[test]
2080    fn test_partition_by_primitives() {
2081        let runtime = setup_runtime();
2082        // For primitives, use any field name - it will use the value itself
2083        let expr = runtime.compile(r#"partition_by(@, `"_"`)"#).unwrap();
2084        let data = json!([1, 1, 2, 2, 1, 1]);
2085        let result = expr.search(&data).unwrap();
2086        let arr = result.as_array().unwrap();
2087        assert_eq!(arr.len(), 3);
2088
2089        let partition1 = arr[0].as_array().unwrap();
2090        assert_eq!(partition1.len(), 2);
2091        assert_eq!(partition1[0].as_f64().unwrap() as i64, 1);
2092
2093        let partition2 = arr[1].as_array().unwrap();
2094        assert_eq!(partition2.len(), 2);
2095        assert_eq!(partition2[0].as_f64().unwrap() as i64, 2);
2096
2097        let partition3 = arr[2].as_array().unwrap();
2098        assert_eq!(partition3.len(), 2);
2099        assert_eq!(partition3[0].as_f64().unwrap() as i64, 1);
2100    }
2101
2102    #[test]
2103    fn test_partition_by_empty() {
2104        let runtime = setup_runtime();
2105        let expr = runtime.compile(r#"partition_by(@, `"type"`)"#).unwrap();
2106        let data = json!([]);
2107        let result = expr.search(&data).unwrap();
2108        let arr = result.as_array().unwrap();
2109        assert_eq!(arr.len(), 0);
2110    }
2111
2112    #[test]
2113    fn test_partition_by_single() {
2114        let runtime = setup_runtime();
2115        let expr = runtime.compile(r#"partition_by(@, `"type"`)"#).unwrap();
2116        let data: serde_json::Value = serde_json::from_str(r#"[{"type": "a"}]"#).unwrap();
2117        let result = expr.search(&data).unwrap();
2118        let arr = result.as_array().unwrap();
2119        assert_eq!(arr.len(), 1);
2120        let partition1 = arr[0].as_array().unwrap();
2121        assert_eq!(partition1.len(), 1);
2122    }
2123
2124    #[test]
2125    fn test_dedupe() {
2126        let runtime = setup_runtime();
2127        let expr = runtime.compile("dedupe(@)").unwrap();
2128        let data = json!([1, 1, 2, 2, 1, 1]);
2129        let result = expr.search(&data).unwrap();
2130        let arr = result.as_array().unwrap();
2131        assert_eq!(arr.len(), 3);
2132        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
2133        assert_eq!(arr[1].as_f64().unwrap() as i64, 2);
2134        assert_eq!(arr[2].as_f64().unwrap() as i64, 1);
2135    }
2136
2137    #[test]
2138    fn test_dedupe_empty() {
2139        let runtime = setup_runtime();
2140        let expr = runtime.compile("dedupe(@)").unwrap();
2141        let data = json!([]);
2142        let result = expr.search(&data).unwrap();
2143        let arr = result.as_array().unwrap();
2144        assert_eq!(arr.len(), 0);
2145    }
2146
2147    #[test]
2148    fn test_dedupe_no_consecutive() {
2149        let runtime = setup_runtime();
2150        let expr = runtime.compile("dedupe(@)").unwrap();
2151        let data = json!([1, 2, 3]);
2152        let result = expr.search(&data).unwrap();
2153        let arr = result.as_array().unwrap();
2154        assert_eq!(arr.len(), 3);
2155    }
2156
2157    #[test]
2158    fn test_dedupe_strings() {
2159        let runtime = setup_runtime();
2160        let expr = runtime.compile("dedupe(@)").unwrap();
2161        let data = json!(["a", "a", "b", "a"]);
2162        let result = expr.search(&data).unwrap();
2163        let arr = result.as_array().unwrap();
2164        assert_eq!(arr.len(), 3);
2165        assert_eq!(arr[0].as_str().unwrap(), "a");
2166        assert_eq!(arr[1].as_str().unwrap(), "b");
2167        assert_eq!(arr[2].as_str().unwrap(), "a");
2168    }
2169
2170    #[test]
2171    fn test_dedupe_objects() {
2172        let runtime = setup_runtime();
2173        let expr = runtime.compile("dedupe(@)").unwrap();
2174        let data: serde_json::Value =
2175            serde_json::from_str(r#"[{"x": 1}, {"x": 1}, {"x": 2}, {"x": 1}]"#).unwrap();
2176        let result = expr.search(&data).unwrap();
2177        let arr = result.as_array().unwrap();
2178        assert_eq!(arr.len(), 3);
2179    }
2180
2181    #[test]
2182    fn test_dedupe_all_same() {
2183        let runtime = setup_runtime();
2184        let expr = runtime.compile("dedupe(@)").unwrap();
2185        let data = json!([1, 1, 1]);
2186        let result = expr.search(&data).unwrap();
2187        let arr = result.as_array().unwrap();
2188        assert_eq!(arr.len(), 1);
2189        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
2190    }
2191
2192    #[test]
2193    fn test_zipmap_duplicate_keys() {
2194        // Later key should overwrite earlier one
2195        let runtime = setup_runtime();
2196        let expr = runtime
2197            .compile("zipmap(`[\"a\", \"b\", \"a\"]`, `[1, 2, 3]`)")
2198            .unwrap();
2199        let data = json!(null);
2200        let result = expr.search(&data).unwrap();
2201        let obj = result.as_object().unwrap();
2202        assert_eq!(obj.len(), 2);
2203        assert_eq!(obj.get("a").unwrap().as_f64().unwrap() as i64, 3); // Last value wins
2204        assert_eq!(obj.get("b").unwrap().as_f64().unwrap() as i64, 2);
2205    }
2206
2207    #[test]
2208    fn test_zipmap_values_longer() {
2209        let runtime = setup_runtime();
2210        let expr = runtime.compile("zipmap(`[\"a\"]`, `[1, 2, 3]`)").unwrap();
2211        let data = json!(null);
2212        let result = expr.search(&data).unwrap();
2213        let obj = result.as_object().unwrap();
2214        assert_eq!(obj.len(), 1);
2215        assert_eq!(obj.get("a").unwrap().as_f64().unwrap() as i64, 1);
2216    }
2217
2218    #[test]
2219    fn test_partition_by_missing_field() {
2220        let runtime = setup_runtime();
2221        let expr = runtime.compile(r#"partition_by(@, `"type"`)"#).unwrap();
2222        // Some objects have type, some don't
2223        let data: serde_json::Value =
2224            serde_json::from_str(r#"[{"type": "a"}, {"name": "no-type"}, {"type": "a"}]"#).unwrap();
2225        let result = expr.search(&data).unwrap();
2226        let arr = result.as_array().unwrap();
2227        // Should partition into 3: [type:a], [no type -> null], [type:a]
2228        assert_eq!(arr.len(), 3);
2229    }
2230
2231    #[test]
2232    fn test_partition_by_all_same() {
2233        let runtime = setup_runtime();
2234        let expr = runtime.compile(r#"partition_by(@, `"type"`)"#).unwrap();
2235        let data: serde_json::Value =
2236            serde_json::from_str(r#"[{"type": "a"}, {"type": "a"}, {"type": "a"}]"#).unwrap();
2237        let result = expr.search(&data).unwrap();
2238        let arr = result.as_array().unwrap();
2239        assert_eq!(arr.len(), 1);
2240        let partition = arr[0].as_array().unwrap();
2241        assert_eq!(partition.len(), 3);
2242    }
2243
2244    #[test]
2245    fn test_interpose_null_separator() {
2246        let runtime = setup_runtime();
2247        let expr = runtime.compile("interpose(@, `null`)").unwrap();
2248        let data = json!([1, 2]);
2249        let result = expr.search(&data).unwrap();
2250        let arr = result.as_array().unwrap();
2251        assert_eq!(arr.len(), 3);
2252        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
2253        assert!(arr[1].is_null());
2254        assert_eq!(arr[2].as_f64().unwrap() as i64, 2);
2255    }
2256
2257    #[test]
2258    fn test_interpose_object_separator() {
2259        let runtime = setup_runtime();
2260        let expr = runtime.compile(r#"interpose(@, `{"sep": true}`)"#).unwrap();
2261        let data = json!([1, 2]);
2262        let result = expr.search(&data).unwrap();
2263        let arr = result.as_array().unwrap();
2264        assert_eq!(arr.len(), 3);
2265        assert!(arr[1].as_object().is_some());
2266    }
2267
2268    // =========================================================================
2269    // zip tests
2270    // =========================================================================
2271
2272    #[test]
2273    fn test_zip_basic() {
2274        let runtime = setup_runtime();
2275        let data: serde_json::Value =
2276            serde_json::from_str(r#"{"a": [1, 2, 3], "b": ["x", "y", "z"]}"#).unwrap();
2277        let expr = runtime.compile("zip(a, b)").unwrap();
2278        let result = expr.search(&data).unwrap();
2279        let arr = result.as_array().unwrap();
2280        assert_eq!(arr.len(), 3);
2281        assert_eq!(arr[0].as_array().unwrap()[0].as_f64().unwrap() as i64, 1);
2282        assert_eq!(arr[0].as_array().unwrap()[1].as_str().unwrap(), "x");
2283    }
2284
2285    #[test]
2286    fn test_zip_unequal_lengths() {
2287        let runtime = setup_runtime();
2288        let data: serde_json::Value =
2289            serde_json::from_str(r#"{"a": [1, 2], "b": ["x", "y", "z"]}"#).unwrap();
2290        let expr = runtime.compile("zip(a, b)").unwrap();
2291        let result = expr.search(&data).unwrap();
2292        let arr = result.as_array().unwrap();
2293        // Stops at shorter array
2294        assert_eq!(arr.len(), 2);
2295    }
2296
2297    #[test]
2298    fn test_zip_empty_array() {
2299        let runtime = setup_runtime();
2300        let data: serde_json::Value = serde_json::from_str(r#"{"a": [], "b": [1, 2, 3]}"#).unwrap();
2301        let expr = runtime.compile("zip(a, b)").unwrap();
2302        let result = expr.search(&data).unwrap();
2303        let arr = result.as_array().unwrap();
2304        assert_eq!(arr.len(), 0);
2305    }
2306
2307    #[test]
2308    fn test_zip_with_objects() {
2309        let runtime = setup_runtime();
2310        let data: serde_json::Value =
2311            serde_json::from_str(r#"{"names": ["Alice", "Bob"], "scores": [95, 87]}"#).unwrap();
2312        let expr = runtime.compile("zip(names, scores)").unwrap();
2313        let result = expr.search(&data).unwrap();
2314        let arr = result.as_array().unwrap();
2315        assert_eq!(arr.len(), 2);
2316        assert_eq!(arr[0].as_array().unwrap()[0].as_str().unwrap(), "Alice");
2317        assert_eq!(arr[0].as_array().unwrap()[1].as_f64().unwrap() as i64, 95);
2318    }
2319
2320    // =========================================================================
2321    // chunk tests
2322    // =========================================================================
2323
2324    #[test]
2325    fn test_chunk_basic() {
2326        let runtime = setup_runtime();
2327        let data = json!([1, 2, 3, 4, 5]);
2328        let expr = runtime.compile("chunk(@, `2`)").unwrap();
2329        let result = expr.search(&data).unwrap();
2330        let arr = result.as_array().unwrap();
2331        assert_eq!(arr.len(), 3); // [1,2], [3,4], [5]
2332        assert_eq!(arr[0].as_array().unwrap().len(), 2);
2333        assert_eq!(arr[2].as_array().unwrap().len(), 1);
2334    }
2335
2336    #[test]
2337    fn test_chunk_exact_fit() {
2338        let runtime = setup_runtime();
2339        let data = json!([1, 2, 3, 4, 5, 6]);
2340        let expr = runtime.compile("chunk(@, `3`)").unwrap();
2341        let result = expr.search(&data).unwrap();
2342        let arr = result.as_array().unwrap();
2343        assert_eq!(arr.len(), 2);
2344        assert_eq!(arr[0].as_array().unwrap().len(), 3);
2345        assert_eq!(arr[1].as_array().unwrap().len(), 3);
2346    }
2347
2348    #[test]
2349    fn test_chunk_size_larger_than_array() {
2350        let runtime = setup_runtime();
2351        let data = json!([1, 2, 3]);
2352        let expr = runtime.compile("chunk(@, `10`)").unwrap();
2353        let result = expr.search(&data).unwrap();
2354        let arr = result.as_array().unwrap();
2355        assert_eq!(arr.len(), 1);
2356        assert_eq!(arr[0].as_array().unwrap().len(), 3);
2357    }
2358
2359    #[test]
2360    fn test_chunk_size_one() {
2361        let runtime = setup_runtime();
2362        let data = json!([1, 2, 3]);
2363        let expr = runtime.compile("chunk(@, `1`)").unwrap();
2364        let result = expr.search(&data).unwrap();
2365        let arr = result.as_array().unwrap();
2366        assert_eq!(arr.len(), 3);
2367    }
2368
2369    #[test]
2370    fn test_chunk_and_process_pipeline() {
2371        let runtime = setup_runtime();
2372        let data = json!([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
2373        let expr = runtime.compile("chunk(@, `3`)").unwrap();
2374        let result = expr.search(&data).unwrap();
2375        let arr = result.as_array().unwrap();
2376        // [1,2,3], [4,5,6], [7,8,9], [10]
2377        assert_eq!(arr.len(), 4);
2378    }
2379
2380    // =========================================================================
2381    // take tests
2382    // =========================================================================
2383
2384    #[test]
2385    fn test_take_basic() {
2386        let runtime = setup_runtime();
2387        let data = json!([1, 2, 3, 4, 5]);
2388        let expr = runtime.compile("take(@, `3`)").unwrap();
2389        let result = expr.search(&data).unwrap();
2390        let arr = result.as_array().unwrap();
2391        assert_eq!(arr.len(), 3);
2392        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
2393        assert_eq!(arr[2].as_f64().unwrap() as i64, 3);
2394    }
2395
2396    #[test]
2397    fn test_take_more_than_length() {
2398        let runtime = setup_runtime();
2399        let data = json!([1, 2]);
2400        let expr = runtime.compile("take(@, `10`)").unwrap();
2401        let result = expr.search(&data).unwrap();
2402        let arr = result.as_array().unwrap();
2403        assert_eq!(arr.len(), 2);
2404    }
2405
2406    #[test]
2407    fn test_take_zero() {
2408        let runtime = setup_runtime();
2409        let data = json!([1, 2, 3]);
2410        let expr = runtime.compile("take(@, `0`)").unwrap();
2411        let result = expr.search(&data).unwrap();
2412        let arr = result.as_array().unwrap();
2413        assert_eq!(arr.len(), 0);
2414    }
2415
2416    // =========================================================================
2417    // drop tests
2418    // =========================================================================
2419
2420    #[test]
2421    fn test_drop_basic() {
2422        let runtime = setup_runtime();
2423        let data = json!([1, 2, 3, 4, 5]);
2424        let expr = runtime.compile("drop(@, `2`)").unwrap();
2425        let result = expr.search(&data).unwrap();
2426        let arr = result.as_array().unwrap();
2427        assert_eq!(arr.len(), 3);
2428        assert_eq!(arr[0].as_f64().unwrap() as i64, 3);
2429    }
2430
2431    #[test]
2432    fn test_drop_more_than_length() {
2433        let runtime = setup_runtime();
2434        let data = json!([1, 2]);
2435        let expr = runtime.compile("drop(@, `10`)").unwrap();
2436        let result = expr.search(&data).unwrap();
2437        let arr = result.as_array().unwrap();
2438        assert_eq!(arr.len(), 0);
2439    }
2440
2441    #[test]
2442    fn test_drop_zero() {
2443        let runtime = setup_runtime();
2444        let data = json!([1, 2, 3]);
2445        let expr = runtime.compile("drop(@, `0`)").unwrap();
2446        let result = expr.search(&data).unwrap();
2447        let arr = result.as_array().unwrap();
2448        assert_eq!(arr.len(), 3);
2449    }
2450
2451    // =========================================================================
2452    // flatten_deep tests
2453    // =========================================================================
2454
2455    #[test]
2456    fn test_flatten_deep_basic() {
2457        let runtime = setup_runtime();
2458        let data = json!([[1, 2], [3, 4]]);
2459        let expr = runtime.compile("flatten_deep(@)").unwrap();
2460        let result = expr.search(&data).unwrap();
2461        let arr = result.as_array().unwrap();
2462        assert_eq!(arr.len(), 4);
2463    }
2464
2465    #[test]
2466    fn test_flatten_deep_nested() {
2467        let runtime = setup_runtime();
2468        let data = json!([1, [2, [3, [4, [5]]]]]);
2469        let expr = runtime.compile("flatten_deep(@)").unwrap();
2470        let result = expr.search(&data).unwrap();
2471        let arr = result.as_array().unwrap();
2472        assert_eq!(arr.len(), 5);
2473        assert_eq!(arr[4].as_f64().unwrap() as i64, 5);
2474    }
2475
2476    #[test]
2477    fn test_flatten_deep_already_flat() {
2478        let runtime = setup_runtime();
2479        let data = json!([1, 2, 3]);
2480        let expr = runtime.compile("flatten_deep(@)").unwrap();
2481        let result = expr.search(&data).unwrap();
2482        let arr = result.as_array().unwrap();
2483        assert_eq!(arr.len(), 3);
2484    }
2485
2486    #[test]
2487    fn test_flatten_deep_mixed() {
2488        let runtime = setup_runtime();
2489        let data = json!([1, [2, 3], [[4]], [[[5, 6]]]]);
2490        let expr = runtime.compile("flatten_deep(@)").unwrap();
2491        let result = expr.search(&data).unwrap();
2492        let arr = result.as_array().unwrap();
2493        assert_eq!(arr.len(), 6);
2494    }
2495
2496    // =========================================================================
2497    // compact tests
2498    // =========================================================================
2499
2500    #[test]
2501    fn test_compact_basic() {
2502        let runtime = setup_runtime();
2503        let data = json!([1, null, 2, false, 3]);
2504        let expr = runtime.compile("compact(@)").unwrap();
2505        let result = expr.search(&data).unwrap();
2506        let arr = result.as_array().unwrap();
2507        assert_eq!(arr.len(), 3);
2508    }
2509
2510    #[test]
2511    fn test_compact_keeps_zero_and_empty_string() {
2512        let runtime = setup_runtime();
2513        let data = json!([0, "", null, true]);
2514        let expr = runtime.compile("compact(@)").unwrap();
2515        let result = expr.search(&data).unwrap();
2516        let arr = result.as_array().unwrap();
2517        assert_eq!(arr.len(), 3); // 0, "", true
2518    }
2519
2520    #[test]
2521    fn test_compact_all_falsy() {
2522        let runtime = setup_runtime();
2523        let data = json!([null, false, null]);
2524        let expr = runtime.compile("compact(@)").unwrap();
2525        let result = expr.search(&data).unwrap();
2526        let arr = result.as_array().unwrap();
2527        assert_eq!(arr.len(), 0);
2528    }
2529
2530    // =========================================================================
2531    // index_at tests
2532    // =========================================================================
2533
2534    #[test]
2535    fn test_index_at_positive() {
2536        let runtime = setup_runtime();
2537        let data = json!(["a", "b", "c", "d"]);
2538        let expr = runtime.compile("index_at(@, `2`)").unwrap();
2539        let result = expr.search(&data).unwrap();
2540        assert_eq!(result.as_str().unwrap(), "c");
2541    }
2542
2543    #[test]
2544    fn test_index_at_negative() {
2545        let runtime = setup_runtime();
2546        let data = json!(["a", "b", "c", "d"]);
2547        let expr = runtime.compile("index_at(@, `-1`)").unwrap();
2548        let result = expr.search(&data).unwrap();
2549        assert_eq!(result.as_str().unwrap(), "d");
2550    }
2551
2552    #[test]
2553    fn test_index_at_negative_second() {
2554        let runtime = setup_runtime();
2555        let data = json!(["a", "b", "c", "d"]);
2556        let expr = runtime.compile("index_at(@, `-2`)").unwrap();
2557        let result = expr.search(&data).unwrap();
2558        assert_eq!(result.as_str().unwrap(), "c");
2559    }
2560
2561    #[test]
2562    fn test_index_at_out_of_bounds() {
2563        let runtime = setup_runtime();
2564        let data = json!(["a", "b", "c"]);
2565        let expr = runtime.compile("index_at(@, `10`)").unwrap();
2566        let result = expr.search(&data).unwrap();
2567        assert!(result.is_null());
2568    }
2569
2570    // =========================================================================
2571    // includes tests
2572    // =========================================================================
2573
2574    #[test]
2575    fn test_includes_number() {
2576        let runtime = setup_runtime();
2577        let data = json!([1, 2, 3, 4, 5]);
2578        let expr = runtime.compile("includes(@, `3`)").unwrap();
2579        let result = expr.search(&data).unwrap();
2580        assert!(result.as_bool().unwrap());
2581    }
2582
2583    #[test]
2584    fn test_includes_not_found() {
2585        let runtime = setup_runtime();
2586        let data = json!([1, 2, 3]);
2587        let expr = runtime.compile("includes(@, `10`)").unwrap();
2588        let result = expr.search(&data).unwrap();
2589        assert!(!result.as_bool().unwrap());
2590    }
2591
2592    #[test]
2593    fn test_includes_string() {
2594        let runtime = setup_runtime();
2595        let data = json!(["apple", "banana", "cherry"]);
2596        let expr = runtime.compile(r#"includes(@, `"banana"`)"#).unwrap();
2597        let result = expr.search(&data).unwrap();
2598        assert!(result.as_bool().unwrap());
2599    }
2600
2601    #[test]
2602    fn test_includes_object() {
2603        let runtime = setup_runtime();
2604        let data = json!([{"a": 1}, {"b": 2}]);
2605        let expr = runtime.compile(r#"includes(@, `{"a": 1}`)"#).unwrap();
2606        let result = expr.search(&data).unwrap();
2607        assert!(result.as_bool().unwrap());
2608    }
2609
2610    // =========================================================================
2611    // find_index tests
2612    // =========================================================================
2613
2614    #[test]
2615    fn test_find_index_found() {
2616        let runtime = setup_runtime();
2617        let data = json!(["a", "b", "c", "d"]);
2618        let expr = runtime.compile(r#"find_index(@, `"c"`)"#).unwrap();
2619        let result = expr.search(&data).unwrap();
2620        assert_eq!(result.as_f64().unwrap() as i64, 2);
2621    }
2622
2623    #[test]
2624    fn test_find_index_not_found() {
2625        let runtime = setup_runtime();
2626        let data = json!(["a", "b", "c"]);
2627        let expr = runtime.compile(r#"find_index(@, `"z"`)"#).unwrap();
2628        let result = expr.search(&data).unwrap();
2629        assert_eq!(result.as_f64().unwrap() as i64, -1);
2630    }
2631
2632    // =========================================================================
2633    // group_by tests
2634    // =========================================================================
2635
2636    #[test]
2637    fn test_group_by_basic() {
2638        let runtime = setup_runtime();
2639        let data: serde_json::Value = serde_json::from_str(
2640            r#"[{"type": "a", "v": 1}, {"type": "b", "v": 2}, {"type": "a", "v": 3}]"#,
2641        )
2642        .unwrap();
2643        let expr = runtime.compile(r#"group_by(@, `"type"`)"#).unwrap();
2644        let result = expr.search(&data).unwrap();
2645        let obj = result.as_object().unwrap();
2646        assert_eq!(obj.get("a").unwrap().as_array().unwrap().len(), 2);
2647        assert_eq!(obj.get("b").unwrap().as_array().unwrap().len(), 1);
2648    }
2649
2650    // =========================================================================
2651    // index_by tests
2652    // =========================================================================
2653
2654    #[test]
2655    fn test_index_by_basic() {
2656        let runtime = setup_runtime();
2657        let data: serde_json::Value =
2658            serde_json::from_str(r#"[{"id": 1, "name": "alice"}, {"id": 2, "name": "bob"}]"#)
2659                .unwrap();
2660        let expr = runtime.compile(r#"index_by(@, `"id"`)"#).unwrap();
2661        let result = expr.search(&data).unwrap();
2662        let obj = result.as_object().unwrap();
2663        assert_eq!(obj.len(), 2);
2664        // Keys are string versions of the id
2665        let alice = obj.get("1").unwrap().as_object().unwrap();
2666        assert_eq!(alice.get("name").unwrap().as_str().unwrap(), "alice");
2667        let bob = obj.get("2").unwrap().as_object().unwrap();
2668        assert_eq!(bob.get("name").unwrap().as_str().unwrap(), "bob");
2669    }
2670
2671    #[test]
2672    fn test_index_by_string_key() {
2673        let runtime = setup_runtime();
2674        let data: serde_json::Value = serde_json::from_str(
2675            r#"[{"code": "US", "name": "United States"}, {"code": "UK", "name": "United Kingdom"}]"#,
2676        )
2677        .unwrap();
2678        let expr = runtime.compile(r#"index_by(@, `"code"`)"#).unwrap();
2679        let result = expr.search(&data).unwrap();
2680        let obj = result.as_object().unwrap();
2681        assert_eq!(obj.len(), 2);
2682        let us = obj.get("US").unwrap().as_object().unwrap();
2683        assert_eq!(us.get("name").unwrap().as_str().unwrap(), "United States");
2684    }
2685
2686    #[test]
2687    fn test_index_by_duplicate_keys() {
2688        // Last value wins for duplicate keys
2689        let runtime = setup_runtime();
2690        let data: serde_json::Value = serde_json::from_str(
2691            r#"[{"type": "a", "v": 1}, {"type": "a", "v": 2}, {"type": "a", "v": 3}]"#,
2692        )
2693        .unwrap();
2694        let expr = runtime.compile(r#"index_by(@, `"type"`)"#).unwrap();
2695        let result = expr.search(&data).unwrap();
2696        let obj = result.as_object().unwrap();
2697        assert_eq!(obj.len(), 1);
2698        // Last value (v=3) wins
2699        let a = obj.get("a").unwrap().as_object().unwrap();
2700        assert_eq!(a.get("v").unwrap().as_f64().unwrap() as i64, 3);
2701    }
2702
2703    #[test]
2704    fn test_index_by_missing_key() {
2705        // Items without the key field are skipped
2706        let runtime = setup_runtime();
2707        let data: serde_json::Value = serde_json::from_str(
2708            r#"[{"id": 1, "name": "alice"}, {"name": "bob"}, {"id": 3, "name": "charlie"}]"#,
2709        )
2710        .unwrap();
2711        let expr = runtime.compile(r#"index_by(@, `"id"`)"#).unwrap();
2712        let result = expr.search(&data).unwrap();
2713        let obj = result.as_object().unwrap();
2714        assert_eq!(obj.len(), 2);
2715        assert!(obj.contains_key("1"));
2716        assert!(obj.contains_key("3"));
2717        assert!(!obj.contains_key("2")); // bob was skipped
2718    }
2719
2720    #[test]
2721    fn test_index_by_empty_array() {
2722        let runtime = setup_runtime();
2723        let data = json!([]);
2724        let expr = runtime.compile(r#"index_by(@, `"id"`)"#).unwrap();
2725        let result = expr.search(&data).unwrap();
2726        let obj = result.as_object().unwrap();
2727        assert!(obj.is_empty());
2728    }
2729
2730    // =========================================================================
2731    // set operations tests
2732    // =========================================================================
2733
2734    #[test]
2735    fn test_difference() {
2736        let runtime = setup_runtime();
2737        let data: serde_json::Value =
2738            serde_json::from_str(r#"{"a": [1, 2, 3, 4], "b": [2, 4]}"#).unwrap();
2739        let expr = runtime.compile("difference(a, b)").unwrap();
2740        let result = expr.search(&data).unwrap();
2741        let arr = result.as_array().unwrap();
2742        assert_eq!(arr.len(), 2); // 1, 3
2743    }
2744
2745    #[test]
2746    fn test_intersection() {
2747        let runtime = setup_runtime();
2748        let data: serde_json::Value =
2749            serde_json::from_str(r#"{"a": [1, 2, 3], "b": [2, 3, 4]}"#).unwrap();
2750        let expr = runtime.compile("intersection(a, b)").unwrap();
2751        let result = expr.search(&data).unwrap();
2752        let arr = result.as_array().unwrap();
2753        assert_eq!(arr.len(), 2); // 2, 3
2754    }
2755
2756    #[test]
2757    fn test_union() {
2758        let runtime = setup_runtime();
2759        let data: serde_json::Value =
2760            serde_json::from_str(r#"{"a": [1, 2], "b": [2, 3]}"#).unwrap();
2761        let expr = runtime.compile("union(a, b)").unwrap();
2762        let result = expr.search(&data).unwrap();
2763        let arr = result.as_array().unwrap();
2764        assert_eq!(arr.len(), 3); // 1, 2, 3
2765    }
2766
2767    // =========================================================================
2768    // frequencies tests
2769    // =========================================================================
2770
2771    #[test]
2772    fn test_frequencies_basic() {
2773        let runtime = setup_runtime();
2774        let data = json!(["a", "b", "a", "c", "a", "b"]);
2775        let expr = runtime.compile("frequencies(@)").unwrap();
2776        let result = expr.search(&data).unwrap();
2777        let obj = result.as_object().unwrap();
2778        assert_eq!(obj.get("a").unwrap().as_f64().unwrap() as i64, 3);
2779        assert_eq!(obj.get("b").unwrap().as_f64().unwrap() as i64, 2);
2780        assert_eq!(obj.get("c").unwrap().as_f64().unwrap() as i64, 1);
2781    }
2782
2783    #[test]
2784    fn test_frequencies_numbers() {
2785        let runtime = setup_runtime();
2786        let data = json!([1, 2, 1, 1, 2, 3]);
2787        let expr = runtime.compile("frequencies(@)").unwrap();
2788        let result = expr.search(&data).unwrap();
2789        let obj = result.as_object().unwrap();
2790        assert_eq!(obj.get("1").unwrap().as_f64().unwrap() as i64, 3);
2791        assert_eq!(obj.get("2").unwrap().as_f64().unwrap() as i64, 2);
2792    }
2793
2794    // =========================================================================
2795    // mode tests
2796    // =========================================================================
2797
2798    #[test]
2799    fn test_mode_basic() {
2800        let runtime = setup_runtime();
2801        let data = json!([1, 2, 2, 3, 2, 4]);
2802        let expr = runtime.compile("mode(@)").unwrap();
2803        let result = expr.search(&data).unwrap();
2804        assert_eq!(result.as_f64().unwrap() as i64, 2);
2805    }
2806
2807    #[test]
2808    fn test_mode_empty() {
2809        let runtime = setup_runtime();
2810        let data = json!([]);
2811        let expr = runtime.compile("mode(@)").unwrap();
2812        let result = expr.search(&data).unwrap();
2813        assert!(result.is_null());
2814    }
2815
2816    // =========================================================================
2817    // cartesian tests
2818    // =========================================================================
2819
2820    #[test]
2821    fn test_cartesian_basic() {
2822        let runtime = setup_runtime();
2823        let data: serde_json::Value =
2824            serde_json::from_str(r#"{"a": [1, 2], "b": ["x", "y"]}"#).unwrap();
2825        let expr = runtime.compile("cartesian(a, b)").unwrap();
2826        let result = expr.search(&data).unwrap();
2827        let arr = result.as_array().unwrap();
2828        assert_eq!(arr.len(), 4); // [1,x], [1,y], [2,x], [2,y]
2829    }
2830
2831    #[test]
2832    fn test_cartesian_empty() {
2833        let runtime = setup_runtime();
2834        let data: serde_json::Value = serde_json::from_str(r#"{"a": [], "b": [1, 2]}"#).unwrap();
2835        let expr = runtime.compile("cartesian(a, b)").unwrap();
2836        let result = expr.search(&data).unwrap();
2837        let arr = result.as_array().unwrap();
2838        assert_eq!(arr.len(), 0);
2839    }
2840
2841    #[test]
2842    fn test_cartesian_n_way_two_arrays() {
2843        let runtime = setup_runtime();
2844        let data = json!([[1, 2], ["a", "b"]]);
2845        let expr = runtime.compile("cartesian(@)").unwrap();
2846        let result = expr.search(&data).unwrap();
2847        let arr = result.as_array().unwrap();
2848        assert_eq!(arr.len(), 4); // [1,a], [1,b], [2,a], [2,b]
2849    }
2850
2851    #[test]
2852    fn test_cartesian_n_way_three_arrays() {
2853        let runtime = setup_runtime();
2854        let data = json!([[1, 2], ["a", "b"], [true, false]]);
2855        let expr = runtime.compile("cartesian(@)").unwrap();
2856        let result = expr.search(&data).unwrap();
2857        let arr = result.as_array().unwrap();
2858        assert_eq!(arr.len(), 8); // 2 * 2 * 2 = 8 combinations
2859    }
2860
2861    #[test]
2862    fn test_cartesian_n_way_single_array() {
2863        let runtime = setup_runtime();
2864        let data = json!([[1, 2, 3]]);
2865        let expr = runtime.compile("cartesian(@)").unwrap();
2866        let result = expr.search(&data).unwrap();
2867        let arr = result.as_array().unwrap();
2868        assert_eq!(arr.len(), 3); // [1], [2], [3]
2869    }
2870
2871    #[test]
2872    fn test_cartesian_n_way_empty() {
2873        let runtime = setup_runtime();
2874        let data = json!([]);
2875        let expr = runtime.compile("cartesian(@)").unwrap();
2876        let result = expr.search(&data).unwrap();
2877        let arr = result.as_array().unwrap();
2878        assert_eq!(arr.len(), 0);
2879    }
2880
2881    // =========================================================================
2882    // Edge cases
2883    // =========================================================================
2884
2885    #[test]
2886    fn test_first_empty_array() {
2887        let runtime = setup_runtime();
2888        let data = json!([]);
2889        let expr = runtime.compile("first(@)").unwrap();
2890        let result = expr.search(&data).unwrap();
2891        assert!(result.is_null());
2892    }
2893
2894    #[test]
2895    fn test_last_empty_array() {
2896        let runtime = setup_runtime();
2897        let data = json!([]);
2898        let expr = runtime.compile("last(@)").unwrap();
2899        let result = expr.search(&data).unwrap();
2900        assert!(result.is_null());
2901    }
2902
2903    #[test]
2904    fn test_unique_preserves_order() {
2905        let runtime = setup_runtime();
2906        let data = json!(["c", "a", "b", "a", "c"]);
2907        let expr = runtime.compile("unique(@)").unwrap();
2908        let result = expr.search(&data).unwrap();
2909        let arr = result.as_array().unwrap();
2910        assert_eq!(arr.len(), 3);
2911        assert_eq!(arr[0].as_str().unwrap(), "c");
2912        assert_eq!(arr[1].as_str().unwrap(), "a");
2913        assert_eq!(arr[2].as_str().unwrap(), "b");
2914    }
2915
2916    #[test]
2917    fn test_unique_different_types() {
2918        let runtime = setup_runtime();
2919        let data = json!([1, "1", 1, "1"]);
2920        let expr = runtime.compile("unique(@)").unwrap();
2921        let result = expr.search(&data).unwrap();
2922        let arr = result.as_array().unwrap();
2923        assert_eq!(arr.len(), 2); // 1 and "1" are different
2924    }
2925
2926    #[test]
2927    fn test_range_with_step() {
2928        let runtime = setup_runtime();
2929        let data = json!(null);
2930        let expr = runtime.compile("range(`1`, `10`, `2`)").unwrap();
2931        let result = expr.search(&data).unwrap();
2932        let arr = result.as_array().unwrap();
2933        assert_eq!(arr.len(), 5); // 1, 3, 5, 7, 9
2934        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
2935        assert_eq!(arr[4].as_f64().unwrap() as i64, 9);
2936    }
2937
2938    #[test]
2939    fn test_range_descending() {
2940        let runtime = setup_runtime();
2941        let data = json!(null);
2942        let expr = runtime.compile("range(`5`, `0`, `-1`)").unwrap();
2943        let result = expr.search(&data).unwrap();
2944        let arr = result.as_array().unwrap();
2945        assert_eq!(arr.len(), 5); // 5, 4, 3, 2, 1
2946        assert_eq!(arr[0].as_f64().unwrap() as i64, 5);
2947        assert_eq!(arr[4].as_f64().unwrap() as i64, 1);
2948    }
2949
2950    // =========================================================================
2951    // Pipeline patterns with arrays
2952    // =========================================================================
2953
2954    #[test]
2955    fn test_pipeline_unique_sort() {
2956        let runtime = setup_runtime();
2957        let data = json!(["redis", "database", "redis", "nosql", "database"]);
2958        let expr = runtime.compile("unique(@) | sort(@)").unwrap();
2959        let result = expr.search(&data).unwrap();
2960        let arr = result.as_array().unwrap();
2961        assert_eq!(arr.len(), 3);
2962        assert_eq!(arr[0].as_str().unwrap(), "database");
2963        assert_eq!(arr[1].as_str().unwrap(), "nosql");
2964        assert_eq!(arr[2].as_str().unwrap(), "redis");
2965    }
2966
2967    #[test]
2968    fn test_pipeline_filter_take() {
2969        let runtime = setup_runtime();
2970        let data = json!([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
2971        let expr = runtime.compile("[?@ > `3`] | take(@, `3`)").unwrap();
2972        let result = expr.search(&data).unwrap();
2973        let arr = result.as_array().unwrap();
2974        assert_eq!(arr.len(), 3);
2975        assert_eq!(arr[0].as_f64().unwrap() as i64, 4);
2976        assert_eq!(arr[1].as_f64().unwrap() as i64, 5);
2977        assert_eq!(arr[2].as_f64().unwrap() as i64, 6);
2978    }
2979
2980    #[test]
2981    fn test_pipeline_flatten_unique() {
2982        let runtime = setup_runtime();
2983        let data = json!([[1, 2], [2, 3], [3, 4]]);
2984        let expr = runtime.compile("flatten_deep(@) | unique(@)").unwrap();
2985        let result = expr.search(&data).unwrap();
2986        let arr = result.as_array().unwrap();
2987        assert_eq!(arr.len(), 4); // 1, 2, 3, 4
2988    }
2989
2990    #[test]
2991    fn test_large_array_processing() {
2992        let runtime = setup_runtime();
2993        // Create array with 1000 elements
2994        let items: Vec<i32> = (1..=1000).collect();
2995        let json_str = serde_json::to_string(&items).unwrap();
2996        let data: serde_json::Value = serde_json::from_str(&json_str).unwrap();
2997
2998        let expr = runtime.compile("length(@)").unwrap();
2999        let result = expr.search(&data).unwrap();
3000        assert_eq!(result.as_f64().unwrap() as i64, 1000);
3001    }
3002
3003    #[test]
3004    fn test_transpose_basic() {
3005        let runtime = setup_runtime();
3006        let data = json!([[1, 2, 3], [4, 5, 6]]);
3007        let expr = runtime.compile("transpose(@)").unwrap();
3008        let result = expr.search(&data).unwrap();
3009        let arr = result.as_array().unwrap();
3010        assert_eq!(arr.len(), 3);
3011        // First column: [1, 4]
3012        let col0 = arr[0].as_array().unwrap();
3013        assert_eq!(col0[0].as_f64().unwrap() as i64, 1);
3014        assert_eq!(col0[1].as_f64().unwrap() as i64, 4);
3015        // Second column: [2, 5]
3016        let col1 = arr[1].as_array().unwrap();
3017        assert_eq!(col1[0].as_f64().unwrap() as i64, 2);
3018        assert_eq!(col1[1].as_f64().unwrap() as i64, 5);
3019    }
3020
3021    #[test]
3022    fn test_transpose_empty() {
3023        let runtime = setup_runtime();
3024        let data = json!([]);
3025        let expr = runtime.compile("transpose(@)").unwrap();
3026        let result = expr.search(&data).unwrap();
3027        let arr = result.as_array().unwrap();
3028        assert_eq!(arr.len(), 0);
3029    }
3030
3031    #[test]
3032    fn test_transpose_unequal_rows() {
3033        let runtime = setup_runtime();
3034        let data = json!([[1, 2], [3, 4, 5], [6, 7]]);
3035        let expr = runtime.compile("transpose(@)").unwrap();
3036        let result = expr.search(&data).unwrap();
3037        let arr = result.as_array().unwrap();
3038        // Should use minimum length (2)
3039        assert_eq!(arr.len(), 2);
3040    }
3041
3042    #[test]
3043    fn test_pairwise_basic() {
3044        let runtime = setup_runtime();
3045        let data = json!([1, 2, 3, 4]);
3046        let expr = runtime.compile("pairwise(@)").unwrap();
3047        let result = expr.search(&data).unwrap();
3048        let arr = result.as_array().unwrap();
3049        assert_eq!(arr.len(), 3);
3050        // First pair: [1, 2]
3051        let pair0 = arr[0].as_array().unwrap();
3052        assert_eq!(pair0[0].as_f64().unwrap() as i64, 1);
3053        assert_eq!(pair0[1].as_f64().unwrap() as i64, 2);
3054        // Second pair: [2, 3]
3055        let pair1 = arr[1].as_array().unwrap();
3056        assert_eq!(pair1[0].as_f64().unwrap() as i64, 2);
3057        assert_eq!(pair1[1].as_f64().unwrap() as i64, 3);
3058    }
3059
3060    #[test]
3061    fn test_pairwise_short_array() {
3062        let runtime = setup_runtime();
3063        let data = json!([1]);
3064        let expr = runtime.compile("pairwise(@)").unwrap();
3065        let result = expr.search(&data).unwrap();
3066        let arr = result.as_array().unwrap();
3067        assert_eq!(arr.len(), 0);
3068    }
3069
3070    #[test]
3071    fn test_sliding_window_alias() {
3072        let runtime = setup_runtime();
3073        let data = json!([1, 2, 3, 4, 5]);
3074        let expr = runtime.compile("sliding_window(@, `3`)").unwrap();
3075        let result = expr.search(&data).unwrap();
3076        let arr = result.as_array().unwrap();
3077        assert_eq!(arr.len(), 3);
3078        // First window: [1, 2, 3]
3079        let win0 = arr[0].as_array().unwrap();
3080        assert_eq!(win0.len(), 3);
3081        assert_eq!(win0[0].as_f64().unwrap() as i64, 1);
3082    }
3083
3084    // indices_array tests
3085    #[test]
3086    fn test_indices_array_found() {
3087        let runtime = setup_runtime();
3088        let data = json!([1, 2, 3, 2, 4, 2]);
3089        let expr = runtime.compile("indices_array(@, `2`)").unwrap();
3090        let result = expr.search(&data).unwrap();
3091        let arr = result.as_array().unwrap();
3092        assert_eq!(arr.len(), 3);
3093        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
3094        assert_eq!(arr[1].as_f64().unwrap() as i64, 3);
3095        assert_eq!(arr[2].as_f64().unwrap() as i64, 5);
3096    }
3097
3098    #[test]
3099    fn test_indices_array_not_found() {
3100        let runtime = setup_runtime();
3101        let data = json!([1, 2, 3]);
3102        let expr = runtime.compile("indices_array(@, `5`)").unwrap();
3103        let result = expr.search(&data).unwrap();
3104        let arr = result.as_array().unwrap();
3105        assert_eq!(arr.len(), 0);
3106    }
3107
3108    #[test]
3109    fn test_indices_array_strings() {
3110        let runtime = setup_runtime();
3111        let data = json!(["a", "b", "a", "c", "a"]);
3112        let expr = runtime.compile(r#"indices_array(@, `"a"`)"#).unwrap();
3113        let result = expr.search(&data).unwrap();
3114        let arr = result.as_array().unwrap();
3115        assert_eq!(arr.len(), 3);
3116        assert_eq!(arr[0].as_f64().unwrap() as i64, 0);
3117        assert_eq!(arr[1].as_f64().unwrap() as i64, 2);
3118        assert_eq!(arr[2].as_f64().unwrap() as i64, 4);
3119    }
3120
3121    // inside_array tests
3122    #[test]
3123    fn test_inside_array_true() {
3124        let runtime = setup_runtime();
3125        let data: serde_json::Value =
3126            serde_json::from_str(r#"{"a": [1, 2], "b": [1, 2, 3, 4]}"#).unwrap();
3127        let expr = runtime.compile("inside_array(a, b)").unwrap();
3128        let result = expr.search(&data).unwrap();
3129        assert!(result.as_bool().unwrap());
3130    }
3131
3132    #[test]
3133    fn test_inside_array_false() {
3134        let runtime = setup_runtime();
3135        let data: serde_json::Value =
3136            serde_json::from_str(r#"{"a": [1, 5], "b": [1, 2, 3, 4]}"#).unwrap();
3137        let expr = runtime.compile("inside_array(a, b)").unwrap();
3138        let result = expr.search(&data).unwrap();
3139        assert!(!result.as_bool().unwrap());
3140    }
3141
3142    #[test]
3143    fn test_inside_array_empty() {
3144        let runtime = setup_runtime();
3145        let data: serde_json::Value = serde_json::from_str(r#"{"a": [], "b": [1, 2, 3]}"#).unwrap();
3146        let expr = runtime.compile("inside_array(a, b)").unwrap();
3147        let result = expr.search(&data).unwrap();
3148        assert!(result.as_bool().unwrap());
3149    }
3150
3151    // bsearch tests
3152    #[test]
3153    fn test_bsearch_found() {
3154        let runtime = setup_runtime();
3155        let data = json!([1, 3, 5, 7, 9]);
3156        let expr = runtime.compile("bsearch(@, `5`)").unwrap();
3157        let result = expr.search(&data).unwrap();
3158        assert_eq!(result.as_f64().unwrap() as i64, 2);
3159    }
3160
3161    #[test]
3162    fn test_bsearch_not_found_middle() {
3163        let runtime = setup_runtime();
3164        let data = json!([1, 3, 5, 7, 9]);
3165        let expr = runtime.compile("bsearch(@, `4`)").unwrap();
3166        let result = expr.search(&data).unwrap();
3167        assert_eq!(result.as_f64().unwrap() as i64, -3);
3168    }
3169
3170    #[test]
3171    fn test_bsearch_not_found_start() {
3172        let runtime = setup_runtime();
3173        let data = json!([1, 3, 5, 7, 9]);
3174        let expr = runtime.compile("bsearch(@, `0`)").unwrap();
3175        let result = expr.search(&data).unwrap();
3176        assert_eq!(result.as_f64().unwrap() as i64, -1);
3177    }
3178
3179    #[test]
3180    fn test_bsearch_not_found_end() {
3181        let runtime = setup_runtime();
3182        let data = json!([1, 3, 5, 7, 9]);
3183        let expr = runtime.compile("bsearch(@, `10`)").unwrap();
3184        let result = expr.search(&data).unwrap();
3185        assert_eq!(result.as_f64().unwrap() as i64, -6);
3186    }
3187
3188    #[test]
3189    fn test_bsearch_empty_array() {
3190        let runtime = setup_runtime();
3191        let data = json!([]);
3192        let expr = runtime.compile("bsearch(@, `5`)").unwrap();
3193        let result = expr.search(&data).unwrap();
3194        assert_eq!(result.as_f64().unwrap() as i64, -1);
3195    }
3196
3197    // repeat_array tests
3198    #[test]
3199    fn test_repeat_array_basic() {
3200        let runtime = setup_runtime();
3201        let data = json!(null);
3202        let expr = runtime.compile("repeat_array(`1`, `3`)").unwrap();
3203        let result = expr.search(&data).unwrap();
3204        let arr = result.as_array().unwrap();
3205        assert_eq!(arr.len(), 3);
3206        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
3207        assert_eq!(arr[1].as_f64().unwrap() as i64, 1);
3208        assert_eq!(arr[2].as_f64().unwrap() as i64, 1);
3209    }
3210
3211    #[test]
3212    fn test_repeat_array_string() {
3213        let runtime = setup_runtime();
3214        let data = json!(null);
3215        let expr = runtime.compile(r#"repeat_array(`"x"`, `4`)"#).unwrap();
3216        let result = expr.search(&data).unwrap();
3217        let arr = result.as_array().unwrap();
3218        assert_eq!(arr.len(), 4);
3219        assert_eq!(arr[0].as_str().unwrap(), "x");
3220        assert_eq!(arr[3].as_str().unwrap(), "x");
3221    }
3222
3223    #[test]
3224    fn test_repeat_array_zero() {
3225        let runtime = setup_runtime();
3226        let data = json!(null);
3227        let expr = runtime.compile("repeat_array(`1`, `0`)").unwrap();
3228        let result = expr.search(&data).unwrap();
3229        let arr = result.as_array().unwrap();
3230        assert_eq!(arr.len(), 0);
3231    }
3232
3233    #[test]
3234    fn test_repeat_array_object() {
3235        let runtime = setup_runtime();
3236        let data = json!(null);
3237        let expr = runtime.compile(r#"repeat_array(`{"a": 1}`, `2`)"#).unwrap();
3238        let result = expr.search(&data).unwrap();
3239        let arr = result.as_array().unwrap();
3240        assert_eq!(arr.len(), 2);
3241        assert_eq!(
3242            arr[0]
3243                .as_object()
3244                .unwrap()
3245                .get("a")
3246                .unwrap()
3247                .as_f64()
3248                .unwrap() as i64,
3249            1
3250        );
3251    }
3252
3253    // cycle tests
3254    #[test]
3255    fn test_cycle_basic() {
3256        let runtime = setup_runtime();
3257        let data = json!([1, 2, 3]);
3258        let expr = runtime.compile("cycle(@, `2`)").unwrap();
3259        let result = expr.search(&data).unwrap();
3260        let arr = result.as_array().unwrap();
3261        assert_eq!(arr.len(), 6);
3262        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
3263        assert_eq!(arr[1].as_f64().unwrap() as i64, 2);
3264        assert_eq!(arr[2].as_f64().unwrap() as i64, 3);
3265        assert_eq!(arr[3].as_f64().unwrap() as i64, 1);
3266        assert_eq!(arr[4].as_f64().unwrap() as i64, 2);
3267        assert_eq!(arr[5].as_f64().unwrap() as i64, 3);
3268    }
3269
3270    #[test]
3271    fn test_cycle_strings() {
3272        let runtime = setup_runtime();
3273        let data = json!(["a", "b"]);
3274        let expr = runtime.compile("cycle(@, `3`)").unwrap();
3275        let result = expr.search(&data).unwrap();
3276        let arr = result.as_array().unwrap();
3277        assert_eq!(arr.len(), 6);
3278        assert_eq!(arr[0].as_str().unwrap(), "a");
3279        assert_eq!(arr[1].as_str().unwrap(), "b");
3280        assert_eq!(arr[2].as_str().unwrap(), "a");
3281    }
3282
3283    #[test]
3284    fn test_cycle_zero() {
3285        let runtime = setup_runtime();
3286        let data = json!([1, 2, 3]);
3287        let expr = runtime.compile("cycle(@, `0`)").unwrap();
3288        let result = expr.search(&data).unwrap();
3289        let arr = result.as_array().unwrap();
3290        assert_eq!(arr.len(), 0);
3291    }
3292
3293    #[test]
3294    fn test_cycle_empty_array() {
3295        let runtime = setup_runtime();
3296        let data = json!([]);
3297        let expr = runtime.compile("cycle(@, `5`)").unwrap();
3298        let result = expr.search(&data).unwrap();
3299        let arr = result.as_array().unwrap();
3300        assert_eq!(arr.len(), 0);
3301    }
3302
3303    #[test]
3304    fn test_cycle_once() {
3305        let runtime = setup_runtime();
3306        let data = json!([1, 2]);
3307        let expr = runtime.compile("cycle(@, `1`)").unwrap();
3308        let result = expr.search(&data).unwrap();
3309        let arr = result.as_array().unwrap();
3310        assert_eq!(arr.len(), 2);
3311        assert_eq!(arr[0].as_f64().unwrap() as i64, 1);
3312        assert_eq!(arr[1].as_f64().unwrap() as i64, 2);
3313    }
3314
3315    #[test]
3316    fn test_lag_by_one() {
3317        let runtime = setup_runtime();
3318        let data = json!([1, 2, 3]);
3319        let expr = runtime.compile("lag(@, `1`)").unwrap();
3320        let result = expr.search(&data).unwrap();
3321        assert_eq!(result, json!([null, 1, 2]));
3322    }
3323
3324    #[test]
3325    fn test_lag_by_two() {
3326        let runtime = setup_runtime();
3327        let data = json!([1, 2, 3]);
3328        let expr = runtime.compile("lag(@, `2`)").unwrap();
3329        let result = expr.search(&data).unwrap();
3330        assert_eq!(result, json!([null, null, 1]));
3331    }
3332
3333    #[test]
3334    fn test_lag_by_zero() {
3335        let runtime = setup_runtime();
3336        let data = json!([1, 2, 3]);
3337        let expr = runtime.compile("lag(@, `0`)").unwrap();
3338        let result = expr.search(&data).unwrap();
3339        assert_eq!(result, json!([1, 2, 3]));
3340    }
3341
3342    #[test]
3343    fn test_lag_exceeds_length() {
3344        let runtime = setup_runtime();
3345        let data = json!([1, 2, 3]);
3346        let expr = runtime.compile("lag(@, `5`)").unwrap();
3347        let result = expr.search(&data).unwrap();
3348        assert_eq!(result, json!([null, null, null]));
3349    }
3350
3351    #[test]
3352    fn test_lag_empty_array() {
3353        let runtime = setup_runtime();
3354        let data = json!([]);
3355        let expr = runtime.compile("lag(@, `1`)").unwrap();
3356        let result = expr.search(&data).unwrap();
3357        assert_eq!(result, json!([]));
3358    }
3359
3360    #[test]
3361    fn test_lead_by_one() {
3362        let runtime = setup_runtime();
3363        let data = json!([1, 2, 3]);
3364        let expr = runtime.compile("lead(@, `1`)").unwrap();
3365        let result = expr.search(&data).unwrap();
3366        assert_eq!(result, json!([2, 3, null]));
3367    }
3368
3369    #[test]
3370    fn test_lead_by_two() {
3371        let runtime = setup_runtime();
3372        let data = json!([1, 2, 3]);
3373        let expr = runtime.compile("lead(@, `2`)").unwrap();
3374        let result = expr.search(&data).unwrap();
3375        assert_eq!(result, json!([3, null, null]));
3376    }
3377
3378    #[test]
3379    fn test_lead_by_zero() {
3380        let runtime = setup_runtime();
3381        let data = json!([1, 2, 3]);
3382        let expr = runtime.compile("lead(@, `0`)").unwrap();
3383        let result = expr.search(&data).unwrap();
3384        assert_eq!(result, json!([1, 2, 3]));
3385    }
3386
3387    #[test]
3388    fn test_lead_exceeds_length() {
3389        let runtime = setup_runtime();
3390        let data = json!([1, 2, 3]);
3391        let expr = runtime.compile("lead(@, `5`)").unwrap();
3392        let result = expr.search(&data).unwrap();
3393        assert_eq!(result, json!([null, null, null]));
3394    }
3395
3396    #[test]
3397    fn test_lead_empty_array() {
3398        let runtime = setup_runtime();
3399        let data = json!([]);
3400        let expr = runtime.compile("lead(@, `1`)").unwrap();
3401        let result = expr.search(&data).unwrap();
3402        assert_eq!(result, json!([]));
3403    }
3404}