use std::collections::{HashMap, VecDeque};
use petgraph::{graph::NodeIndex, Direction};
use tracing::{instrument, trace};
use crate::query_planner::planner::fetch::{
error::FetchGraphError, fetch_graph::FetchGraph, optimize::utils::perform_fetch_step_merge,
state::MultiTypeFetchStep,
};
impl FetchGraph<MultiTypeFetchStep> {
#[instrument(level = "trace", skip_all)]
pub(crate) fn merge_children_with_parents(&mut self) -> Result<(), FetchGraphError> {
let root_index = self
.root_index
.ok_or(FetchGraphError::NonSingleRootStep(0))?;
let mut queue = VecDeque::from([root_index]);
let mut node_indexes: HashMap<NodeIndex, NodeIndex> = HashMap::new();
node_indexes.insert(root_index, root_index);
while let Some(parent_index) = queue.pop_front() {
let mut merges_to_perform: Vec<(NodeIndex, NodeIndex)> = Vec::new();
let parent_index = *node_indexes
.get(&parent_index)
.ok_or(FetchGraphError::IndexMappingLost)?;
let children: Vec<_> = self
.graph
.neighbors_directed(parent_index, Direction::Outgoing)
.collect();
let parent = self.get_step_data(parent_index)?;
for child_index in children.iter() {
queue.push_back(*child_index);
let child = self.get_step_data(*child_index)?;
node_indexes.insert(*child_index, *child_index);
node_indexes.insert(parent_index, parent_index);
if parent.can_merge(parent_index, *child_index, child, self) {
trace!(
"optimization found: merge parent [{}] with child [{}]",
parent_index.index(),
child_index.index()
);
merges_to_perform.push((parent_index, *child_index));
}
}
for (parent_index, child_index) in merges_to_perform {
let parent_index_latest = node_indexes
.get(&parent_index)
.ok_or(FetchGraphError::IndexMappingLost)?;
let child_index_latest = node_indexes
.get(&child_index)
.ok_or(FetchGraphError::IndexMappingLost)?;
perform_fetch_step_merge(*parent_index_latest, *child_index_latest, self, false)?;
node_indexes.insert(*child_index_latest, *parent_index_latest);
}
}
Ok(())
}
}