Skip to main content

reinhardt_query/query/maintenance/
repair_table.rs

1//! REPAIR TABLE statement builder
2//!
3//! This module provides the `RepairTableStatement` type for building SQL REPAIR TABLE queries.
4//! **MySQL-only**: This statement is specific to MySQL and MariaDB.
5
6use crate::{
7	backend::QueryBuilder,
8	types::{DynIden, IntoIden, RepairTableOption},
9};
10
11use crate::query::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
12
13/// REPAIR TABLE statement builder
14///
15/// This struct provides a fluent API for constructing REPAIR TABLE queries.
16/// REPAIR TABLE repairs a possibly corrupted table.
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/// // REPAIR TABLE users
26/// let query = Query::repair_table()
27///     .table("users");
28///
29/// // REPAIR TABLE users QUICK
30/// let query = Query::repair_table()
31///     .table("users")
32///     .quick();
33///
34/// // REPAIR TABLE users EXTENDED USE_FRM
35/// let query = Query::repair_table()
36///     .table("users")
37///     .extended()
38///     .use_frm();
39/// ```
40#[derive(Debug, Clone, Default)]
41pub struct RepairTableStatement {
42	pub(crate) tables: Vec<DynIden>,
43	pub(crate) no_write_to_binlog: bool,
44	pub(crate) local: bool,
45	pub(crate) quick: bool,
46	pub(crate) extended: bool,
47	pub(crate) use_frm: bool,
48}
49
50impl RepairTableStatement {
51	/// Create a new REPAIR TABLE statement
52	///
53	/// # Examples
54	///
55	/// ```rust
56	/// use reinhardt_query::prelude::*;
57	///
58	/// let query = Query::repair_table();
59	/// ```
60	pub fn new() -> Self {
61		Self::default()
62	}
63
64	/// Take the ownership of data in the current [`RepairTableStatement`]
65	pub fn take(&mut self) -> Self {
66		Self {
67			tables: std::mem::take(&mut self.tables),
68			no_write_to_binlog: std::mem::take(&mut self.no_write_to_binlog),
69			local: std::mem::take(&mut self.local),
70			quick: std::mem::take(&mut self.quick),
71			extended: std::mem::take(&mut self.extended),
72			use_frm: std::mem::take(&mut self.use_frm),
73		}
74	}
75
76	/// Add a table to repair
77	///
78	/// # Examples
79	///
80	/// ```rust
81	/// use reinhardt_query::prelude::*;
82	///
83	/// let query = Query::repair_table()
84	///     .table("users");
85	/// ```
86	pub fn table<T>(&mut self, table: T) -> &mut Self
87	where
88		T: IntoIden,
89	{
90		self.tables.push(table.into_iden());
91		self
92	}
93
94	/// Set NO_WRITE_TO_BINLOG option
95	///
96	/// Suppresses binary logging for this operation.
97	///
98	/// # Examples
99	///
100	/// ```rust
101	/// use reinhardt_query::prelude::*;
102	///
103	/// let query = Query::repair_table()
104	///     .table("users")
105	///     .no_write_to_binlog();
106	/// ```
107	pub fn no_write_to_binlog(&mut self) -> &mut Self {
108		self.no_write_to_binlog = true;
109		self
110	}
111
112	/// Set LOCAL option
113	///
114	/// Suppresses binary logging for this operation (same as NO_WRITE_TO_BINLOG).
115	///
116	/// # Examples
117	///
118	/// ```rust
119	/// use reinhardt_query::prelude::*;
120	///
121	/// let query = Query::repair_table()
122	///     .table("users")
123	///     .local();
124	/// ```
125	pub fn local(&mut self) -> &mut Self {
126		self.local = true;
127		self
128	}
129
130	/// Set QUICK option
131	///
132	/// Tries to repair only the index file, not the data file.
133	///
134	/// # Examples
135	///
136	/// ```rust
137	/// use reinhardt_query::prelude::*;
138	///
139	/// let query = Query::repair_table()
140	///     .table("users")
141	///     .quick();
142	/// ```
143	pub fn quick(&mut self) -> &mut Self {
144		self.quick = true;
145		self
146	}
147
148	/// Set EXTENDED option
149	///
150	/// Creates the index row by row instead of creating one index at a time with sorting.
151	///
152	/// # Examples
153	///
154	/// ```rust
155	/// use reinhardt_query::prelude::*;
156	///
157	/// let query = Query::repair_table()
158	///     .table("users")
159	///     .extended();
160	/// ```
161	pub fn extended(&mut self) -> &mut Self {
162		self.extended = true;
163		self
164	}
165
166	/// Set USE_FRM option
167	///
168	/// Uses the table definition from the .frm file to recreate the index file.
169	///
170	/// # Examples
171	///
172	/// ```rust
173	/// use reinhardt_query::prelude::*;
174	///
175	/// let query = Query::repair_table()
176	///     .table("users")
177	///     .use_frm();
178	/// ```
179	pub fn use_frm(&mut self) -> &mut Self {
180		self.use_frm = true;
181		self
182	}
183
184	/// Set options from RepairTableOption
185	///
186	/// # Examples
187	///
188	/// ```rust
189	/// use reinhardt_query::prelude::*;
190	/// use reinhardt_query::types::RepairTableOption;
191	///
192	/// let opt = RepairTableOption::new().quick(true).use_frm(true);
193	/// let query = Query::repair_table()
194	///     .table("users")
195	///     .options(opt);
196	/// ```
197	pub fn options(&mut self, opt: RepairTableOption) -> &mut Self {
198		self.no_write_to_binlog = opt.no_write_to_binlog;
199		self.local = opt.local;
200		self.quick = opt.quick;
201		self.extended = opt.extended;
202		self.use_frm = opt.use_frm;
203		self
204	}
205}
206
207impl QueryStatementBuilder for RepairTableStatement {
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_repair_table(self);
215		}
216		if let Some(builder) =
217			(query_builder as &dyn Any).downcast_ref::<crate::backend::MySqlQueryBuilder>()
218		{
219			return builder.build_repair_table(self);
220		}
221		if let Some(builder) =
222			(query_builder as &dyn Any).downcast_ref::<crate::backend::SqliteQueryBuilder>()
223		{
224			return builder.build_repair_table(self);
225		}
226		if let Some(builder) =
227			(query_builder as &dyn Any).downcast_ref::<crate::backend::CockroachDBQueryBuilder>()
228		{
229			return builder.build_repair_table(self);
230		}
231		panic!("Unsupported query builder type");
232	}
233}
234
235impl QueryStatementWriter for RepairTableStatement {}
236
237#[cfg(test)]
238mod tests {
239	use super::*;
240	use rstest::*;
241
242	#[rstest]
243	fn test_repair_table_new() {
244		let stmt = RepairTableStatement::new();
245		assert!(stmt.tables.is_empty());
246		assert!(!stmt.no_write_to_binlog);
247		assert!(!stmt.local);
248		assert!(!stmt.quick);
249		assert!(!stmt.extended);
250		assert!(!stmt.use_frm);
251	}
252
253	#[rstest]
254	fn test_repair_table_with_table() {
255		let mut stmt = RepairTableStatement::new();
256		stmt.table("users");
257		assert_eq!(stmt.tables.len(), 1);
258		assert_eq!(stmt.tables[0].to_string(), "users");
259	}
260
261	#[rstest]
262	fn test_repair_table_with_multiple_tables() {
263		let mut stmt = RepairTableStatement::new();
264		stmt.table("users").table("posts");
265		assert_eq!(stmt.tables.len(), 2);
266		assert_eq!(stmt.tables[0].to_string(), "users");
267		assert_eq!(stmt.tables[1].to_string(), "posts");
268	}
269
270	#[rstest]
271	fn test_repair_table_quick() {
272		let mut stmt = RepairTableStatement::new();
273		stmt.quick();
274		assert!(stmt.quick);
275		assert!(!stmt.extended);
276		assert!(!stmt.use_frm);
277	}
278
279	#[rstest]
280	fn test_repair_table_extended() {
281		let mut stmt = RepairTableStatement::new();
282		stmt.extended();
283		assert!(!stmt.quick);
284		assert!(stmt.extended);
285		assert!(!stmt.use_frm);
286	}
287
288	#[rstest]
289	fn test_repair_table_use_frm() {
290		let mut stmt = RepairTableStatement::new();
291		stmt.use_frm();
292		assert!(!stmt.quick);
293		assert!(!stmt.extended);
294		assert!(stmt.use_frm);
295	}
296
297	#[rstest]
298	fn test_repair_table_with_option() {
299		let opt = RepairTableOption::new().quick(true).use_frm(true);
300		let mut stmt = RepairTableStatement::new();
301		stmt.table("users").options(opt);
302		assert_eq!(stmt.tables.len(), 1);
303		assert!(stmt.quick);
304		assert!(!stmt.extended);
305		assert!(stmt.use_frm);
306	}
307
308	#[rstest]
309	fn test_repair_table_take() {
310		let mut stmt = RepairTableStatement::new();
311		stmt.table("users").quick().use_frm();
312
313		let taken = stmt.take();
314		assert_eq!(taken.tables.len(), 1);
315		assert!(taken.quick);
316		assert!(taken.use_frm);
317
318		// Original should be reset
319		assert!(stmt.tables.is_empty());
320		assert!(!stmt.quick);
321		assert!(!stmt.use_frm);
322	}
323}