Skip to main content

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 {}