reinhardt_query/query/create_trigger.rs
1//! CREATE TRIGGER statement builder
2//!
3//! This module provides the `CreateTriggerStatement` type for building SQL CREATE TRIGGER queries.
4
5use crate::{
6 backend::QueryBuilder,
7 expr::SimpleExpr,
8 types::{
9 DynIden, IntoIden, IntoTableRef, TableRef, TriggerBody, TriggerEvent, TriggerOrder,
10 TriggerScope, TriggerTiming,
11 },
12};
13
14use super::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
15
16/// CREATE TRIGGER statement builder
17///
18/// This struct provides a fluent API for constructing CREATE TRIGGER queries.
19///
20/// # Backend Support
21///
22/// - **PostgreSQL**: Full support (BEFORE/AFTER/INSTEAD OF, FOR EACH ROW/STATEMENT, WHEN clause)
23/// - **MySQL**: Basic support (BEFORE/AFTER, FOR EACH ROW only, FOLLOWS/PRECEDES)
24/// - **SQLite**: Basic support (BEFORE/AFTER/INSTEAD OF, FOR EACH ROW, WHEN clause)
25///
26/// # Examples
27///
28/// ```rust,ignore
29/// use reinhardt_query::prelude::*;
30/// use reinhardt_query::types::{TriggerEvent, TriggerTiming, TriggerScope, TriggerBody};
31///
32/// // PostgreSQL: Call a function when a row is inserted
33/// let query = Query::create_trigger()
34/// .name("audit_insert")
35/// .timing(TriggerTiming::After)
36/// .event(TriggerEvent::Insert)
37/// .on_table("users")
38/// .for_each(TriggerScope::Row)
39/// .execute_function("audit_log_insert");
40///
41/// // MySQL: Multiple statements on update
42/// let query = Query::create_trigger()
43/// .name("update_timestamp")
44/// .timing(TriggerTiming::Before)
45/// .event(TriggerEvent::Update { columns: None })
46/// .on_table("users")
47/// .for_each(TriggerScope::Row)
48/// .body(TriggerBody::multiple(vec![
49/// "SET NEW.updated_at = NOW()",
50/// ]));
51/// ```
52#[derive(Debug, Clone)]
53pub struct CreateTriggerStatement {
54 pub(crate) name: Option<DynIden>,
55 pub(crate) timing: Option<TriggerTiming>,
56 pub(crate) events: Vec<TriggerEvent>,
57 pub(crate) table: Option<TableRef>,
58 pub(crate) scope: Option<TriggerScope>,
59 pub(crate) when_condition: Option<SimpleExpr>,
60 pub(crate) body: Option<TriggerBody>,
61 pub(crate) order: Option<TriggerOrder>,
62}
63
64impl CreateTriggerStatement {
65 /// Create a new CREATE TRIGGER statement
66 pub fn new() -> Self {
67 Self {
68 name: None,
69 timing: None,
70 events: Vec::new(),
71 table: None,
72 scope: None,
73 when_condition: None,
74 body: None,
75 order: None,
76 }
77 }
78
79 /// Take the ownership of data in the current [`CreateTriggerStatement`]
80 pub fn take(&mut self) -> Self {
81 Self {
82 name: self.name.take(),
83 timing: self.timing.take(),
84 events: std::mem::take(&mut self.events),
85 table: self.table.take(),
86 scope: self.scope.take(),
87 when_condition: self.when_condition.take(),
88 body: self.body.take(),
89 order: self.order.take(),
90 }
91 }
92
93 /// Set the trigger name
94 ///
95 /// # Examples
96 ///
97 /// ```rust,ignore
98 /// use reinhardt_query::prelude::*;
99 ///
100 /// let query = Query::create_trigger()
101 /// .name("audit_insert");
102 /// ```
103 pub fn name<N>(&mut self, name: N) -> &mut Self
104 where
105 N: IntoIden,
106 {
107 self.name = Some(name.into_iden());
108 self
109 }
110
111 /// Set the trigger timing (BEFORE, AFTER, INSTEAD OF)
112 ///
113 /// # Examples
114 ///
115 /// ```rust,ignore
116 /// use reinhardt_query::prelude::*;
117 /// use reinhardt_query::types::TriggerTiming;
118 ///
119 /// let query = Query::create_trigger()
120 /// .timing(TriggerTiming::Before);
121 /// ```
122 pub fn timing(&mut self, timing: TriggerTiming) -> &mut Self {
123 self.timing = Some(timing);
124 self
125 }
126
127 /// Add a trigger event (INSERT, UPDATE, DELETE)
128 ///
129 /// Can be called multiple times to add multiple events (PostgreSQL only).
130 ///
131 /// # Examples
132 ///
133 /// ```rust,ignore
134 /// use reinhardt_query::prelude::*;
135 /// use reinhardt_query::types::TriggerEvent;
136 ///
137 /// let query = Query::create_trigger()
138 /// .event(TriggerEvent::Insert)
139 /// .event(TriggerEvent::Update { columns: None });
140 /// ```
141 pub fn event(&mut self, event: TriggerEvent) -> &mut Self {
142 self.events.push(event);
143 self
144 }
145
146 /// Set the table on which the trigger operates
147 ///
148 /// # Examples
149 ///
150 /// ```rust,ignore
151 /// use reinhardt_query::prelude::*;
152 ///
153 /// let query = Query::create_trigger()
154 /// .on_table("users");
155 /// ```
156 pub fn on_table<T>(&mut self, table: T) -> &mut Self
157 where
158 T: IntoTableRef,
159 {
160 self.table = Some(table.into_table_ref());
161 self
162 }
163
164 /// Set the trigger scope (FOR EACH ROW or FOR EACH STATEMENT)
165 ///
166 /// # Examples
167 ///
168 /// ```rust,ignore
169 /// use reinhardt_query::prelude::*;
170 /// use reinhardt_query::types::TriggerScope;
171 ///
172 /// let query = Query::create_trigger()
173 /// .for_each(TriggerScope::Row);
174 /// ```
175 pub fn for_each(&mut self, scope: TriggerScope) -> &mut Self {
176 self.scope = Some(scope);
177 self
178 }
179
180 /// Set the WHEN condition (optional filter for when trigger fires)
181 ///
182 /// # Examples
183 ///
184 /// ```rust,ignore
185 /// use reinhardt_query::prelude::*;
186 ///
187 /// let query = Query::create_trigger()
188 /// .when_condition(Expr::col("status").eq("active"));
189 /// ```
190 pub fn when_condition(&mut self, condition: SimpleExpr) -> &mut Self {
191 self.when_condition = Some(condition);
192 self
193 }
194
195 /// Set the trigger body (SQL statements to execute)
196 ///
197 /// # Examples
198 ///
199 /// ```rust,ignore
200 /// use reinhardt_query::prelude::*;
201 /// use reinhardt_query::types::TriggerBody;
202 ///
203 /// let query = Query::create_trigger()
204 /// .body(TriggerBody::single("UPDATE counters SET count = count + 1"));
205 /// ```
206 pub fn body(&mut self, body: TriggerBody) -> &mut Self {
207 self.body = Some(body);
208 self
209 }
210
211 /// Set the PostgreSQL function to execute (EXECUTE FUNCTION function_name())
212 ///
213 /// This is a convenience method for PostgreSQL triggers.
214 ///
215 /// # Examples
216 ///
217 /// ```rust,ignore
218 /// use reinhardt_query::prelude::*;
219 ///
220 /// let query = Query::create_trigger()
221 /// .execute_function("audit_log_insert");
222 /// ```
223 pub fn execute_function<S: Into<String>>(&mut self, function_name: S) -> &mut Self {
224 self.body = Some(TriggerBody::postgres_function(function_name));
225 self
226 }
227
228 /// Set the MySQL trigger order (FOLLOWS or PRECEDES)
229 ///
230 /// MySQL-specific feature to control trigger execution order.
231 ///
232 /// # Examples
233 ///
234 /// ```rust,ignore
235 /// use reinhardt_query::prelude::*;
236 /// use reinhardt_query::types::TriggerOrder;
237 ///
238 /// let query = Query::create_trigger()
239 /// .order(TriggerOrder::Follows("other_trigger".to_string()));
240 /// ```
241 pub fn order(&mut self, order: TriggerOrder) -> &mut Self {
242 self.order = Some(order);
243 self
244 }
245}
246
247impl Default for CreateTriggerStatement {
248 fn default() -> Self {
249 Self::new()
250 }
251}
252
253impl QueryStatementBuilder for CreateTriggerStatement {
254 fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, crate::value::Values) {
255 // Downcast to concrete QueryBuilder type
256 use std::any::Any;
257 if let Some(builder) =
258 (query_builder as &dyn Any).downcast_ref::<crate::backend::PostgresQueryBuilder>()
259 {
260 return builder.build_create_trigger(self);
261 }
262 if let Some(builder) =
263 (query_builder as &dyn Any).downcast_ref::<crate::backend::MySqlQueryBuilder>()
264 {
265 return builder.build_create_trigger(self);
266 }
267 if let Some(builder) =
268 (query_builder as &dyn Any).downcast_ref::<crate::backend::SqliteQueryBuilder>()
269 {
270 return builder.build_create_trigger(self);
271 }
272 panic!("Unsupported query builder type");
273 }
274}
275
276impl QueryStatementWriter for CreateTriggerStatement {}