use crate::{JsonPathConfig, JsonPathValue};
use serde_json::Value;
use crate::parser::model::{Function, JsonPath, JsonPathIndex, Operand};
use crate::path::index::{ArrayIndex, ArraySlice, Current, FilterPath, UnionIndex};
use crate::path::top::*;
pub mod config;
mod index;
mod json;
mod top;
pub trait Path<'a> {
type Data;
fn find(&self, input: JsonPathValue<'a, Self::Data>) -> Vec<JsonPathValue<'a, Self::Data>> {
vec![input]
}
fn flat_find(
&self,
input: Vec<JsonPathValue<'a, Self::Data>>,
_is_search_length: bool,
) -> Vec<JsonPathValue<'a, Self::Data>> {
input.into_iter().flat_map(|d| self.find(d)).collect()
}
fn cfg(&self) -> JsonPathConfig {
JsonPathConfig::default()
}
fn needs_all(&self) -> bool {
false
}
}
pub type PathInstance<'a> = Box<dyn Path<'a, Data = Value> + 'a>;
pub fn json_path_instance<'a>(
json_path: &'a JsonPath,
root: &'a Value,
cfg: JsonPathConfig,
) -> PathInstance<'a> {
match json_path {
JsonPath::Root => Box::new(RootPointer::new(root)),
JsonPath::Field(key) => Box::new(ObjectField::new(key)),
JsonPath::Chain(chain) => Box::new(Chain::from(chain, root, cfg)),
JsonPath::Wildcard => Box::new(Wildcard {}),
JsonPath::Descent(key) => Box::new(DescentObject::new(key)),
JsonPath::DescentW => Box::new(DescentWildcard),
JsonPath::Current(value) => Box::new(Current::from(value, root, cfg)),
JsonPath::Index(index) => process_index(index, root, cfg),
JsonPath::Empty => Box::new(IdentityPath {}),
JsonPath::Fn(Function::Length) => Box::new(FnPath::Size),
}
}
fn process_index<'a>(
json_path_index: &'a JsonPathIndex,
root: &'a Value,
cfg: JsonPathConfig,
) -> PathInstance<'a> {
match json_path_index {
JsonPathIndex::Single(index) => Box::new(ArrayIndex::new(index.as_u64().unwrap() as usize)),
JsonPathIndex::Slice(s, e, step) => Box::new(ArraySlice::new(*s, *e, *step)),
JsonPathIndex::UnionKeys(elems) => Box::new(UnionIndex::from_keys(elems)),
JsonPathIndex::UnionIndex(elems) => Box::new(UnionIndex::from_indexes(elems)),
JsonPathIndex::Filter(fe) => Box::new(FilterPath::new(fe, root, cfg)),
}
}
fn process_operand<'a>(op: &'a Operand, root: &'a Value, cfg: JsonPathConfig) -> PathInstance<'a> {
match op {
Operand::Static(v) => json_path_instance(&JsonPath::Root, v, cfg),
Operand::Dynamic(jp) => json_path_instance(jp, root, cfg),
}
}