Skip to main content

reinhardt_query/query/procedure/
drop_procedure.rs

1//! DROP PROCEDURE statement builder
2//!
3//! This module provides the `DropProcedureStatement` type for building SQL DROP PROCEDURE queries.
4
5use crate::{
6	backend::QueryBuilder,
7	types::{DynIden, IntoIden, procedure::ProcedureParameter},
8};
9
10use crate::query::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
11
12/// DROP PROCEDURE statement builder
13///
14/// This struct provides a fluent API for constructing DROP PROCEDURE queries.
15///
16/// # Examples
17///
18/// ```rust
19/// use reinhardt_query::prelude::*;
20///
21/// // DROP PROCEDURE my_proc
22/// let query = Query::drop_procedure()
23///     .name("my_proc");
24///
25/// // DROP PROCEDURE IF EXISTS my_proc(integer) CASCADE
26/// let query = Query::drop_procedure()
27///     .name("my_proc")
28///     .if_exists()
29///     .add_parameter("", "integer")
30///     .cascade();
31/// ```
32#[derive(Debug, Clone)]
33pub struct DropProcedureStatement {
34	pub(crate) name: Option<DynIden>,
35	pub(crate) parameters: Vec<ProcedureParameter>,
36	pub(crate) if_exists: bool,
37	pub(crate) cascade: bool,
38}
39
40impl DropProcedureStatement {
41	/// Create a new DROP PROCEDURE statement
42	///
43	/// # Examples
44	///
45	/// ```rust
46	/// use reinhardt_query::prelude::*;
47	///
48	/// let query = Query::drop_procedure();
49	/// ```
50	pub fn new() -> Self {
51		Self {
52			name: None,
53			parameters: Vec::new(),
54			if_exists: false,
55			cascade: false,
56		}
57	}
58
59	/// Take the ownership of data in the current [`DropProcedureStatement`]
60	pub fn take(&mut self) -> Self {
61		let taken = Self {
62			name: self.name.take(),
63			parameters: self.parameters.clone(),
64			if_exists: self.if_exists,
65			cascade: self.cascade,
66		};
67		// Reset self to empty state
68		self.name = None;
69		self.parameters.clear();
70		self.if_exists = false;
71		self.cascade = false;
72		taken
73	}
74
75	/// Set the procedure name
76	///
77	/// # Examples
78	///
79	/// ```rust
80	/// use reinhardt_query::prelude::*;
81	///
82	/// let query = Query::drop_procedure()
83	///     .name("my_proc");
84	/// ```
85	pub fn name<N>(&mut self, name: N) -> &mut Self
86	where
87		N: IntoIden,
88	{
89		self.name = Some(name.into_iden());
90		self
91	}
92
93	/// Add a procedure parameter (for identifying which overloaded procedure to drop)
94	///
95	/// # Examples
96	///
97	/// ```rust
98	/// use reinhardt_query::prelude::*;
99	///
100	/// // DROP PROCEDURE my_proc(integer, text)
101	/// let query = Query::drop_procedure()
102	///     .name("my_proc")
103	///     .add_parameter("", "integer")
104	///     .add_parameter("", "text");
105	/// ```
106	pub fn add_parameter<N: IntoIden, T: Into<String>>(
107		&mut self,
108		name: N,
109		param_type: T,
110	) -> &mut Self {
111		self.parameters.push(ProcedureParameter {
112			name: Some(name.into_iden()),
113			param_type: Some(param_type.into()),
114			mode: None,
115			default_value: None,
116		});
117		self
118	}
119
120	/// Add IF EXISTS clause
121	///
122	/// # Examples
123	///
124	/// ```rust
125	/// use reinhardt_query::prelude::*;
126	///
127	/// let query = Query::drop_procedure()
128	///     .name("my_proc")
129	///     .if_exists();
130	/// ```
131	pub fn if_exists(&mut self) -> &mut Self {
132		self.if_exists = true;
133		self
134	}
135
136	/// Add CASCADE clause
137	///
138	/// # Examples
139	///
140	/// ```rust
141	/// use reinhardt_query::prelude::*;
142	///
143	/// let query = Query::drop_procedure()
144	///     .name("my_proc")
145	///     .cascade();
146	/// ```
147	pub fn cascade(&mut self) -> &mut Self {
148		self.cascade = true;
149		self
150	}
151}
152
153impl Default for DropProcedureStatement {
154	fn default() -> Self {
155		Self::new()
156	}
157}
158
159impl QueryStatementBuilder for DropProcedureStatement {
160	fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, crate::value::Values) {
161		// Downcast to concrete QueryBuilder type
162		use std::any::Any;
163		if let Some(builder) =
164			(query_builder as &dyn Any).downcast_ref::<crate::backend::PostgresQueryBuilder>()
165		{
166			return builder.build_drop_procedure(self);
167		}
168		if let Some(builder) =
169			(query_builder as &dyn Any).downcast_ref::<crate::backend::MySqlQueryBuilder>()
170		{
171			return builder.build_drop_procedure(self);
172		}
173		if let Some(builder) =
174			(query_builder as &dyn Any).downcast_ref::<crate::backend::SqliteQueryBuilder>()
175		{
176			return builder.build_drop_procedure(self);
177		}
178		if let Some(builder) =
179			(query_builder as &dyn Any).downcast_ref::<crate::backend::CockroachDBQueryBuilder>()
180		{
181			return builder.build_drop_procedure(self);
182		}
183		panic!("Unsupported query builder type");
184	}
185}
186
187impl QueryStatementWriter for DropProcedureStatement {}
188
189#[cfg(test)]
190mod tests {
191	use super::*;
192	use rstest::*;
193
194	#[rstest]
195	fn test_drop_procedure_new() {
196		let stmt = DropProcedureStatement::new();
197		assert!(stmt.name.is_none());
198		assert!(stmt.parameters.is_empty());
199		assert!(!stmt.if_exists);
200		assert!(!stmt.cascade);
201	}
202
203	#[rstest]
204	fn test_drop_procedure_with_name() {
205		let mut stmt = DropProcedureStatement::new();
206		stmt.name("my_proc");
207		assert_eq!(stmt.name.as_ref().unwrap().to_string(), "my_proc");
208	}
209
210	#[rstest]
211	fn test_drop_procedure_if_exists() {
212		let mut stmt = DropProcedureStatement::new();
213		stmt.name("my_proc").if_exists();
214		assert!(stmt.if_exists);
215	}
216
217	#[rstest]
218	fn test_drop_procedure_cascade() {
219		let mut stmt = DropProcedureStatement::new();
220		stmt.name("my_proc").cascade();
221		assert!(stmt.cascade);
222	}
223
224	#[rstest]
225	fn test_drop_procedure_with_parameters() {
226		let mut stmt = DropProcedureStatement::new();
227		stmt.name("my_proc")
228			.add_parameter("", "integer")
229			.add_parameter("", "text");
230		assert_eq!(stmt.parameters.len(), 2);
231		assert_eq!(stmt.parameters[0].param_type.as_ref().unwrap(), "integer");
232		assert_eq!(stmt.parameters[1].param_type.as_ref().unwrap(), "text");
233	}
234
235	#[rstest]
236	fn test_drop_procedure_all_options() {
237		let mut stmt = DropProcedureStatement::new();
238		stmt.name("my_proc")
239			.if_exists()
240			.add_parameter("", "integer")
241			.cascade();
242		assert_eq!(stmt.name.as_ref().unwrap().to_string(), "my_proc");
243		assert!(stmt.if_exists);
244		assert!(stmt.cascade);
245		assert_eq!(stmt.parameters.len(), 1);
246	}
247
248	#[rstest]
249	fn test_drop_procedure_take() {
250		let mut stmt = DropProcedureStatement::new();
251		stmt.name("my_proc").cascade();
252		let taken = stmt.take();
253		assert!(stmt.name.is_none());
254		assert!(!stmt.cascade);
255		assert_eq!(taken.name.as_ref().unwrap().to_string(), "my_proc");
256		assert!(taken.cascade);
257	}
258}