use rayon::prelude::*;
use simd_json::OwnedValue as Value;
use simd_json::StaticNode;
use super::{json_cmp, type_error};
use crate::error::EvalError;
use crate::utils::type_name;
const PARALLEL_THRESHOLD: usize = 10_000;
pub fn eval_first(value: &Value) -> Result<Value, EvalError> {
match value {
Value::Array(arr) => Ok(arr
.first()
.cloned()
.unwrap_or(Value::Static(StaticNode::Null))),
_ => Err(type_error(format!(
"cannot index {} with number",
type_name(value)
))),
}
}
pub fn eval_last(value: &Value) -> Result<Value, EvalError> {
match value {
Value::Array(arr) => Ok(arr
.last()
.cloned()
.unwrap_or(Value::Static(StaticNode::Null))),
_ => Err(type_error(format!(
"cannot index {} with number",
type_name(value)
))),
}
}
pub fn eval_reverse(value: &Value) -> Result<Value, EvalError> {
match value {
Value::Array(arr) => {
let reversed: Vec<Value> = arr.iter().rev().cloned().collect();
Ok(Value::Array(Box::new(reversed)))
}
_ => Err(type_error(format!(
"{} cannot be reversed, as it is not an array",
type_name(value)
))),
}
}
pub fn eval_sort(value: &Value) -> Result<Value, EvalError> {
match value {
Value::Array(arr) if arr.len() >= PARALLEL_THRESHOLD => {
let mut sorted: Vec<Value> = arr.to_vec();
sorted.par_sort_by(json_cmp);
Ok(Value::Array(Box::new(sorted)))
}
Value::Array(arr) => {
let mut sorted: Vec<Value> = arr.to_vec();
sorted.sort_by(json_cmp);
Ok(Value::Array(Box::new(sorted)))
}
_ => Err(type_error(format!(
"{} cannot be sorted, as it is not an array",
type_name(value)
))),
}
}
pub fn eval_unique(value: &Value) -> Result<Value, EvalError> {
match value {
Value::Array(arr) => {
let mut seen = Vec::new();
for v in arr.iter() {
if !seen.contains(v) {
seen.push(v.clone());
}
}
Ok(Value::Array(Box::new(seen)))
}
_ => Err(type_error(format!(
"{} cannot have unique elements taken, as it is not an array",
type_name(value)
))),
}
}
pub fn eval_flatten(value: &Value) -> Result<Value, EvalError> {
match value {
Value::Array(arr) => {
let mut flat = Vec::new();
for v in arr.iter() {
match v {
Value::Array(inner) => flat.extend(inner.iter().cloned()),
other => flat.push(other.clone()),
}
}
Ok(Value::Array(Box::new(flat)))
}
_ => Err(type_error(format!(
"{} cannot be flattened, as it is not an array",
type_name(value)
))),
}
}
#[cfg(test)]
mod tests {
use crate::filter::builtins::{Builtin, eval};
use simd_json::json;
#[test]
fn test_first() {
assert_eq!(
eval(&Builtin::First, &json!([1, 2, 3])).unwrap(),
vec![json!(1)]
);
}
#[test]
fn test_first_empty() {
assert_eq!(
eval(&Builtin::First, &json!([])).unwrap(),
vec![json!(null)]
);
}
#[test]
fn test_last() {
assert_eq!(
eval(&Builtin::Last, &json!([1, 2, 3])).unwrap(),
vec![json!(3)]
);
}
#[test]
fn test_last_empty() {
assert_eq!(eval(&Builtin::Last, &json!([])).unwrap(), vec![json!(null)]);
}
#[test]
fn test_reverse() {
assert_eq!(
eval(&Builtin::Reverse, &json!([1, 2, 3])).unwrap(),
vec![json!([3, 2, 1])]
);
}
#[test]
fn test_reverse_empty() {
assert_eq!(
eval(&Builtin::Reverse, &json!([])).unwrap(),
vec![json!([])]
);
}
#[test]
fn test_sort_numbers() {
assert_eq!(
eval(&Builtin::Sort, &json!([3, 1, 2])).unwrap(),
vec![json!([1, 2, 3])]
);
}
#[test]
fn test_sort_strings() {
assert_eq!(
eval(&Builtin::Sort, &json!(["banana", "apple", "cherry"])).unwrap(),
vec![json!(["apple", "banana", "cherry"])]
);
}
#[test]
fn test_sort_mixed() {
assert_eq!(
eval(&Builtin::Sort, &json!([1, null, "a", false, true])).unwrap(),
vec![json!([null, false, true, 1, "a"])]
);
}
#[test]
fn test_sort_objects() {
assert_eq!(
eval(&Builtin::Sort, &json!([{"a": 2}, {"a": 1}])).unwrap(),
vec![json!([{"a": 1}, {"a": 2}])]
);
}
#[test]
fn test_sort_objects_different_keys() {
assert_eq!(
eval(&Builtin::Sort, &json!([{"b": 1}, {"a": 1}])).unwrap(),
vec![json!([{"a": 1}, {"b": 1}])]
);
assert_eq!(
eval(&Builtin::Sort, &json!([{"a": 1, "b": 2}, {"a": 1}])).unwrap(),
vec![json!([{"a": 1}, {"a": 1, "b": 2}])]
);
}
#[test]
fn test_unique() {
assert_eq!(
eval(&Builtin::Unique, &json!([1, 2, 1, 3, 2, 1])).unwrap(),
vec![json!([1, 2, 3])]
);
}
#[test]
fn test_unique_preserves_order() {
assert_eq!(
eval(&Builtin::Unique, &json!([3, 1, 2, 1, 3])).unwrap(),
vec![json!([3, 1, 2])]
);
}
#[test]
fn test_flatten() {
assert_eq!(
eval(&Builtin::Flatten, &json!([[1, 2], [3, 4]])).unwrap(),
vec![json!([1, 2, 3, 4])]
);
}
#[test]
fn test_flatten_mixed() {
assert_eq!(
eval(&Builtin::Flatten, &json!([[1, 2], 3, [4]])).unwrap(),
vec![json!([1, 2, 3, 4])]
);
}
#[test]
fn test_flatten_one_level() {
assert_eq!(
eval(&Builtin::Flatten, &json!([[[1]], [2]])).unwrap(),
vec![json!([[1], 2])]
);
}
#[test]
fn test_sort_non_array_errors() {
assert!(eval(&Builtin::Sort, &json!("hello")).is_err());
assert!(eval(&Builtin::Sort, &json!(42)).is_err());
assert!(eval(&Builtin::Sort, &json!({"a": 1})).is_err());
}
#[test]
fn test_first_non_array_errors() {
assert!(eval(&Builtin::First, &json!("hello")).is_err());
assert!(eval(&Builtin::First, &json!({"a": 1})).is_err());
}
#[test]
fn test_reverse_non_array_errors() {
assert!(eval(&Builtin::Reverse, &json!("hello")).is_err());
}
#[test]
fn test_unique_non_array_errors() {
assert!(eval(&Builtin::Unique, &json!("hello")).is_err());
}
#[test]
fn test_flatten_non_array_errors() {
assert!(eval(&Builtin::Flatten, &json!("hello")).is_err());
}
}