elefant_tools/models/
trigger.rs

1use crate::helpers::StringExt;
2use crate::object_id::ObjectId;
3use crate::postgres_client_wrapper::FromPgChar;
4use crate::quoting::AttemptedKeywordUsage::{ColumnName, TypeOrFunctionName};
5use crate::quoting::{quote_value_string, IdentifierQuoter, Quotable};
6use crate::{ElefantToolsError, PostgresSchema};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Eq, PartialEq, Default, Clone, Serialize, Deserialize)]
10pub struct PostgresTrigger {
11    pub name: String,
12    pub table_name: String,
13    pub events: Vec<PostgresTriggerEvent>,
14    pub timing: PostgresTriggerTiming,
15    pub level: PostgresTriggerLevel,
16    pub function_name: String,
17    pub condition: Option<String>,
18    pub old_table_name: Option<String>,
19    pub new_table_name: Option<String>,
20    pub comment: Option<String>,
21    pub object_id: ObjectId,
22    pub arguments: Option<String>,
23}
24
25impl PostgresTrigger {
26    pub fn get_create_statement(
27        &self,
28        schema: &PostgresSchema,
29        identifier_quoter: &IdentifierQuoter,
30    ) -> String {
31        let mut sql = "create trigger ".to_string();
32
33        sql.push_str(&self.name.quote(identifier_quoter, ColumnName));
34        sql.push(' ');
35        sql.push_str(match self.timing {
36            PostgresTriggerTiming::Before => "before",
37            PostgresTriggerTiming::After => "after",
38            PostgresTriggerTiming::InsteadOf => "instead of",
39        });
40        sql.push(' ');
41
42        sql.push_join(" or ", self.events.iter().map(|e| e.get_event_name()));
43
44        sql.push_str(" on ");
45        sql.push_str(&schema.name.quote(identifier_quoter, ColumnName));
46        sql.push('.');
47        sql.push_str(&self.table_name.quote(identifier_quoter, ColumnName));
48        sql.push_str(" for each ");
49        sql.push_str(match self.level {
50            PostgresTriggerLevel::Row => "row",
51            PostgresTriggerLevel::Statement => "statement",
52        });
53
54        if let Some(cond) = &self.condition {
55            sql.push_str(" when (");
56            sql.push_str(cond);
57            sql.push(')');
58        }
59
60        sql.push_str(" execute function ");
61        sql.push_str(
62            &self
63                .function_name
64                .quote(identifier_quoter, TypeOrFunctionName),
65        );
66        sql.push('(');
67
68        if let Some(args) = &self.arguments {
69            sql.push_str(args);
70        }
71
72        sql.push_str(");");
73
74        if let Some(comment) = &self.comment {
75            sql.push_str("\ncomment on trigger ");
76            sql.push_str(&self.name.quote(identifier_quoter, ColumnName));
77            sql.push_str(" on ");
78            sql.push_str(&schema.name.quote(identifier_quoter, ColumnName));
79            sql.push('.');
80            sql.push_str(&self.table_name.quote(identifier_quoter, ColumnName));
81            sql.push_str(" is ");
82            sql.push_str(&quote_value_string(comment));
83            sql.push(';');
84        }
85
86        sql
87    }
88}
89
90#[derive(Debug, Eq, PartialEq, Default, Clone, Serialize, Deserialize)]
91pub enum PostgresTriggerEvent {
92    #[default]
93    Insert,
94    Update,
95    Delete,
96    Truncate,
97}
98
99impl FromPgChar for PostgresTriggerEvent {
100    fn from_pg_char(c: char) -> Result<Self, ElefantToolsError> {
101        match c {
102            'i' => Ok(PostgresTriggerEvent::Insert),
103            'u' => Ok(PostgresTriggerEvent::Update),
104            'd' => Ok(PostgresTriggerEvent::Delete),
105            't' => Ok(PostgresTriggerEvent::Truncate),
106            _ => Err(ElefantToolsError::UnknownTriggerEvent(c.to_string())),
107        }
108    }
109}
110
111impl PostgresTriggerEvent {
112    fn get_event_name(&self) -> &str {
113        match self {
114            PostgresTriggerEvent::Insert => "insert",
115            PostgresTriggerEvent::Update => "update",
116            PostgresTriggerEvent::Delete => "delete",
117            PostgresTriggerEvent::Truncate => "truncate",
118        }
119    }
120}
121
122#[derive(Debug, Eq, PartialEq, Default, Clone, Serialize, Deserialize)]
123pub enum PostgresTriggerTiming {
124    #[default]
125    Before,
126    After,
127    InsteadOf,
128}
129
130impl FromPgChar for PostgresTriggerTiming {
131    fn from_pg_char(c: char) -> Result<Self, ElefantToolsError> {
132        match c {
133            'b' => Ok(PostgresTriggerTiming::Before),
134            'a' => Ok(PostgresTriggerTiming::After),
135            'i' => Ok(PostgresTriggerTiming::InsteadOf),
136            _ => Err(ElefantToolsError::UnknownTriggerTiming(c.to_string())),
137        }
138    }
139}
140
141#[derive(Debug, Eq, PartialEq, Default, Clone, Serialize, Deserialize)]
142pub enum PostgresTriggerLevel {
143    #[default]
144    Row,
145    Statement,
146}
147
148impl FromPgChar for PostgresTriggerLevel {
149    fn from_pg_char(c: char) -> Result<Self, ElefantToolsError> {
150        match c {
151            'r' => Ok(PostgresTriggerLevel::Row),
152            's' => Ok(PostgresTriggerLevel::Statement),
153            _ => Err(ElefantToolsError::UnknownTriggerLevel(c.to_string())),
154        }
155    }
156}