uqa_sql/schema/removal/
hierarchy.rs1use crate::ast::TableHierarchy;
9use std::{collections::BTreeSet, ops::Deref};
10use uqa_core::RelationIdentity;
11pub type HierarchyDropRead<'a> = Box<dyn Deref<Target = TableHierarchy> + 'a>;
12pub trait HierarchyDropTable {
13 fn hierarchy(&self) -> HierarchyDropRead<'_>;
14}
15pub type HierarchyDropEntries<'a> =
16 Box<dyn Iterator<Item = (&'a RelationIdentity, &'a dyn HierarchyDropTable)> + 'a>;
17pub trait HierarchyDropTables {
18 fn iter(&self) -> HierarchyDropEntries<'_>;
19}
20pub trait HierarchyDropCatalog {
21 fn tables(&self) -> Box<dyn HierarchyDropTables + '_>;
22}
23pub fn hierarchy_drop_targets(
24 catalog: &dyn HierarchyDropCatalog,
25 roots: &[String],
26 cascade: bool,
27) -> (Vec<String>, Vec<String>) {
28 let mut targets = roots.iter().cloned().collect::<BTreeSet<_>>();
29 let mut blockers = BTreeSet::new();
30 loop {
31 let mut added = false;
32 let tables = catalog.tables();
33 for (identity, table) in tables.iter() {
34 let candidate = identity.qualified_name();
35 if targets.contains(&candidate) {
36 continue;
37 }
38 let hierarchy = table.hierarchy();
39 if !hierarchy
40 .parents
41 .iter()
42 .any(|parent| targets.contains(parent))
43 {
44 continue;
45 }
46 if hierarchy.is_partition() || cascade {
47 added |= targets.insert(candidate);
48 } else {
49 blockers.insert(candidate);
50 }
51 }
52 if !added {
53 break;
54 }
55 }
56 (
57 targets.into_iter().collect(),
58 blockers.into_iter().collect(),
59 )
60}
61
62#[cfg(test)]
63mod tests;
64
65pub fn surviving_partition_ancestors(
67 catalog: &dyn HierarchyDropCatalog,
68 targets: &[String],
69) -> Vec<String> {
70 let tables = catalog.tables();
71 let parents = tables
72 .iter()
73 .filter_map(|(identity, table)| {
74 let hierarchy = table.hierarchy();
75 hierarchy
76 .is_partition()
77 .then(|| hierarchy.parents.first().cloned())
78 .flatten()
79 .map(|parent| (identity.qualified_name(), parent))
80 })
81 .collect::<std::collections::BTreeMap<_, _>>();
82 let dropped = targets.iter().collect::<BTreeSet<_>>();
83 let mut ancestors = Vec::new();
84 for target in targets {
85 let mut visited = BTreeSet::new();
86 let mut current = target;
87 while let Some(parent) = parents.get(current) {
88 if !visited.insert(parent) {
89 break;
90 }
91 if !dropped.contains(parent) && !ancestors.contains(parent) {
92 ancestors.push(parent.clone());
93 }
94 current = parent;
95 }
96 }
97 ancestors
98}