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("e_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}