Skip to main content

reinhardt_query/query/procedure/
alter_procedure.rs

1//! ALTER PROCEDURE statement builder
2//!
3//! This module provides the `AlterProcedureStatement` type for building SQL ALTER PROCEDURE queries.
4
5use crate::{
6	backend::QueryBuilder,
7	types::{
8		DynIden, IntoIden,
9		function::{FunctionBehavior, FunctionSecurity},
10		procedure::{ProcedureOperation, ProcedureParameter},
11	},
12};
13
14use crate::query::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
15
16/// ALTER PROCEDURE statement builder
17///
18/// This struct provides a fluent API for constructing ALTER PROCEDURE queries.
19///
20/// # Examples
21///
22/// ```rust
23/// use reinhardt_query::prelude::*;
24///
25/// // ALTER PROCEDURE my_proc RENAME TO new_proc
26/// let query = Query::alter_procedure()
27///     .name("my_proc")
28///     .rename_to("new_proc");
29///
30/// // ALTER PROCEDURE my_proc OWNER TO new_owner
31/// let query = Query::alter_procedure()
32///     .name("my_proc")
33///     .owner_to("new_owner");
34/// ```
35#[derive(Debug, Clone)]
36pub struct AlterProcedureStatement {
37	pub(crate) name: Option<DynIden>,
38	pub(crate) parameters: Vec<ProcedureParameter>,
39	pub(crate) operation: Option<ProcedureOperation>,
40}
41
42impl AlterProcedureStatement {
43	/// Create a new ALTER PROCEDURE statement
44	///
45	/// # Examples
46	///
47	/// ```rust
48	/// use reinhardt_query::prelude::*;
49	///
50	/// let query = Query::alter_procedure();
51	/// ```
52	pub fn new() -> Self {
53		Self {
54			name: None,
55			parameters: Vec::new(),
56			operation: None,
57		}
58	}
59
60	/// Take the ownership of data in the current [`AlterProcedureStatement`]
61	pub fn take(&mut self) -> Self {
62		let taken = Self {
63			name: self.name.take(),
64			parameters: self.parameters.clone(),
65			operation: self.operation.take(),
66		};
67		// Reset self to empty state
68		self.name = None;
69		self.parameters.clear();
70		self.operation = None;
71		taken
72	}
73
74	/// Set the procedure name
75	///
76	/// # Examples
77	///
78	/// ```rust
79	/// use reinhardt_query::prelude::*;
80	///
81	/// let query = Query::alter_procedure()
82	///     .name("my_proc");
83	/// ```
84	pub fn name<N>(&mut self, name: N) -> &mut Self
85	where
86		N: IntoIden,
87	{
88		self.name = Some(name.into_iden());
89		self
90	}
91
92	/// Add a procedure parameter (for identifying which overloaded procedure to alter)
93	///
94	/// # Examples
95	///
96	/// ```rust
97	/// use reinhardt_query::prelude::*;
98	///
99	/// let query = Query::alter_procedure()
100	///     .name("my_proc")
101	///     .add_parameter("a", "integer")
102	///     .rename_to("new_proc");
103	/// ```
104	pub fn add_parameter<N: IntoIden, T: Into<String>>(
105		&mut self,
106		name: N,
107		param_type: T,
108	) -> &mut Self {
109		self.parameters.push(ProcedureParameter {
110			name: Some(name.into_iden()),
111			param_type: Some(param_type.into()),
112			mode: None,
113			default_value: None,
114		});
115		self
116	}
117
118	/// RENAME TO new_name
119	///
120	/// # Examples
121	///
122	/// ```rust
123	/// use reinhardt_query::prelude::*;
124	///
125	/// let query = Query::alter_procedure()
126	///     .name("my_proc")
127	///     .rename_to("new_proc");
128	/// ```
129	pub fn rename_to<N: IntoIden>(&mut self, new_name: N) -> &mut Self {
130		self.operation = Some(ProcedureOperation::RenameTo(new_name.into_iden()));
131		self
132	}
133
134	/// OWNER TO new_owner
135	///
136	/// # Examples
137	///
138	/// ```rust
139	/// use reinhardt_query::prelude::*;
140	///
141	/// let query = Query::alter_procedure()
142	///     .name("my_proc")
143	///     .owner_to("new_owner");
144	/// ```
145	pub fn owner_to<N: IntoIden>(&mut self, new_owner: N) -> &mut Self {
146		self.operation = Some(ProcedureOperation::OwnerTo(new_owner.into_iden()));
147		self
148	}
149
150	/// SET SCHEMA new_schema
151	///
152	/// # Examples
153	///
154	/// ```rust
155	/// use reinhardt_query::prelude::*;
156	///
157	/// let query = Query::alter_procedure()
158	///     .name("my_proc")
159	///     .set_schema("new_schema");
160	/// ```
161	pub fn set_schema<N: IntoIden>(&mut self, new_schema: N) -> &mut Self {
162		self.operation = Some(ProcedureOperation::SetSchema(new_schema.into_iden()));
163		self
164	}
165
166	/// Set behavior (IMMUTABLE/STABLE/VOLATILE)
167	///
168	/// # Examples
169	///
170	/// ```rust
171	/// use reinhardt_query::prelude::*;
172	/// use reinhardt_query::types::function::FunctionBehavior;
173	///
174	/// let query = Query::alter_procedure()
175	///     .name("my_proc")
176	///     .set_behavior(FunctionBehavior::Immutable);
177	/// ```
178	pub fn set_behavior(&mut self, behavior: FunctionBehavior) -> &mut Self {
179		self.operation = Some(ProcedureOperation::SetBehavior(behavior));
180		self
181	}
182
183	/// Set security (DEFINER/INVOKER)
184	///
185	/// # Examples
186	///
187	/// ```rust
188	/// use reinhardt_query::prelude::*;
189	/// use reinhardt_query::types::function::FunctionSecurity;
190	///
191	/// let query = Query::alter_procedure()
192	///     .name("my_proc")
193	///     .set_security(FunctionSecurity::Definer);
194	/// ```
195	pub fn set_security(&mut self, security: FunctionSecurity) -> &mut Self {
196		self.operation = Some(ProcedureOperation::SetSecurity(security));
197		self
198	}
199}
200
201impl Default for AlterProcedureStatement {
202	fn default() -> Self {
203		Self::new()
204	}
205}
206
207impl QueryStatementBuilder for AlterProcedureStatement {
208	fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, crate::value::Values) {
209		// Downcast to concrete QueryBuilder type
210		use std::any::Any;
211		if let Some(builder) =
212			(query_builder as &dyn Any).downcast_ref::<crate::backend::PostgresQueryBuilder>()
213		{
214			return builder.build_alter_procedure(self);
215		}
216		if let Some(builder) =
217			(query_builder as &dyn Any).downcast_ref::<crate::backend::MySqlQueryBuilder>()
218		{
219			return builder.build_alter_procedure(self);
220		}
221		if let Some(builder) =
222			(query_builder as &dyn Any).downcast_ref::<crate::backend::SqliteQueryBuilder>()
223		{
224			return builder.build_alter_procedure(self);
225		}
226		if let Some(builder) =
227			(query_builder as &dyn Any).downcast_ref::<crate::backend::CockroachDBQueryBuilder>()
228		{
229			return builder.build_alter_procedure(self);
230		}
231		panic!("Unsupported query builder type");
232	}
233}
234
235impl QueryStatementWriter for AlterProcedureStatement {}
236
237#[cfg(test)]
238mod tests {
239	use super::*;
240	use rstest::*;
241
242	#[rstest]
243	fn test_alter_procedure_new() {
244		let stmt = AlterProcedureStatement::new();
245		assert!(stmt.name.is_none());
246		assert!(stmt.parameters.is_empty());
247		assert!(stmt.operation.is_none());
248	}
249
250	#[rstest]
251	fn test_alter_procedure_with_name() {
252		let mut stmt = AlterProcedureStatement::new();
253		stmt.name("my_proc");
254		assert_eq!(stmt.name.as_ref().unwrap().to_string(), "my_proc");
255	}
256
257	#[rstest]
258	fn test_alter_procedure_rename_to() {
259		let mut stmt = AlterProcedureStatement::new();
260		stmt.name("my_proc").rename_to("new_proc");
261		assert_eq!(stmt.name.as_ref().unwrap().to_string(), "my_proc");
262		assert!(matches!(
263			stmt.operation,
264			Some(ProcedureOperation::RenameTo(_))
265		));
266	}
267
268	#[rstest]
269	fn test_alter_procedure_owner_to() {
270		let mut stmt = AlterProcedureStatement::new();
271		stmt.name("my_proc").owner_to("new_owner");
272		assert!(matches!(
273			stmt.operation,
274			Some(ProcedureOperation::OwnerTo(_))
275		));
276	}
277
278	#[rstest]
279	fn test_alter_procedure_set_schema() {
280		let mut stmt = AlterProcedureStatement::new();
281		stmt.name("my_proc").set_schema("new_schema");
282		assert!(matches!(
283			stmt.operation,
284			Some(ProcedureOperation::SetSchema(_))
285		));
286	}
287
288	#[rstest]
289	fn test_alter_procedure_set_behavior() {
290		use crate::types::function::FunctionBehavior;
291
292		let mut stmt = AlterProcedureStatement::new();
293		stmt.name("my_proc")
294			.set_behavior(FunctionBehavior::Immutable);
295		assert!(matches!(
296			stmt.operation,
297			Some(ProcedureOperation::SetBehavior(FunctionBehavior::Immutable))
298		));
299	}
300
301	#[rstest]
302	fn test_alter_procedure_set_security() {
303		use crate::types::function::FunctionSecurity;
304
305		let mut stmt = AlterProcedureStatement::new();
306		stmt.name("my_proc").set_security(FunctionSecurity::Definer);
307		assert!(matches!(
308			stmt.operation,
309			Some(ProcedureOperation::SetSecurity(FunctionSecurity::Definer))
310		));
311	}
312
313	#[rstest]
314	fn test_alter_procedure_add_parameter() {
315		let mut stmt = AlterProcedureStatement::new();
316		stmt.name("my_proc")
317			.add_parameter("a", "integer")
318			.rename_to("new_proc");
319		assert_eq!(stmt.parameters.len(), 1);
320		assert_eq!(stmt.parameters[0].name.as_ref().unwrap().to_string(), "a");
321		assert_eq!(stmt.parameters[0].param_type.as_ref().unwrap(), "integer");
322	}
323
324	#[rstest]
325	fn test_alter_procedure_take() {
326		let mut stmt = AlterProcedureStatement::new();
327		stmt.name("my_proc").rename_to("new_proc");
328		let taken = stmt.take();
329		assert!(stmt.name.is_none());
330		assert!(stmt.operation.is_none());
331		assert_eq!(taken.name.as_ref().unwrap().to_string(), "my_proc");
332	}
333}