use std::collections::{HashMap, HashSet};
use flowscope_core::{EdgeType, NodeType, StatementLineage};
pub(crate) fn representative_join_edge_indexes(statement: &StatementLineage) -> Vec<usize> {
let node_types: HashMap<&str, NodeType> = statement
.nodes
.iter()
.map(|node| (node.id.as_ref(), node.node_type))
.collect();
let owned_node_to_relation: HashMap<&str, &str> = statement
.edges
.iter()
.filter(|edge| edge.edge_type == EdgeType::Ownership)
.filter_map(|edge| {
let owner_type = node_types.get(edge.from.as_ref()).copied()?;
owner_type
.is_relation()
.then_some((edge.to.as_ref(), edge.from.as_ref()))
})
.collect();
let mut seen = HashSet::new();
let mut indexes = Vec::new();
for (edge_idx, edge) in statement.edges.iter().enumerate() {
let Some(join_type) = edge.join_type else {
continue;
};
let Some(from_relation_id) =
resolve_relation_node_id(edge.from.as_ref(), &node_types, &owned_node_to_relation)
else {
continue;
};
let Some(to_relation_id) =
resolve_relation_node_id(edge.to.as_ref(), &node_types, &owned_node_to_relation)
else {
continue;
};
if from_relation_id == to_relation_id {
continue;
}
let key = (
from_relation_id.to_owned(),
to_relation_id.to_owned(),
format!("{join_type:?}"),
edge.join_condition
.as_deref()
.unwrap_or_default()
.to_owned(),
);
if seen.insert(key) {
indexes.push(edge_idx);
}
}
indexes
}
fn resolve_relation_node_id<'a>(
node_id: &'a str,
node_types: &HashMap<&'a str, NodeType>,
owned_node_to_relation: &HashMap<&'a str, &'a str>,
) -> Option<&'a str> {
match node_types.get(node_id).copied() {
Some(node_type) if node_type.is_relation() => Some(node_id),
_ => owned_node_to_relation.get(node_id).copied(),
}
}