uqa_sql/schema/
constraint_views.rs1use crate::ast::{ColumnDef, ForeignKey, TableCheck, TableKeyConstraint, TableKeyConstraintKind};
9use std::collections::BTreeSet;
10use uqa_core::RelationIdentity;
11
12pub fn column_checks(columns: &[ColumnDef]) -> Vec<TableCheck> {
13 let mut out = Vec::new();
14 for column in columns {
15 if let Some(expr) = column.check.clone() {
16 out.push(TableCheck {
17 name: column
18 .check_name
19 .clone()
20 .or_else(|| Some(format!("{}_check", column.name))),
21 expr,
22 enforced: column.check_enforced,
23 validated: column.check_validated,
24 no_inherit: column.check_no_inherit,
25 object_id: column.check_object_id,
26 is_local: column.check_is_local,
27 partition_constraint: None,
28 });
29 }
30 }
31 out
32}
33pub fn append_column_foreign_keys(columns: &[ColumnDef], foreign_keys: &mut Vec<ForeignKey>) {
34 for column in columns {
35 if let Some(reference) = &column.references {
36 let mut foreign_key = super::foreign_keys::column_foreign_key(column, reference);
37 foreign_key.name = foreign_key
38 .name
39 .or_else(|| Some(format!("{}_fkey", column.name)));
40 foreign_keys.push(foreign_key);
41 }
42 }
43}
44pub fn append_column_keys(columns: &[ColumnDef], constraints: &mut Vec<TableKeyConstraint>) {
45 for column in columns {
46 let kind = if column.primary_key {
47 Some(TableKeyConstraintKind::PrimaryKey)
48 } else if column.unique {
49 Some(TableKeyConstraintKind::Unique)
50 } else {
51 None
52 };
53 let Some(kind) = kind else {
54 continue;
55 };
56 if constraints.iter().any(|constraint| {
57 constraint.kind == kind
58 && constraint.columns.as_slice() == std::slice::from_ref(&column.name)
59 }) {
60 continue;
61 }
62 constraints.push(TableKeyConstraint {
63 name: None,
64 kind,
65 columns: vec![column.name.clone()],
66 nulls_not_distinct: false,
67 without_overlaps: false,
68 });
69 }
70}
71pub fn auto_increment_columns(columns: &[ColumnDef]) -> BTreeSet<String> {
72 columns
73 .iter()
74 .filter(|column| column.auto_increment.is_some())
75 .map(|column| column.name.clone())
76 .collect()
77}
78pub fn unique_scalar_columns(
79 constraints: Vec<TableKeyConstraint>,
80 auto_increment: &BTreeSet<String>,
81) -> Vec<String> {
82 constraints
83 .into_iter()
84 .filter(|constraint| constraint.columns.len() == 1)
85 .map(|constraint| constraint.columns[0].clone())
86 .filter(|column| !auto_increment.contains(column))
87 .collect()
88}
89pub trait StoredTableNames {
91 fn stored_table_exists(&self, relation: &RelationIdentity) -> bool;
92 fn stored_table_names(&self) -> Vec<RelationIdentity>;
93}
94pub fn canonical_stored_foreign_key_target(
95 catalog: &dyn StoredTableNames,
96 reference: &str,
97) -> Result<String, String> {
98 let (schema, local_name) = RelationIdentity::parse_reference(reference)
99 .map_err(|error| format!("invalid persisted foreign-key target `{reference}`: {error}"))?;
100 if let Some(schema) = schema {
101 let target = RelationIdentity::new(schema, local_name);
102 if catalog.stored_table_exists(&target) {
103 return Ok(target.qualified_name());
104 }
105 return Err(format!(
106 "dangling persisted foreign-key target `{reference}`"
107 ));
108 }
109 let candidates = catalog
110 .stored_table_names()
111 .into_iter()
112 .filter(|candidate| candidate.name == local_name)
113 .map(|candidate| candidate.qualified_name())
114 .collect::<Vec<_>>();
115 match candidates.as_slice() {
116 [target] => Ok(target.clone()),
117 [] => Err(format!(
118 "dangling persisted foreign-key target `{reference}`"
119 )),
120 _ => Err(format!(
121 "ambiguous persisted foreign-key target `{reference}` matches {}",
122 candidates.join(", ")
123 )),
124 }
125}
126pub fn bind_stored_foreign_key_targets(
127 catalog: &dyn StoredTableNames,
128 foreign_keys: &mut [ForeignKey],
129) -> Result<(), String> {
130 for foreign_key in foreign_keys {
131 foreign_key.ref_table =
132 canonical_stored_foreign_key_target(catalog, &foreign_key.ref_table)?;
133 }
134 Ok(())
135}