use simd_json::OwnedValue as Value;
use simd_json::StaticNode;
use simd_json::prelude::*;
use super::{type_error, type_name};
use crate::error::EvalError;
pub fn eval_keys(value: &Value) -> Result<Value, EvalError> {
match value {
Value::Object(obj) => {
let mut keys: Vec<&String> = obj.keys().collect();
keys.sort(); let keys: Vec<Value> = keys.into_iter().map(|k| Value::String(k.clone())).collect();
Ok(Value::Array(Box::new(keys)))
}
Value::Array(arr) => {
let indices: Vec<Value> = (0..arr.len())
.map(|i| Value::Static(StaticNode::U64(i as u64)))
.collect();
Ok(Value::Array(Box::new(indices)))
}
_ => Err(type_error(format!("{} has no keys", type_name(value)))),
}
}
pub fn eval_values(value: &Value) -> Result<Value, EvalError> {
match value {
Value::Object(obj) => {
let vals: Vec<Value> = obj.values().cloned().collect();
Ok(Value::Array(Box::new(vals)))
}
Value::Array(arr) => Ok(Value::Array(arr.clone())),
_ => Err(type_error(format!("{} has no values", type_name(value)))),
}
}
pub fn eval_to_entries(value: &Value) -> Result<Value, EvalError> {
match value {
Value::Object(obj) => {
let mut entries: Vec<Value> = obj
.iter()
.map(|(k, v)| {
let mut entry = simd_json::owned::Object::new();
entry.insert("key".to_string(), Value::String(k.clone()));
entry.insert("value".to_string(), v.clone());
Value::Object(Box::new(entry))
})
.collect();
entries.sort_by(|a, b| {
let ka = a.get("key").and_then(|k| k.as_str()).unwrap_or("");
let kb = b.get("key").and_then(|k| k.as_str()).unwrap_or("");
ka.cmp(kb)
});
Ok(Value::Array(Box::new(entries)))
}
_ => Err(type_error(format!("{} has no keys", type_name(value)))),
}
}
pub fn eval_from_entries(value: &Value) -> Result<Value, EvalError> {
match value {
Value::Array(arr) => {
let mut obj = simd_json::owned::Object::new();
for entry in arr.iter() {
let key = entry
.get("key")
.or_else(|| entry.get("k"))
.or_else(|| entry.get("name"))
.and_then(|k| k.as_str())
.ok_or_else(|| type_error("Cannot use null as object key".to_string()))?;
let val = entry
.get("value")
.or_else(|| entry.get("v"))
.cloned()
.unwrap_or(Value::Static(StaticNode::Null));
obj.insert(key.to_string(), val);
}
Ok(Value::Object(Box::new(obj)))
}
_ => Err(type_error(format!(
"{} cannot be converted to object",
type_name(value)
))),
}
}
#[cfg(test)]
mod tests {
use crate::filter::builtins::{Builtin, eval};
use simd_json::json;
use simd_json::prelude::*;
#[test]
fn test_keys_object() {
let result = eval(&Builtin::Keys, &json!({"b": 1, "a": 2, "c": 3})).unwrap();
assert_eq!(result, vec![json!(["a", "b", "c"])]); }
#[test]
fn test_keys_array() {
assert_eq!(
eval(&Builtin::Keys, &json!([10, 20, 30])).unwrap(),
vec![json!([0, 1, 2])]
);
}
#[test]
fn test_keys_empty() {
assert_eq!(eval(&Builtin::Keys, &json!({})).unwrap(), vec![json!([])]);
assert_eq!(eval(&Builtin::Keys, &json!([])).unwrap(), vec![json!([])]);
}
#[test]
fn test_values_object() {
let result = eval(&Builtin::Values, &json!({"a": 1, "b": 2})).unwrap();
assert_eq!(result.len(), 1);
let arr = result[0].as_array().unwrap();
assert!(arr.contains(&json!(1)));
assert!(arr.contains(&json!(2)));
}
#[test]
fn test_values_array() {
assert_eq!(
eval(&Builtin::Values, &json!([1, 2, 3])).unwrap(),
vec![json!([1, 2, 3])]
);
}
#[test]
fn test_keys_non_container_errors() {
assert!(eval(&Builtin::Keys, &json!("hello")).is_err());
assert!(eval(&Builtin::Keys, &json!(42)).is_err());
assert!(eval(&Builtin::Keys, &json!(null)).is_err());
}
#[test]
fn test_to_entries_basic() {
let result = eval(&Builtin::ToEntries, &json!({"a": 1, "b": 2})).unwrap();
assert_eq!(result.len(), 1);
let arr = result[0].as_array().unwrap();
assert_eq!(arr.len(), 2);
assert_eq!(arr[0], json!({"key": "a", "value": 1}));
assert_eq!(arr[1], json!({"key": "b", "value": 2}));
}
#[test]
fn test_to_entries_empty() {
assert_eq!(
eval(&Builtin::ToEntries, &json!({})).unwrap(),
vec![json!([])]
);
}
#[test]
fn test_to_entries_non_object_errors() {
assert!(eval(&Builtin::ToEntries, &json!([1, 2])).is_err());
assert!(eval(&Builtin::ToEntries, &json!("string")).is_err());
}
#[test]
fn test_from_entries_basic() {
let result = eval(
&Builtin::FromEntries,
&json!([{"key": "a", "value": 1}, {"key": "b", "value": 2}]),
)
.unwrap();
assert_eq!(result, vec![json!({"a": 1, "b": 2})]);
}
#[test]
fn test_from_entries_name_key() {
let result = eval(&Builtin::FromEntries, &json!([{"name": "x", "value": 42}])).unwrap();
assert_eq!(result, vec![json!({"x": 42})]);
}
#[test]
fn test_from_entries_k_v_keys() {
let result = eval(&Builtin::FromEntries, &json!([{"k": "foo", "v": "bar"}])).unwrap();
assert_eq!(result, vec![json!({"foo": "bar"})]);
}
#[test]
fn test_from_entries_empty() {
assert_eq!(
eval(&Builtin::FromEntries, &json!([])).unwrap(),
vec![json!({})]
);
}
#[test]
fn test_from_entries_non_array_errors() {
assert!(eval(&Builtin::FromEntries, &json!({"a": 1})).is_err());
}
}