uqa_sql/schema/removal/
tables.rs1use crate::{
9 ast::{ColumnDef, ForeignKey, TableCheck, TableKeyConstraint},
10 schema::dependencies::rewrites::{
11 schema_expr_references_relation, stored_relation_reference_matches,
12 },
13};
14use std::ops::Deref;
15use uqa_core::RelationIdentity;
16pub type TableColumnsRead<'a> = Box<dyn Deref<Target = Vec<ColumnDef>> + 'a>;
17pub type TableChecksRead<'a> = Box<dyn Deref<Target = Vec<TableCheck>> + 'a>;
18pub type TableForeignKeysRead<'a> = Box<dyn Deref<Target = Vec<ForeignKey>> + 'a>;
19pub type TableKeysRead<'a> = Box<dyn Deref<Target = Vec<TableKeyConstraint>> + 'a>;
20pub trait TableRemovalMetadata {
21 fn columns(&self) -> TableColumnsRead<'_>;
22 fn table_checks(&self) -> TableChecksRead<'_>;
23 fn foreign_keys(&self) -> TableForeignKeysRead<'_>;
24 fn key_constraints(&self) -> TableKeysRead<'_>;
25}
26pub fn table_schema_references_relation(
27 table: &dyn TableRemovalMetadata,
28 target: &RelationIdentity,
29) -> bool {
30 table.columns().iter().any(|column| {
31 column
32 .default
33 .as_ref()
34 .is_some_and(|expr| schema_expr_references_relation(expr, target))
35 || column
36 .check
37 .as_ref()
38 .is_some_and(|expr| schema_expr_references_relation(expr, target))
39 || column.generated.as_ref().is_some_and(|generated| {
40 schema_expr_references_relation(&generated.expression, target)
41 })
42 }) || table
43 .table_checks()
44 .iter()
45 .any(|check| schema_expr_references_relation(&check.expr, target))
46}
47pub fn foreign_key_targets(
48 foreign_key: &crate::ast::ForeignKey,
49 target: &RelationIdentity,
50) -> bool {
51 stored_relation_reference_matches(&foreign_key.ref_table, target)
52}
53pub fn resolved_table_ddl_target(
54 resolved: Option<(String, &str)>,
55 action: &str,
56) -> Result<Option<String>, String> {
57 match resolved {
58 Some((canonical, "table")) => Ok(Some(canonical)),
59 Some((canonical, kind)) => Err(format!(
60 "{action}: relation `{canonical}` is a {kind}, not a table"
61 )),
62 None => Ok(None),
63 }
64}
65pub fn detach_inbound_foreign_keys(
66 columns: &mut [ColumnDef],
67 foreign_keys: &mut Vec<ForeignKey>,
68 targets: &[RelationIdentity],
69) -> bool {
70 let previous_fk_len = foreign_keys.len();
71 foreign_keys.retain(|foreign_key| {
72 !targets
73 .iter()
74 .any(|target| foreign_key_targets(foreign_key, target))
75 });
76 let mut changed = previous_fk_len != foreign_keys.len();
77 for column in columns {
78 if column.references.as_ref().is_some_and(|reference| {
79 targets
80 .iter()
81 .any(|target| stored_relation_reference_matches(&reference.table, target))
82 }) {
83 column.references = None;
84 changed = true;
85 }
86 }
87 changed
88}
89
90#[cfg(test)]
91mod tests;