json_walk 0.1.0

Access values in your JSON data using string paths (e.g. "result.item[0].value").
Documentation
use crate::json_path_parser::{JsonPathParser, Segment};
use anyhow::anyhow;
use serde_json::Value;
#[derive(Debug, Clone)]
pub struct JsonValueLocator {
    data: Value,
}

impl JsonValueLocator {
    /// Initialize the Json Value Locator
    /// Parameters
    /// - data: The deserialized JSON data.
    pub fn new(data: Value) -> Self {
        Self { data }
    }

    /// Get the value from a given path.
    /// Parameters:
    /// - path:  The path to retrieve. Example: result.item[0].value
    pub fn get(&self, path: &str) -> anyhow::Result<Value> {
        let segment = JsonPathParser::parse(path)?;
        let mut data: Value = self.data.clone();
        for item in segment.iter() {
            match item {
                Segment::Key(key) => {
                    if let Value::Object(obj) = &data {
                        data = if obj.contains_key(key)
                            && let Some(value) = obj.get(key)
                        {
                            value.to_owned()
                        } else {
                            return Err(anyhow!(format!("{} key does not exists", key)));
                        };
                    }
                }
                Segment::Index(key, index) => {
                    if let Value::Object(obj) = &data {
                        let values = if obj.contains_key(key)
                            && let Some(Value::Array(values)) = obj.get(key)
                        {
                            values.to_owned()
                        } else {
                            return Err(anyhow!(format!(
                                "{} key does not exists or must be an array",
                                key
                            )));
                        };
                        if let Some(value) = values.get(index.to_owned()) {
                            data = value.to_owned()
                        }
                    }
                }
            }
        }
        Ok(data)
    }
}

/// Test Data
/// | Path                           | Expected Value           |
/// | ------------------------------ | ------------------------ |
/// | `result.item[0].value`         | `"apple"`                |
/// | `result.item[1].details.color` | `"yellow"`               |
/// | `result.meta.count`            | `2`                      |
/// | `status`                       | `"success"`              |
/// | `result.item[0].details.price` | `1.2`                    |
/// | `timestamp`                    | `"2025-10-12T10:00:00Z"` |
#[test]
pub fn test_json_value_locator() {
    use crate::file_handler::FileHandler;
    use serde_json::{Number, Value};
    let data = FileHandler::load("storage/test-data/data.json").unwrap();
    let locator = JsonValueLocator::new(data);

    let test_cases: Vec<(&str, Value)> = vec![
        ("result.item[0].value", Value::String("apple".to_string())),
        (
            "result.item[1].details.color",
            Value::String("yellow".to_string()),
        ),
        ("result.meta.count", Value::Number(Number::from(2))),
        ("status", Value::String("success".to_string())),
        (
            "result.item[0].details.price",
            Value::Number(Number::from_f64(1.2).unwrap()),
        ),
        (
            "timestamp",
            Value::String("2025-10-12T10:00:00Z".to_string()),
        ),
    ];
    for test_case in test_cases {
        let result = locator.get(test_case.0);
        assert!(result.is_ok(), "{:#?}", result.err());
        assert_eq!(test_case.1, result.unwrap())
    }
}