Skip to main content

uqa_sql/schema/removal/
hierarchy.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Expand DROP targets through retained inheritance and partition metadata.
8use 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;