Skip to main content

uqa_sql/ast/
events.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Row-trigger and rewrite-rule catalog statements.
8
9use serde::{Deserialize, Serialize};
10
11use super::{Expr, Statement};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14pub enum TriggerTiming {
15    Before,
16    After,
17    InsteadOf,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
21pub enum TriggerEvent {
22    Insert,
23    Update,
24    Delete,
25    Truncate,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
29pub struct TriggerTransitionRelation {
30    pub name: String,
31    pub is_new: bool,
32    pub is_table: bool,
33}
34
35#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
36#[serde(rename_all = "snake_case")]
37pub enum TriggerDeferrability {
38    #[default]
39    NotDeferrable,
40    InitiallyImmediate,
41    InitiallyDeferred,
42}
43
44impl TriggerDeferrability {
45    pub const fn is_deferrable(self) -> bool {
46        !matches!(self, Self::NotDeferrable)
47    }
48
49    pub const fn is_initially_deferred(self) -> bool {
50        matches!(self, Self::InitiallyDeferred)
51    }
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct CreateTrigger {
56    pub name: String,
57    pub table: String,
58    pub function: String,
59    pub arguments: Vec<String>,
60    #[serde(default)]
61    pub constraint: bool,
62    #[serde(default)]
63    pub referenced_table: Option<String>,
64    #[serde(default)]
65    pub deferrability: TriggerDeferrability,
66    pub row: bool,
67    pub timing: TriggerTiming,
68    pub events: Vec<TriggerEvent>,
69    pub update_columns: Vec<String>,
70    #[serde(default)]
71    pub transition_relations: Vec<TriggerTransitionRelation>,
72    pub when: Option<Expr>,
73    pub or_replace: bool,
74}
75
76impl CreateTrigger {
77    #[must_use]
78    pub fn old_transition_table(&self) -> Option<&str> {
79        self.transition_relations
80            .iter()
81            .find(|relation| relation.is_table && !relation.is_new)
82            .map(|relation| relation.name.as_str())
83    }
84
85    #[must_use]
86    pub fn new_transition_table(&self) -> Option<&str> {
87        self.transition_relations
88            .iter()
89            .find(|relation| relation.is_table && relation.is_new)
90            .map(|relation| relation.name.as_str())
91    }
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct DropTrigger {
96    pub name: String,
97    pub table: String,
98    pub if_exists: bool,
99    pub cascade: bool,
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
103pub enum RuleEvent {
104    Select,
105    Insert,
106    Update,
107    Delete,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct CreateRule {
112    pub name: String,
113    pub table: String,
114    pub event: RuleEvent,
115    pub instead: bool,
116    pub condition: Option<Expr>,
117    #[serde(default, skip_serializing_if = "Option::is_none")]
118    pub condition_sql: Option<String>,
119    pub actions: Vec<Statement>,
120    #[serde(default)]
121    pub action_sql: Vec<String>,
122    pub or_replace: bool,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct DropRule {
127    pub name: String,
128    pub table: String,
129    pub if_exists: bool,
130    pub cascade: bool,
131}
132
133#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
134pub enum EventEnableMode {
135    #[default]
136    Origin,
137    Disabled,
138    Replica,
139    Always,
140}
141
142impl EventEnableMode {
143    #[must_use]
144    pub const fn catalog_code(self) -> &'static str {
145        match self {
146            Self::Origin => "O",
147            Self::Disabled => "D",
148            Self::Replica => "R",
149            Self::Always => "A",
150        }
151    }
152
153    #[must_use]
154    pub const fn fires_in_origin(self) -> bool {
155        matches!(self, Self::Origin | Self::Always)
156    }
157
158    #[must_use]
159    pub const fn fires_in_replica(self) -> bool {
160        matches!(self, Self::Replica | Self::Always)
161    }
162}