Skip to main content

reinhardt_query/query/maintenance/
vacuum.rs

1//! VACUUM statement builder
2//!
3//! This module provides the `VacuumStatement` type for building SQL VACUUM queries.
4
5use crate::{
6	backend::QueryBuilder,
7	types::{DynIden, IntoIden, VacuumOption},
8};
9
10use crate::query::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
11
12/// VACUUM statement builder
13///
14/// This struct provides a fluent API for constructing VACUUM queries.
15/// VACUUM reclaims storage and optionally analyzes a database.
16///
17/// # Examples
18///
19/// ```rust
20/// use reinhardt_query::prelude::*;
21///
22/// // VACUUM (all tables)
23/// let query = Query::vacuum();
24///
25/// // VACUUM users
26/// let query = Query::vacuum()
27///     .table("users");
28///
29/// // VACUUM FULL users
30/// let query = Query::vacuum()
31///     .table("users")
32///     .full();
33///
34/// // VACUUM FULL ANALYZE users
35/// let query = Query::vacuum()
36///     .table("users")
37///     .full()
38///     .analyze();
39/// ```
40#[derive(Debug, Clone, Default)]
41pub struct VacuumStatement {
42	pub(crate) tables: Vec<DynIden>,
43	pub(crate) full: bool,
44	pub(crate) freeze: bool,
45	pub(crate) verbose: bool,
46	pub(crate) analyze: bool,
47}
48
49impl VacuumStatement {
50	/// Create a new VACUUM statement
51	///
52	/// # Examples
53	///
54	/// ```rust
55	/// use reinhardt_query::prelude::*;
56	///
57	/// let query = Query::vacuum();
58	/// ```
59	pub fn new() -> Self {
60		Self::default()
61	}
62
63	/// Take the ownership of data in the current [`VacuumStatement`]
64	pub fn take(&mut self) -> Self {
65		Self {
66			tables: std::mem::take(&mut self.tables),
67			full: std::mem::take(&mut self.full),
68			freeze: std::mem::take(&mut self.freeze),
69			verbose: std::mem::take(&mut self.verbose),
70			analyze: std::mem::take(&mut self.analyze),
71		}
72	}
73
74	/// Add a table to vacuum
75	///
76	/// # Examples
77	///
78	/// ```rust
79	/// use reinhardt_query::prelude::*;
80	///
81	/// let query = Query::vacuum()
82	///     .table("users");
83	/// ```
84	pub fn table<T>(&mut self, table: T) -> &mut Self
85	where
86		T: IntoIden,
87	{
88		self.tables.push(table.into_iden());
89		self
90	}
91
92	/// Set FULL option
93	///
94	/// # Examples
95	///
96	/// ```rust
97	/// use reinhardt_query::prelude::*;
98	///
99	/// let query = Query::vacuum()
100	///     .full();
101	/// ```
102	pub fn full(&mut self) -> &mut Self {
103		self.full = true;
104		self
105	}
106
107	/// Set FREEZE option
108	///
109	/// # Examples
110	///
111	/// ```rust
112	/// use reinhardt_query::prelude::*;
113	///
114	/// let query = Query::vacuum()
115	///     .freeze();
116	/// ```
117	pub fn freeze(&mut self) -> &mut Self {
118		self.freeze = true;
119		self
120	}
121
122	/// Set VERBOSE option
123	///
124	/// # Examples
125	///
126	/// ```rust
127	/// use reinhardt_query::prelude::*;
128	///
129	/// let query = Query::vacuum()
130	///     .verbose();
131	/// ```
132	pub fn verbose(&mut self) -> &mut Self {
133		self.verbose = true;
134		self
135	}
136
137	/// Set ANALYZE option
138	///
139	/// # Examples
140	///
141	/// ```rust
142	/// use reinhardt_query::prelude::*;
143	///
144	/// let query = Query::vacuum()
145	///     .analyze();
146	/// ```
147	pub fn analyze(&mut self) -> &mut Self {
148		self.analyze = true;
149		self
150	}
151
152	/// Set options from VacuumOption
153	///
154	/// # Examples
155	///
156	/// ```rust
157	/// use reinhardt_query::prelude::*;
158	/// use reinhardt_query::types::VacuumOption;
159	///
160	/// let opt = VacuumOption::new().full(true).analyze(true);
161	/// let query = Query::vacuum()
162	///     .table("users")
163	///     .options(opt);
164	/// ```
165	pub fn options(&mut self, opt: VacuumOption) -> &mut Self {
166		self.full = opt.full;
167		self.freeze = opt.freeze;
168		self.verbose = opt.verbose;
169		self.analyze = opt.analyze;
170		self
171	}
172}
173
174impl QueryStatementBuilder for VacuumStatement {
175	fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, crate::value::Values) {
176		// Downcast to concrete QueryBuilder type
177		use std::any::Any;
178		if let Some(builder) =
179			(query_builder as &dyn Any).downcast_ref::<crate::backend::PostgresQueryBuilder>()
180		{
181			return builder.build_vacuum(self);
182		}
183		if let Some(builder) =
184			(query_builder as &dyn Any).downcast_ref::<crate::backend::MySqlQueryBuilder>()
185		{
186			return builder.build_vacuum(self);
187		}
188		if let Some(builder) =
189			(query_builder as &dyn Any).downcast_ref::<crate::backend::SqliteQueryBuilder>()
190		{
191			return builder.build_vacuum(self);
192		}
193		if let Some(builder) =
194			(query_builder as &dyn Any).downcast_ref::<crate::backend::CockroachDBQueryBuilder>()
195		{
196			return builder.build_vacuum(self);
197		}
198		panic!("Unsupported query builder type");
199	}
200}
201
202impl QueryStatementWriter for VacuumStatement {}
203
204#[cfg(test)]
205mod tests {
206	use super::*;
207	use rstest::*;
208
209	#[rstest]
210	fn test_vacuum_new() {
211		let stmt = VacuumStatement::new();
212		assert!(stmt.tables.is_empty());
213		assert!(!stmt.full);
214		assert!(!stmt.freeze);
215		assert!(!stmt.verbose);
216		assert!(!stmt.analyze);
217	}
218
219	#[rstest]
220	fn test_vacuum_with_table() {
221		let mut stmt = VacuumStatement::new();
222		stmt.table("users");
223		assert_eq!(stmt.tables.len(), 1);
224		assert_eq!(stmt.tables[0].to_string(), "users");
225	}
226
227	#[rstest]
228	fn test_vacuum_with_multiple_tables() {
229		let mut stmt = VacuumStatement::new();
230		stmt.table("users").table("posts");
231		assert_eq!(stmt.tables.len(), 2);
232		assert_eq!(stmt.tables[0].to_string(), "users");
233		assert_eq!(stmt.tables[1].to_string(), "posts");
234	}
235
236	#[rstest]
237	fn test_vacuum_full() {
238		let mut stmt = VacuumStatement::new();
239		stmt.full();
240		assert!(stmt.full);
241		assert!(!stmt.freeze);
242		assert!(!stmt.verbose);
243		assert!(!stmt.analyze);
244	}
245
246	#[rstest]
247	fn test_vacuum_freeze() {
248		let mut stmt = VacuumStatement::new();
249		stmt.freeze();
250		assert!(!stmt.full);
251		assert!(stmt.freeze);
252		assert!(!stmt.verbose);
253		assert!(!stmt.analyze);
254	}
255
256	#[rstest]
257	fn test_vacuum_verbose() {
258		let mut stmt = VacuumStatement::new();
259		stmt.verbose();
260		assert!(!stmt.full);
261		assert!(!stmt.freeze);
262		assert!(stmt.verbose);
263		assert!(!stmt.analyze);
264	}
265
266	#[rstest]
267	fn test_vacuum_analyze() {
268		let mut stmt = VacuumStatement::new();
269		stmt.analyze();
270		assert!(!stmt.full);
271		assert!(!stmt.freeze);
272		assert!(!stmt.verbose);
273		assert!(stmt.analyze);
274	}
275
276	#[rstest]
277	fn test_vacuum_combined_options() {
278		let mut stmt = VacuumStatement::new();
279		stmt.table("users").full().freeze().verbose().analyze();
280		assert_eq!(stmt.tables.len(), 1);
281		assert_eq!(stmt.tables[0].to_string(), "users");
282		assert!(stmt.full);
283		assert!(stmt.freeze);
284		assert!(stmt.verbose);
285		assert!(stmt.analyze);
286	}
287
288	#[rstest]
289	fn test_vacuum_with_vacuum_option() {
290		let opt = VacuumOption::new().full(true).analyze(true);
291		let mut stmt = VacuumStatement::new();
292		stmt.table("users").options(opt);
293		assert_eq!(stmt.tables.len(), 1);
294		assert!(stmt.full);
295		assert!(!stmt.freeze);
296		assert!(!stmt.verbose);
297		assert!(stmt.analyze);
298	}
299
300	#[rstest]
301	fn test_vacuum_take() {
302		let mut stmt = VacuumStatement::new();
303		stmt.table("users").full().analyze();
304
305		let taken = stmt.take();
306		assert_eq!(taken.tables.len(), 1);
307		assert!(taken.full);
308		assert!(taken.analyze);
309
310		// Original should be reset
311		assert!(stmt.tables.is_empty());
312		assert!(!stmt.full);
313		assert!(!stmt.analyze);
314	}
315}