use crate::graph::GraphStorage;
use crate::value::json_path::{JsonPathSegment, descend_properties, descend_property};
use crate::value::{JsonPath, PropKey, PropKeys};
use crate::*;
pub(crate) fn peek_path<S: GraphStorage, R>(
context: &TraverserContext<'_, S>,
value: &TraverserValue<S>,
segments: &[JsonPathSegment],
f: impl FnOnce(&ElementProperty) -> R,
) -> TraverserResult<Option<R>> {
match value {
TraverserValue::Vertex(node) => Ok(context
.storage
.vertex_properties(*node)
.and_then(|props| descend_properties(props, segments))
.map(f)),
TraverserValue::Edge(edge) => Ok(context
.storage
.edge_properties(*edge)
.and_then(|props| descend_properties(props, segments))
.map(f)),
TraverserValue::Computed(root, _) => Ok(descend_property(root, segments).map(f)),
TraverserValue::VertexProperty(name, node, _) => Ok(context
.storage
.vertex_properties(*node)
.and_then(|props| props.get(name.as_str()))
.and_then(|root| descend_property(root, segments))
.map(f)),
TraverserValue::EdgeProperty(name, edge, _) => Ok(context
.storage
.edge_properties(*edge)
.and_then(|props| props.get(name.as_str()))
.and_then(|root| descend_property(root, segments))
.map(f)),
TraverserValue::Object(_) | TraverserValue::Record { .. } => {
match TraverserValue::resolve_json_path(context, value, segments) {
Some(leaf) => {
let leaf = leaf.into_node_property(context.storage)?;
Ok(Some(f(&leaf)))
}
None => Ok(None),
}
}
other => Err(Box::new(TraverserError::cast_exception(
&["vertex", "edge", "object"],
other,
))),
}
}
#[derive(Clone)]
pub(crate) struct PathKeys {
pub(crate) paths: Vec<(JsonPath, CompactString)>,
display: Vec<PropKey>,
}
impl PathKeys {
pub(crate) fn split(keys: PropKeys) -> (Option<Vec<String>>, Option<PathKeys>) {
match keys.into_names() {
Ok(names) => (names, None),
Err(keys) => {
let names = keys
.iter()
.filter_map(|k| k.as_name().map(str::to_string))
.collect();
let paths = keys
.iter()
.filter_map(|k| {
k.as_path()
.map(|p| (p.clone(), CompactString::new(p.to_string())))
})
.collect();
(
Some(names),
Some(PathKeys {
paths,
display: keys,
}),
)
}
}
}
pub(crate) fn render(&self) -> String {
self.display
.iter()
.map(crate::value::literal::rhai_prop_key)
.collect::<Vec<_>>()
.join(", ")
}
pub(crate) fn append<S: GraphStorage>(
&self,
props: Option<&PropertyMap>,
keys: &mut Vec<CompactString>,
values: &mut Vec<TraverserValue<S>>,
wrap: impl Fn(ElementProperty) -> TraverserValue<S>,
) {
let Some(props) = props else { return };
for (path, text) in &self.paths {
if let Some(leaf) = descend_properties(props, path.segments()) {
keys.push(text.clone());
values.push(wrap(leaf.to_logical()));
}
}
}
pub(crate) fn append_from_value<S: GraphStorage>(
&self,
context: &TraverserContext<'_, S>,
value: &TraverserValue<S>,
keys: &mut Vec<CompactString>,
values: &mut Vec<TraverserValue<S>>,
) {
for (path, text) in &self.paths {
if let Some(leaf) = TraverserValue::resolve_json_path(context, value, path.segments()) {
keys.push(text.clone());
values.push(leaf);
}
}
}
}