use crate::graph::GraphStorage;
use crate::traversal::optimizer::plan::Plan;
use crate::traversal::optimizer::rule::OptimizationRule;
use crate::traversal::step::GraphStep;
#[derive(Default)]
pub(crate) struct AddPropertyFoldRule;
impl AddPropertyFoldRule {
pub fn new() -> Self {
Self
}
}
impl<'g, S: GraphStorage + 'g> OptimizationRule<'g, S> for AddPropertyFoldRule {
fn name(&self) -> &'static str {
"add_property_fold"
}
fn apply(&self, plan: &mut Plan<'g, S>) -> bool {
let mut modified = false;
let mut add = 0;
while add < plan.len() {
if !matches!(&plan[add], GraphStep::SideEffectMut("add_v" | "add_e", _)) {
add += 1;
continue;
}
let mut next = add + 1;
while next < plan.len() {
let folded = match &plan[next] {
GraphStep::Modulator(_, _) | GraphStep::As(_, _) => {
next += 1;
continue;
}
GraphStep::SideEffectMut("property", step) => step
.constant_property()
.map(|(key, value)| (key.clone(), value.clone())),
_ => None,
};
let Some((key, value)) = folded else {
break;
};
if let GraphStep::SideEffectMut(_, step) = plan.step_mut(add)
&& let Some(element) = step.as_add_element_mut()
{
element.fold_property(key, value);
}
plan.absorb(next, add);
modified = true;
}
add += 1;
}
modified
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::*;
#[test]
fn folds_the_whole_run_and_stops_at_a_traversal_value() {
let mut graph = TraversalGraph::new();
let mut traversal = graph
.traversal_mut()
.add_v("p")
.property("a", 1)
.property("b", 2)
.property_by("c", __::values("a"))
.property("d", 4);
let rule = AddPropertyFoldRule::new();
assert!(rule.apply_to_steps(&mut traversal.steps));
assert_eq!(traversal.steps.len(), 3);
assert!(!rule.apply_to_steps(&mut traversal.steps));
}
}