Skip to main content

uqa_sql/schema/columns/
publication.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Mutate a declared column candidate before its catalog publication.
8use crate::ast::{ColumnDef, ColumnType, Expr, GeneratedColumn};
9
10/// Rename the declaration without changing its durable column identity or attribute number.
11pub fn rename_column(columns: &mut [ColumnDef], from: &str, to: &str) {
12    for column in columns {
13        if column.name == from {
14            column.name = to.to_string();
15        }
16    }
17}
18
19/// Record a newly declared local column; recursively added parent columns retain their inherited origin.
20pub fn register_local_column(
21    hierarchy: &mut crate::ast::TableHierarchy,
22    name: &str,
23    inherited: bool,
24) {
25    if !inherited && !hierarchy.local_columns.iter().any(|column| column == name) {
26        hierarchy.local_columns.push(name.to_string());
27    }
28}
29
30/// A rename changes the spelling of the local declaration, not its origin.
31pub fn rename_local_column(hierarchy: &mut crate::ast::TableHierarchy, from: &str, to: &str) {
32    for name in &mut hierarchy.local_columns {
33        if name == from {
34            *name = to.to_string();
35        }
36    }
37}
38
39/// Removing a local declaration lets a later same-named inherited column have its own origin.
40pub fn remove_local_column(hierarchy: &mut crate::ast::TableHierarchy, name: &str) {
41    hierarchy.local_columns.retain(|column| column != name);
42}
43
44#[derive(Clone)]
45pub enum ColumnProperty<'a> {
46    Default(Option<Expr>),
47    Generated(Option<GeneratedColumn>),
48    Type(&'a ColumnType),
49    /// The `SERIAL` or identity provenance of the column.
50    AutoIncrement(Option<crate::ast::AutoIncrement>),
51}
52pub fn column_mut<'a>(
53    columns: &'a mut [ColumnDef],
54    table: &str,
55    column: &str,
56) -> Result<&'a mut ColumnDef, String> {
57    columns
58        .iter_mut()
59        .find(|definition| definition.name == column)
60        .ok_or_else(|| format!("column `{column}` does not exist on table `{table}`"))
61}
62pub fn apply_property(
63    columns: &mut [ColumnDef],
64    table: &str,
65    column: &str,
66    property: ColumnProperty<'_>,
67) -> Result<(), String> {
68    let definition = column_mut(columns, table, column)?;
69    match property {
70        ColumnProperty::Default(default) => definition.default = default,
71        ColumnProperty::Generated(generated) => definition.generated = generated,
72        ColumnProperty::Type(ty) => definition.ty.clone_from(ty),
73        ColumnProperty::AutoIncrement(provenance) => definition.auto_increment = provenance,
74    }
75    // Each change removes the column's `pg_attrdef` row; an expression that remains is stored again under a new OID, as `ATExecAlterColumnType` and `ATExecColumnDefault` store it.
76    definition.default_catalog_oid = None;
77    Ok(())
78}
79pub fn set_not_null(
80    columns: &mut [ColumnDef],
81    table: &str,
82    column: &str,
83    not_null: bool,
84) -> Result<(), String> {
85    let definition = column_mut(columns, table, column)?;
86    definition.not_null = not_null;
87    definition.not_null_explicit = not_null;
88    definition.not_null_is_local = true;
89    definition.not_null_validated = true;
90    definition.not_null_no_inherit = false;
91    if !not_null {
92        definition.not_null_name = None;
93        definition.not_null_identity = None;
94    }
95    Ok(())
96}