jarq 0.2.1

An interactive jq-like JSON query tool with a TUI
Documentation
//! Object operations: keys, values

use serde_json::Value;

use crate::error::EvalError;
use super::{type_error, type_name};

pub fn eval_keys(value: &Value) -> Result<Value, EvalError> {
    match value {
        Value::Object(obj) => {
            let mut keys: Vec<&String> = obj.keys().collect();
            keys.sort(); // jq returns sorted keys
            let keys: Vec<Value> = keys.into_iter().map(|k| Value::String(k.clone())).collect();
            Ok(Value::Array(keys))
        }
        Value::Array(arr) => {
            let indices: Vec<Value> = (0..arr.len()).map(|i| Value::Number(i.into())).collect();
            Ok(Value::Array(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(vals))
        }
        Value::Array(arr) => Ok(Value::Array(arr.clone())),
        _ => Err(type_error(format!("{} has no values", type_name(value)))),
    }
}

#[cfg(test)]
mod tests {
    use crate::filter::builtins::{eval, Builtin};
    use serde_json::json;

    #[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"])]); // sorted
    }

    #[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());
    }
}