Skip to main content

reinhardt_query/types/
maintenance.rs

1//! Database maintenance types
2//!
3//! This module provides types for database maintenance operations:
4//!
5//! - [`VacuumOption`]: Options for VACUUM statement
6//! - [`OptimizeTableOption`]: Options for OPTIMIZE TABLE statement (MySQL-only)
7//! - [`RepairTableOption`]: Options for REPAIR TABLE statement (MySQL-only)
8//! - [`CheckTableOption`]: Options for CHECK TABLE statement (MySQL-only)
9
10use crate::types::{DynIden, IntoIden};
11
12/// VACUUM statement options
13///
14/// This struct represents options for the VACUUM statement.
15///
16/// # Examples
17///
18/// ```rust
19/// use reinhardt_query::types::maintenance::VacuumOption;
20///
21/// // Basic VACUUM
22/// let opt = VacuumOption::new();
23///
24/// // VACUUM FULL
25/// let opt = VacuumOption::new().full(true);
26///
27/// // VACUUM FULL ANALYZE
28/// let opt = VacuumOption::new().full(true).analyze(true);
29/// ```
30#[derive(Debug, Clone, Default)]
31pub struct VacuumOption {
32	pub(crate) full: bool,
33	pub(crate) freeze: bool,
34	pub(crate) verbose: bool,
35	pub(crate) analyze: bool,
36}
37
38impl VacuumOption {
39	/// Create a new VACUUM option
40	///
41	/// # Examples
42	///
43	/// ```rust
44	/// use reinhardt_query::types::maintenance::VacuumOption;
45	///
46	/// let opt = VacuumOption::new();
47	/// ```
48	pub fn new() -> Self {
49		Self::default()
50	}
51
52	/// Set FULL option
53	///
54	/// # Examples
55	///
56	/// ```rust
57	/// use reinhardt_query::types::maintenance::VacuumOption;
58	///
59	/// let opt = VacuumOption::new().full(true);
60	/// ```
61	pub fn full(mut self, full: bool) -> Self {
62		self.full = full;
63		self
64	}
65
66	/// Set FREEZE option
67	///
68	/// # Examples
69	///
70	/// ```rust
71	/// use reinhardt_query::types::maintenance::VacuumOption;
72	///
73	/// let opt = VacuumOption::new().freeze(true);
74	/// ```
75	pub fn freeze(mut self, freeze: bool) -> Self {
76		self.freeze = freeze;
77		self
78	}
79
80	/// Set VERBOSE option
81	///
82	/// # Examples
83	///
84	/// ```rust
85	/// use reinhardt_query::types::maintenance::VacuumOption;
86	///
87	/// let opt = VacuumOption::new().verbose(true);
88	/// ```
89	pub fn verbose(mut self, verbose: bool) -> Self {
90		self.verbose = verbose;
91		self
92	}
93
94	/// Set ANALYZE option
95	///
96	/// # Examples
97	///
98	/// ```rust
99	/// use reinhardt_query::types::maintenance::VacuumOption;
100	///
101	/// let opt = VacuumOption::new().analyze(true);
102	/// ```
103	pub fn analyze(mut self, analyze: bool) -> Self {
104		self.analyze = analyze;
105		self
106	}
107}
108
109/// Table specification for ANALYZE statement
110///
111/// This struct represents a table and its optional columns for ANALYZE.
112///
113/// # Examples
114///
115/// ```rust
116/// use reinhardt_query::types::maintenance::AnalyzeTable;
117///
118/// // Analyze entire table
119/// let tbl = AnalyzeTable::new("users");
120///
121/// // Analyze specific columns
122/// let tbl = AnalyzeTable::new("users")
123///     .add_column("email")
124///     .add_column("name");
125/// ```
126#[derive(Debug, Clone)]
127pub struct AnalyzeTable {
128	// Allow dead_code: table field will be used when Phase B ANALYZE implementation is completed
129	#[allow(dead_code)]
130	pub(crate) table: DynIden,
131	pub(crate) columns: Vec<DynIden>,
132}
133
134impl AnalyzeTable {
135	/// Create a new ANALYZE table specification
136	///
137	/// # Examples
138	///
139	/// ```rust
140	/// use reinhardt_query::types::maintenance::AnalyzeTable;
141	///
142	/// let tbl = AnalyzeTable::new("users");
143	/// ```
144	pub fn new<T: IntoIden>(table: T) -> Self {
145		Self {
146			table: table.into_iden(),
147			columns: Vec::new(),
148		}
149	}
150
151	/// Add a column to analyze
152	///
153	/// # Examples
154	///
155	/// ```rust
156	/// use reinhardt_query::types::maintenance::AnalyzeTable;
157	///
158	/// let tbl = AnalyzeTable::new("users")
159	///     .add_column("email");
160	/// ```
161	pub fn add_column<C: IntoIden>(mut self, column: C) -> Self {
162		self.columns.push(column.into_iden());
163		self
164	}
165}
166
167/// OPTIMIZE TABLE statement options (MySQL-only)
168///
169/// This struct represents options for the OPTIMIZE TABLE statement.
170/// OPTIMIZE TABLE reorganizes the physical storage of table data and associated index data.
171///
172/// # Examples
173///
174/// ```rust
175/// use reinhardt_query::types::maintenance::OptimizeTableOption;
176///
177/// // Basic OPTIMIZE TABLE
178/// let opt = OptimizeTableOption::new();
179///
180/// // OPTIMIZE NO_WRITE_TO_BINLOG TABLE
181/// let opt = OptimizeTableOption::new().no_write_to_binlog(true);
182///
183/// // OPTIMIZE LOCAL TABLE
184/// let opt = OptimizeTableOption::new().local(true);
185/// ```
186#[derive(Debug, Clone, Default)]
187pub struct OptimizeTableOption {
188	pub(crate) no_write_to_binlog: bool,
189	pub(crate) local: bool,
190}
191
192impl OptimizeTableOption {
193	/// Create a new OPTIMIZE TABLE option
194	///
195	/// # Examples
196	///
197	/// ```rust
198	/// use reinhardt_query::types::maintenance::OptimizeTableOption;
199	///
200	/// let opt = OptimizeTableOption::new();
201	/// ```
202	pub fn new() -> Self {
203		Self::default()
204	}
205
206	/// Set NO_WRITE_TO_BINLOG option
207	///
208	/// Suppresses binary logging for this operation (same as LOCAL).
209	///
210	/// # Examples
211	///
212	/// ```rust
213	/// use reinhardt_query::types::maintenance::OptimizeTableOption;
214	///
215	/// let opt = OptimizeTableOption::new().no_write_to_binlog(true);
216	/// ```
217	pub fn no_write_to_binlog(mut self, no_write_to_binlog: bool) -> Self {
218		self.no_write_to_binlog = no_write_to_binlog;
219		self
220	}
221
222	/// Set LOCAL option
223	///
224	/// Suppresses binary logging for this operation (same as NO_WRITE_TO_BINLOG).
225	///
226	/// # Examples
227	///
228	/// ```rust
229	/// use reinhardt_query::types::maintenance::OptimizeTableOption;
230	///
231	/// let opt = OptimizeTableOption::new().local(true);
232	/// ```
233	pub fn local(mut self, local: bool) -> Self {
234		self.local = local;
235		self
236	}
237}
238
239/// REPAIR TABLE statement options (MySQL-only)
240///
241/// This struct represents options for the REPAIR TABLE statement.
242/// REPAIR TABLE repairs a possibly corrupted table.
243///
244/// # Examples
245///
246/// ```rust
247/// use reinhardt_query::types::maintenance::RepairTableOption;
248///
249/// // Basic REPAIR TABLE
250/// let opt = RepairTableOption::new();
251///
252/// // REPAIR TABLE with QUICK option
253/// let opt = RepairTableOption::new().quick(true);
254///
255/// // REPAIR TABLE with EXTENDED option
256/// let opt = RepairTableOption::new().extended(true);
257/// ```
258#[derive(Debug, Clone, Default)]
259pub struct RepairTableOption {
260	pub(crate) no_write_to_binlog: bool,
261	pub(crate) local: bool,
262	pub(crate) quick: bool,
263	pub(crate) extended: bool,
264	pub(crate) use_frm: bool,
265}
266
267impl RepairTableOption {
268	/// Create a new REPAIR TABLE option
269	///
270	/// # Examples
271	///
272	/// ```rust
273	/// use reinhardt_query::types::maintenance::RepairTableOption;
274	///
275	/// let opt = RepairTableOption::new();
276	/// ```
277	pub fn new() -> Self {
278		Self::default()
279	}
280
281	/// Set NO_WRITE_TO_BINLOG option
282	///
283	/// Suppresses binary logging for this operation.
284	///
285	/// # Examples
286	///
287	/// ```rust
288	/// use reinhardt_query::types::maintenance::RepairTableOption;
289	///
290	/// let opt = RepairTableOption::new().no_write_to_binlog(true);
291	/// ```
292	pub fn no_write_to_binlog(mut self, no_write_to_binlog: bool) -> Self {
293		self.no_write_to_binlog = no_write_to_binlog;
294		self
295	}
296
297	/// Set LOCAL option
298	///
299	/// Suppresses binary logging for this operation (same as NO_WRITE_TO_BINLOG).
300	///
301	/// # Examples
302	///
303	/// ```rust
304	/// use reinhardt_query::types::maintenance::RepairTableOption;
305	///
306	/// let opt = RepairTableOption::new().local(true);
307	/// ```
308	pub fn local(mut self, local: bool) -> Self {
309		self.local = local;
310		self
311	}
312
313	/// Set QUICK option
314	///
315	/// Tries to repair only the index file, not the data file.
316	///
317	/// # Examples
318	///
319	/// ```rust
320	/// use reinhardt_query::types::maintenance::RepairTableOption;
321	///
322	/// let opt = RepairTableOption::new().quick(true);
323	/// ```
324	pub fn quick(mut self, quick: bool) -> Self {
325		self.quick = quick;
326		self
327	}
328
329	/// Set EXTENDED option
330	///
331	/// Creates the index row by row instead of creating one index at a time with sorting.
332	///
333	/// # Examples
334	///
335	/// ```rust
336	/// use reinhardt_query::types::maintenance::RepairTableOption;
337	///
338	/// let opt = RepairTableOption::new().extended(true);
339	/// ```
340	pub fn extended(mut self, extended: bool) -> Self {
341		self.extended = extended;
342		self
343	}
344
345	/// Set USE_FRM option
346	///
347	/// Uses the table definition from the .frm file to recreate the index file.
348	///
349	/// # Examples
350	///
351	/// ```rust
352	/// use reinhardt_query::types::maintenance::RepairTableOption;
353	///
354	/// let opt = RepairTableOption::new().use_frm(true);
355	/// ```
356	pub fn use_frm(mut self, use_frm: bool) -> Self {
357		self.use_frm = use_frm;
358		self
359	}
360}
361
362/// CHECK TABLE statement options (MySQL-only)
363///
364/// This enum represents the check option for the CHECK TABLE statement.
365/// CHECK TABLE checks a table or tables for errors.
366///
367/// # Examples
368///
369/// ```rust
370/// use reinhardt_query::types::maintenance::CheckTableOption;
371///
372/// // Default check (MEDIUM)
373/// let opt = CheckTableOption::default();
374///
375/// // Quick check
376/// let opt = CheckTableOption::Quick;
377///
378/// // Extended check
379/// let opt = CheckTableOption::Extended;
380/// ```
381#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
382pub enum CheckTableOption {
383	/// Check for version compatibility
384	ForUpgrade,
385	/// Quick check, skip scanning rows for incorrect links
386	Quick,
387	/// Fast check, check only tables that haven't been closed properly
388	Fast,
389	/// Medium check (default), scan rows to verify deleted links are valid
390	#[default]
391	Medium,
392	/// Extended check, do a full key lookup for all keys
393	Extended,
394	/// Check only tables that have been changed since last check or not closed properly
395	Changed,
396}
397
398#[cfg(test)]
399mod tests {
400	use super::*;
401	use rstest::*;
402
403	// VacuumOption tests
404	#[rstest]
405	fn test_vacuum_option_default() {
406		let opt = VacuumOption::new();
407		assert!(!opt.full);
408		assert!(!opt.freeze);
409		assert!(!opt.verbose);
410		assert!(!opt.analyze);
411	}
412
413	#[rstest]
414	fn test_vacuum_option_full() {
415		let opt = VacuumOption::new().full(true);
416		assert!(opt.full);
417		assert!(!opt.freeze);
418		assert!(!opt.verbose);
419		assert!(!opt.analyze);
420	}
421
422	#[rstest]
423	fn test_vacuum_option_freeze() {
424		let opt = VacuumOption::new().freeze(true);
425		assert!(!opt.full);
426		assert!(opt.freeze);
427		assert!(!opt.verbose);
428		assert!(!opt.analyze);
429	}
430
431	#[rstest]
432	fn test_vacuum_option_verbose() {
433		let opt = VacuumOption::new().verbose(true);
434		assert!(!opt.full);
435		assert!(!opt.freeze);
436		assert!(opt.verbose);
437		assert!(!opt.analyze);
438	}
439
440	#[rstest]
441	fn test_vacuum_option_analyze() {
442		let opt = VacuumOption::new().analyze(true);
443		assert!(!opt.full);
444		assert!(!opt.freeze);
445		assert!(!opt.verbose);
446		assert!(opt.analyze);
447	}
448
449	#[rstest]
450	fn test_vacuum_option_combined() {
451		let opt = VacuumOption::new()
452			.full(true)
453			.freeze(true)
454			.verbose(true)
455			.analyze(true);
456		assert!(opt.full);
457		assert!(opt.freeze);
458		assert!(opt.verbose);
459		assert!(opt.analyze);
460	}
461
462	// AnalyzeTable tests
463	#[rstest]
464	fn test_analyze_table_basic() {
465		let tbl = AnalyzeTable::new("users");
466		assert_eq!(tbl.table.to_string(), "users");
467		assert!(tbl.columns.is_empty());
468	}
469
470	#[rstest]
471	fn test_analyze_table_with_column() {
472		let tbl = AnalyzeTable::new("users").add_column("email");
473		assert_eq!(tbl.table.to_string(), "users");
474		assert_eq!(tbl.columns.len(), 1);
475		assert_eq!(tbl.columns[0].to_string(), "email");
476	}
477
478	#[rstest]
479	fn test_analyze_table_with_multiple_columns() {
480		let tbl = AnalyzeTable::new("users")
481			.add_column("email")
482			.add_column("name")
483			.add_column("age");
484		assert_eq!(tbl.table.to_string(), "users");
485		assert_eq!(tbl.columns.len(), 3);
486		assert_eq!(tbl.columns[0].to_string(), "email");
487		assert_eq!(tbl.columns[1].to_string(), "name");
488		assert_eq!(tbl.columns[2].to_string(), "age");
489	}
490
491	// OptimizeTableOption tests
492	#[rstest]
493	fn test_optimize_table_option_default() {
494		let opt = OptimizeTableOption::new();
495		assert!(!opt.no_write_to_binlog);
496		assert!(!opt.local);
497	}
498
499	#[rstest]
500	fn test_optimize_table_option_no_write_to_binlog() {
501		let opt = OptimizeTableOption::new().no_write_to_binlog(true);
502		assert!(opt.no_write_to_binlog);
503		assert!(!opt.local);
504	}
505
506	#[rstest]
507	fn test_optimize_table_option_local() {
508		let opt = OptimizeTableOption::new().local(true);
509		assert!(!opt.no_write_to_binlog);
510		assert!(opt.local);
511	}
512
513	// RepairTableOption tests
514	#[rstest]
515	fn test_repair_table_option_default() {
516		let opt = RepairTableOption::new();
517		assert!(!opt.no_write_to_binlog);
518		assert!(!opt.local);
519		assert!(!opt.quick);
520		assert!(!opt.extended);
521		assert!(!opt.use_frm);
522	}
523
524	#[rstest]
525	fn test_repair_table_option_quick() {
526		let opt = RepairTableOption::new().quick(true);
527		assert!(opt.quick);
528		assert!(!opt.extended);
529	}
530
531	#[rstest]
532	fn test_repair_table_option_extended() {
533		let opt = RepairTableOption::new().extended(true);
534		assert!(!opt.quick);
535		assert!(opt.extended);
536	}
537
538	#[rstest]
539	fn test_repair_table_option_use_frm() {
540		let opt = RepairTableOption::new().use_frm(true);
541		assert!(opt.use_frm);
542	}
543
544	// CheckTableOption tests
545	#[rstest]
546	fn test_check_table_option_default() {
547		let opt = CheckTableOption::default();
548		assert!(matches!(opt, CheckTableOption::Medium));
549	}
550
551	#[rstest]
552	fn test_check_table_option_variants() {
553		assert!(matches!(
554			CheckTableOption::ForUpgrade,
555			CheckTableOption::ForUpgrade
556		));
557		assert!(matches!(CheckTableOption::Quick, CheckTableOption::Quick));
558		assert!(matches!(CheckTableOption::Fast, CheckTableOption::Fast));
559		assert!(matches!(CheckTableOption::Medium, CheckTableOption::Medium));
560		assert!(matches!(
561			CheckTableOption::Extended,
562			CheckTableOption::Extended
563		));
564		assert!(matches!(
565			CheckTableOption::Changed,
566			CheckTableOption::Changed
567		));
568	}
569}