Skip to main content

reinhardt_query/query/maintenance/
optimize_table.rs

1//! OPTIMIZE TABLE statement builder
2//!
3//! This module provides the `OptimizeTableStatement` type for building SQL OPTIMIZE TABLE queries.
4//! **MySQL-only**: This statement is specific to MySQL and MariaDB.
5
6use crate::{
7	backend::QueryBuilder,
8	types::{DynIden, IntoIden, OptimizeTableOption},
9};
10
11use crate::query::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
12
13/// OPTIMIZE TABLE statement builder
14///
15/// This struct provides a fluent API for constructing OPTIMIZE TABLE queries.
16/// OPTIMIZE TABLE reorganizes the physical storage of table data and associated index data.
17///
18/// **MySQL-only**: Other backends will panic with a helpful error message.
19///
20/// # Examples
21///
22/// ```rust
23/// use reinhardt_query::prelude::*;
24///
25/// // OPTIMIZE TABLE users
26/// let query = Query::optimize_table()
27///     .table("users");
28///
29/// // OPTIMIZE NO_WRITE_TO_BINLOG TABLE users, posts
30/// let query = Query::optimize_table()
31///     .table("users")
32///     .table("posts")
33///     .no_write_to_binlog();
34///
35/// // OPTIMIZE LOCAL TABLE users
36/// let query = Query::optimize_table()
37///     .table("users")
38///     .local();
39/// ```
40#[derive(Debug, Clone, Default)]
41pub struct OptimizeTableStatement {
42	pub(crate) tables: Vec<DynIden>,
43	pub(crate) no_write_to_binlog: bool,
44	pub(crate) local: bool,
45}
46
47impl OptimizeTableStatement {
48	/// Create a new OPTIMIZE TABLE statement
49	///
50	/// # Examples
51	///
52	/// ```rust
53	/// use reinhardt_query::prelude::*;
54	///
55	/// let query = Query::optimize_table();
56	/// ```
57	pub fn new() -> Self {
58		Self::default()
59	}
60
61	/// Take the ownership of data in the current [`OptimizeTableStatement`]
62	pub fn take(&mut self) -> Self {
63		Self {
64			tables: std::mem::take(&mut self.tables),
65			no_write_to_binlog: std::mem::take(&mut self.no_write_to_binlog),
66			local: std::mem::take(&mut self.local),
67		}
68	}
69
70	/// Add a table to optimize
71	///
72	/// # Examples
73	///
74	/// ```rust
75	/// use reinhardt_query::prelude::*;
76	///
77	/// let query = Query::optimize_table()
78	///     .table("users");
79	/// ```
80	pub fn table<T>(&mut self, table: T) -> &mut Self
81	where
82		T: IntoIden,
83	{
84		self.tables.push(table.into_iden());
85		self
86	}
87
88	/// Set NO_WRITE_TO_BINLOG option
89	///
90	/// Suppresses binary logging for this operation (same as LOCAL).
91	///
92	/// # Examples
93	///
94	/// ```rust
95	/// use reinhardt_query::prelude::*;
96	///
97	/// let query = Query::optimize_table()
98	///     .table("users")
99	///     .no_write_to_binlog();
100	/// ```
101	pub fn no_write_to_binlog(&mut self) -> &mut Self {
102		self.no_write_to_binlog = true;
103		self
104	}
105
106	/// Set LOCAL option
107	///
108	/// Suppresses binary logging for this operation (same as NO_WRITE_TO_BINLOG).
109	///
110	/// # Examples
111	///
112	/// ```rust
113	/// use reinhardt_query::prelude::*;
114	///
115	/// let query = Query::optimize_table()
116	///     .table("users")
117	///     .local();
118	/// ```
119	pub fn local(&mut self) -> &mut Self {
120		self.local = true;
121		self
122	}
123
124	/// Set options from OptimizeTableOption
125	///
126	/// # Examples
127	///
128	/// ```rust
129	/// use reinhardt_query::prelude::*;
130	/// use reinhardt_query::types::OptimizeTableOption;
131	///
132	/// let opt = OptimizeTableOption::new().no_write_to_binlog(true);
133	/// let query = Query::optimize_table()
134	///     .table("users")
135	///     .options(opt);
136	/// ```
137	pub fn options(&mut self, opt: OptimizeTableOption) -> &mut Self {
138		self.no_write_to_binlog = opt.no_write_to_binlog;
139		self.local = opt.local;
140		self
141	}
142}
143
144impl QueryStatementBuilder for OptimizeTableStatement {
145	fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, crate::value::Values) {
146		// Downcast to concrete QueryBuilder type
147		use std::any::Any;
148		if let Some(builder) =
149			(query_builder as &dyn Any).downcast_ref::<crate::backend::PostgresQueryBuilder>()
150		{
151			return builder.build_optimize_table(self);
152		}
153		if let Some(builder) =
154			(query_builder as &dyn Any).downcast_ref::<crate::backend::MySqlQueryBuilder>()
155		{
156			return builder.build_optimize_table(self);
157		}
158		if let Some(builder) =
159			(query_builder as &dyn Any).downcast_ref::<crate::backend::SqliteQueryBuilder>()
160		{
161			return builder.build_optimize_table(self);
162		}
163		if let Some(builder) =
164			(query_builder as &dyn Any).downcast_ref::<crate::backend::CockroachDBQueryBuilder>()
165		{
166			return builder.build_optimize_table(self);
167		}
168		panic!("Unsupported query builder type");
169	}
170}
171
172impl QueryStatementWriter for OptimizeTableStatement {}
173
174#[cfg(test)]
175mod tests {
176	use super::*;
177	use rstest::*;
178
179	#[rstest]
180	fn test_optimize_table_new() {
181		let stmt = OptimizeTableStatement::new();
182		assert!(stmt.tables.is_empty());
183		assert!(!stmt.no_write_to_binlog);
184		assert!(!stmt.local);
185	}
186
187	#[rstest]
188	fn test_optimize_table_with_table() {
189		let mut stmt = OptimizeTableStatement::new();
190		stmt.table("users");
191		assert_eq!(stmt.tables.len(), 1);
192		assert_eq!(stmt.tables[0].to_string(), "users");
193	}
194
195	#[rstest]
196	fn test_optimize_table_with_multiple_tables() {
197		let mut stmt = OptimizeTableStatement::new();
198		stmt.table("users").table("posts");
199		assert_eq!(stmt.tables.len(), 2);
200		assert_eq!(stmt.tables[0].to_string(), "users");
201		assert_eq!(stmt.tables[1].to_string(), "posts");
202	}
203
204	#[rstest]
205	fn test_optimize_table_no_write_to_binlog() {
206		let mut stmt = OptimizeTableStatement::new();
207		stmt.no_write_to_binlog();
208		assert!(stmt.no_write_to_binlog);
209		assert!(!stmt.local);
210	}
211
212	#[rstest]
213	fn test_optimize_table_local() {
214		let mut stmt = OptimizeTableStatement::new();
215		stmt.local();
216		assert!(!stmt.no_write_to_binlog);
217		assert!(stmt.local);
218	}
219
220	#[rstest]
221	fn test_optimize_table_with_option() {
222		let opt = OptimizeTableOption::new().no_write_to_binlog(true);
223		let mut stmt = OptimizeTableStatement::new();
224		stmt.table("users").options(opt);
225		assert_eq!(stmt.tables.len(), 1);
226		assert!(stmt.no_write_to_binlog);
227		assert!(!stmt.local);
228	}
229
230	#[rstest]
231	fn test_optimize_table_take() {
232		let mut stmt = OptimizeTableStatement::new();
233		stmt.table("users").no_write_to_binlog();
234
235		let taken = stmt.take();
236		assert_eq!(taken.tables.len(), 1);
237		assert!(taken.no_write_to_binlog);
238
239		// Original should be reset
240		assert!(stmt.tables.is_empty());
241		assert!(!stmt.no_write_to_binlog);
242	}
243}