use petgraph::graph::NodeIndex;
use tracing::{instrument, trace};
use crate::query_planner::planner::fetch::{
error::FetchGraphError, fetch_graph::FetchGraph, fetch_step_data::FetchStepData,
optimize::utils::perform_fetch_step_merge, state::MultiTypeFetchStep,
};
impl FetchStepData<MultiTypeFetchStep> {
pub fn can_merge_leafs(
&self,
self_index: NodeIndex,
other_index: NodeIndex,
other: &Self,
fetch_graph: &FetchGraph<MultiTypeFetchStep>,
) -> bool {
if self_index == other_index {
return false;
}
if self.service_name != other.service_name {
return false;
}
if self.response_path != other.response_path {
return false;
}
if !self.input.selecting_same_types(&other.input) {
return false;
}
if self.condition != other.condition {
return false;
}
if self.mutation_field_position != other.mutation_field_position {
return false;
}
if fetch_graph.children_of(other_index).count() != 0 {
return false;
}
if fetch_graph.is_descendant_of(other_index, self_index) {
return false;
}
if self.has_arguments_conflicts_with(other) {
return false;
}
true
}
}
impl FetchGraph<MultiTypeFetchStep> {
#[instrument(level = "trace", skip_all)]
pub(crate) fn merge_leafs(&mut self) -> Result<(), FetchGraphError> {
while let Some((target_idx, leaf_idx)) = self.find_merge_candidate()? {
perform_fetch_step_merge(target_idx, leaf_idx, self, false)?;
}
Ok(())
}
fn find_merge_candidate(&self) -> Result<Option<(NodeIndex, NodeIndex)>, FetchGraphError> {
let all_nodes: Vec<NodeIndex> = self
.graph
.node_indices()
.filter(|&idx| self.root_index != Some(idx))
.collect();
for &target_idx in &all_nodes {
for &leaf_idx in &all_nodes {
let target_data = self.get_step_data(target_idx)?;
let leaf_data = self.get_step_data(leaf_idx)?;
if target_data.can_merge_leafs(target_idx, leaf_idx, leaf_data, self) {
trace!(
"optimization found: merge leaf [{}] with [{}]",
leaf_idx.index(),
target_idx.index(),
);
return Ok(Some((target_idx, leaf_idx)));
}
}
}
Ok(None)
}
}