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;