use jsonpath_rust::parser::JsonPath;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use shard_den_core::Result;
#[derive(Debug, Clone)]
pub struct ExtractResult {
pub values: Vec<ExtractedValue>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExtractedValue {
pub path: String,
pub value: Value,
}
#[derive(Debug, Default)]
pub struct Extractor;
impl Extractor {
pub fn new() -> Self {
Self
}
pub fn extract(&self, json: &Value, paths: &[String]) -> Result<ExtractResult> {
let values = paths
.iter()
.map(|path| self.extract_single(json, path))
.collect::<Result<Vec<_>>>()?;
Ok(ExtractResult { values })
}
fn extract_single(&self, json: &Value, path: &str) -> Result<ExtractedValue> {
let json_path = JsonPath::try_from(path).map_err(|e| {
shard_den_core::ShardDenError::invalid_input(format!("JSONPath error: {}", e))
})?;
let result = json_path.find(json);
Ok(ExtractedValue {
path: path.to_string(),
value: result,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extractor_new() {
let extractor = Extractor::new();
let _ = extractor; }
#[test]
fn test_extract_array_wildcard() {
let json: Value =
serde_json::from_str(r#"{"items": [{"id": 1}, {"id": 2}, {"id": 3}]}"#).unwrap();
let extractor = Extractor::new();
let result = extractor.extract(&json, &["$.items[*].id".to_string()]);
println!("Array wildcard result: {:?}", result);
assert!(result.is_ok(), "Error: {:?}", result.err());
let extract_result = result.unwrap();
assert_eq!(extract_result.values.len(), 1);
let extracted = &extract_result.values[0].value;
let arr = extracted.as_array().unwrap();
assert_eq!(arr.len(), 3);
}
#[test]
fn test_extract_filter() {
let json: Value =
serde_json::from_str(r#"{"items": [{"price": 10}, {"price": 20}, {"price": 30}]}"#)
.unwrap();
let extractor = Extractor::new();
let result = extractor.extract(&json, &["$.items[?(@.price > 15)]".to_string()]);
println!("Filter result: {:?}", result);
assert!(result.is_ok(), "Error: {:?}", result.err());
let extract_result = result.unwrap();
assert_eq!(extract_result.values.len(), 1);
let extracted = &extract_result.values[0].value;
let arr = extracted.as_array().unwrap();
assert_eq!(arr.len(), 2);
}
#[test]
fn test_extract_recursive() {
let json: Value =
serde_json::from_str(r#"{"a": {"id": 1}, "b": {"c": {"id": 2}}}"#).unwrap();
let extractor = Extractor::new();
let result = extractor.extract(&json, &["$..id".to_string()]);
println!("Recursive result: {:?}", result);
assert!(result.is_ok(), "Error: {:?}", result.err());
let extract_result = result.unwrap();
assert_eq!(extract_result.values.len(), 1);
let extracted = &extract_result.values[0].value;
let arr = extracted.as_array().unwrap();
assert_eq!(arr.len(), 2);
}
#[test]
fn test_extract_invalid_path() {
let json: Value = serde_json::from_str(r#"{"name": "test"}"#).unwrap();
let extractor = Extractor::new();
let result = extractor.extract(&json, &["[[[".to_string()]);
assert!(result.is_err());
}
#[test]
fn test_extract_empty_path() {
let json: Value = serde_json::from_str(r#"{"name": "test"}"#).unwrap();
let extractor = Extractor::new();
let result = extractor.extract(&json, &["".to_string()]);
assert!(result.is_err());
}
}