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