Skip to main content

uqa_sql/catalog/
events.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7use crate::ast::{CreateRule, CreateTrigger, EventEnableMode};
8use serde::{Deserialize, Serialize};
9use std::collections::BTreeSet;
10
11mod rule_condition_binding;
12pub use rule_condition_binding::RuleConditionBinding;
13
14#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
15pub struct RuleDependencies {
16    #[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
17    pub relations: BTreeSet<uqa_core::RelationIdentity>,
18    #[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
19    pub columns: BTreeSet<RuleColumnDependency>,
20    #[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
21    pub routines: BTreeSet<RuleRoutineDependency>,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
25pub struct RuleColumnDependency {
26    pub relation: uqa_core::RelationIdentity,
27    pub column: String,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
31pub struct RuleRoutineDependency {
32    #[serde(default, skip_serializing_if = "Option::is_none")]
33    pub object_id: Option<[u8; 16]>,
34    pub name: String,
35    pub argument_types: Vec<String>,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct StoredTrigger {
40    pub definition: CreateTrigger,
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub function_object_id: Option<[u8; 16]>,
43    #[serde(default)]
44    pub enabled: EventEnableMode,
45    #[serde(default)]
46    pub object_id: Option<[u8; 16]>,
47    #[serde(default)]
48    pub constraint_name: Option<String>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct StoredRule {
53    pub definition: CreateRule,
54    #[serde(default)]
55    pub enabled: EventEnableMode,
56    #[serde(default, skip_serializing_if = "Option::is_none")]
57    pub condition_plan: Option<crate::plan::ExpressionPlan>,
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub condition_binding: Option<RuleConditionBinding>,
60    #[serde(default, skip_serializing_if = "Option::is_none")]
61    pub dependencies: Option<RuleDependencies>,
62}
63
64impl StoredRule {
65    pub fn bound_condition_plan(
66        &self,
67    ) -> Option<(&crate::plan::ExpressionPlan, &RuleConditionBinding)> {
68        self.condition_plan
69            .as_ref()
70            .zip(self.condition_binding.as_ref())
71    }
72}
73
74impl StoredTrigger {
75    pub fn constraint_identity(
76        &self,
77    ) -> Result<super::constraints::ConstraintIdentity, crate::SQLError> {
78        use super::constraints::ConstraintIdentity;
79        use crate::SQLError;
80        use uqa_core::RelationIdentity;
81        let trigger = self;
82        if !trigger.definition.constraint {
83            return Err(SQLError::Internal(format!(
84                "ordinary trigger `{}` requested a constraint identity",
85                trigger.definition.name
86            )));
87        }
88        let relation =
89            RelationIdentity::from_legacy_name(&trigger.definition.table).map_err(|error| {
90                SQLError::Internal(format!(
91                    "decode constraint-trigger relation `{}`: {error}",
92                    trigger.definition.table
93                ))
94            })?;
95        Ok(ConstraintIdentity {
96            relation,
97            name: trigger
98                .constraint_name
99                .clone()
100                .unwrap_or_else(|| trigger.definition.name.clone()),
101            object_id: trigger.object_id,
102        })
103    }
104}
105
106use crate::SQLError;
107pub type TriggerCatalog = std::collections::BTreeMap<
108    uqa_core::RelationIdentity,
109    std::collections::BTreeMap<String, StoredTrigger>,
110>;
111pub type RuleCatalog = std::collections::BTreeMap<
112    uqa_core::RelationIdentity,
113    std::collections::BTreeMap<String, StoredRule>,
114>;
115pub mod dependencies;
116pub mod renames;
117
118pub fn synchronize_rule_sql_text(definition: &mut CreateRule) -> Result<(), SQLError> {
119    definition.condition_sql = definition
120        .condition
121        .as_ref()
122        .map(crate::render::expression_sql)
123        .transpose()?;
124    definition.action_sql = definition
125        .actions
126        .iter()
127        .map(crate::render::statement_sql)
128        .collect::<Result<Vec<_>, _>>()?;
129    Ok(())
130}
131
132/// Surviving rule definitions prepared before column metadata changes, plus the rules to rebind afterward.
133pub struct PreparedRuleColumnDrop {
134    pub rules: RuleCatalog,
135    pub rebind: BTreeSet<(uqa_core::RelationIdentity, String)>,
136}
137
138pub mod validation;
139
140pub mod definition;
141
142pub mod restoration;
143
144pub mod reads;
145
146pub mod removal;
147
148pub mod persistence;