use serde_json::Value;
use super::path_parser::PathSegment;
pub const DEFAULT_ARRAY_SAMPLE_SIZE: usize = 10;
#[allow(dead_code)]
pub fn navigate<'a>(root: &'a Value, segments: &[PathSegment]) -> Option<&'a Value> {
let mut current = root;
for segment in segments {
current = match segment {
PathSegment::Field(name) | PathSegment::OptionalField(name) => match current {
Value::Object(map) => map.get(name)?,
_ => return None,
},
PathSegment::ArrayIterator => match current {
Value::Array(arr) => arr.first()?,
_ => return None,
},
PathSegment::ArrayIndex(i) => {
match current {
Value::Array(arr) => {
let index = if *i < 0 {
let len = arr.len() as i64;
let adjusted = len + i;
if adjusted < 0 {
return None;
}
adjusted as usize
} else {
*i as usize
};
arr.get(index)?
}
_ => return None,
}
}
};
}
Some(current)
}
const MAX_NAVIGATED_VALUES: usize = 1000;
pub fn navigate_multi<'a>(
root: &'a Value,
segments: &[PathSegment],
sample_size: usize,
) -> Vec<&'a Value> {
let mut current_values: Vec<&Value> = vec![root];
for segment in segments {
let mut next_values: Vec<&Value> = Vec::new();
for value in ¤t_values {
match segment {
PathSegment::Field(name) | PathSegment::OptionalField(name) => {
if let Value::Object(map) = value
&& let Some(v) = map.get(name)
{
next_values.push(v);
}
}
PathSegment::ArrayIterator => {
if let Value::Array(arr) = value {
for element in arr.iter().take(sample_size) {
next_values.push(element);
if next_values.len() >= MAX_NAVIGATED_VALUES {
break;
}
}
}
}
PathSegment::ArrayIndex(i) => {
if let Value::Array(arr) = value {
let index = if *i < 0 {
let len = arr.len() as i64;
let adjusted = len + i;
if adjusted < 0 {
continue;
}
adjusted as usize
} else {
*i as usize
};
if let Some(v) = arr.get(index) {
next_values.push(v);
}
}
}
}
if next_values.len() >= MAX_NAVIGATED_VALUES {
break;
}
}
if next_values.is_empty() {
return Vec::new();
}
current_values = next_values;
}
current_values
}