Skip to main content

reinhardt_query/query/maintenance/
analyze.rs

1//! ANALYZE statement builder
2//!
3//! This module provides the `AnalyzeStatement` type for building SQL ANALYZE queries.
4
5use crate::{
6	backend::QueryBuilder,
7	types::{AnalyzeTable, IntoIden},
8};
9
10use crate::query::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
11
12/// ANALYZE statement builder
13///
14/// This struct provides a fluent API for constructing ANALYZE queries.
15/// ANALYZE collects statistics about table contents for the query planner.
16///
17/// # Examples
18///
19/// ```rust
20/// use reinhardt_query::prelude::*;
21///
22/// // ANALYZE (all tables)
23/// let query = Query::analyze();
24///
25/// // ANALYZE users
26/// let query = Query::analyze()
27///     .table("users");
28///
29/// // ANALYZE VERBOSE users
30/// let query = Query::analyze()
31///     .table("users")
32///     .verbose();
33///
34/// // ANALYZE users (email, name)
35/// let query = Query::analyze()
36///     .table_columns("users", ["email", "name"]);
37/// ```
38#[derive(Debug, Clone, Default)]
39pub struct AnalyzeStatement {
40	pub(crate) tables: Vec<AnalyzeTable>,
41	pub(crate) verbose: bool,
42}
43
44impl AnalyzeStatement {
45	/// Create a new ANALYZE statement
46	///
47	/// # Examples
48	///
49	/// ```rust
50	/// use reinhardt_query::prelude::*;
51	///
52	/// let query = Query::analyze();
53	/// ```
54	pub fn new() -> Self {
55		Self::default()
56	}
57
58	/// Take the ownership of data in the current [`AnalyzeStatement`]
59	pub fn take(&mut self) -> Self {
60		Self {
61			tables: std::mem::take(&mut self.tables),
62			verbose: std::mem::take(&mut self.verbose),
63		}
64	}
65
66	/// Add a table to analyze
67	///
68	/// # Examples
69	///
70	/// ```rust
71	/// use reinhardt_query::prelude::*;
72	///
73	/// let query = Query::analyze()
74	///     .table("users");
75	/// ```
76	pub fn table<T>(&mut self, table: T) -> &mut Self
77	where
78		T: IntoIden,
79	{
80		self.tables.push(AnalyzeTable::new(table));
81		self
82	}
83
84	/// Add a table with specific columns to analyze
85	///
86	/// # Examples
87	///
88	/// ```rust
89	/// use reinhardt_query::prelude::*;
90	///
91	/// let query = Query::analyze()
92	///     .table_columns("users", ["email", "name"]);
93	/// ```
94	pub fn table_columns<T, I, C>(&mut self, table: T, columns: I) -> &mut Self
95	where
96		T: IntoIden,
97		I: IntoIterator<Item = C>,
98		C: IntoIden,
99	{
100		let mut tbl = AnalyzeTable::new(table);
101		for col in columns {
102			tbl = tbl.add_column(col);
103		}
104		self.tables.push(tbl);
105		self
106	}
107
108	/// Set VERBOSE option
109	///
110	/// # Examples
111	///
112	/// ```rust
113	/// use reinhardt_query::prelude::*;
114	///
115	/// let query = Query::analyze()
116	///     .verbose();
117	/// ```
118	pub fn verbose(&mut self) -> &mut Self {
119		self.verbose = true;
120		self
121	}
122}
123
124impl QueryStatementBuilder for AnalyzeStatement {
125	fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, crate::value::Values) {
126		// Downcast to concrete QueryBuilder type
127		use std::any::Any;
128		if let Some(builder) =
129			(query_builder as &dyn Any).downcast_ref::<crate::backend::PostgresQueryBuilder>()
130		{
131			return builder.build_analyze(self);
132		}
133		if let Some(builder) =
134			(query_builder as &dyn Any).downcast_ref::<crate::backend::MySqlQueryBuilder>()
135		{
136			return builder.build_analyze(self);
137		}
138		if let Some(builder) =
139			(query_builder as &dyn Any).downcast_ref::<crate::backend::SqliteQueryBuilder>()
140		{
141			return builder.build_analyze(self);
142		}
143		if let Some(builder) =
144			(query_builder as &dyn Any).downcast_ref::<crate::backend::CockroachDBQueryBuilder>()
145		{
146			return builder.build_analyze(self);
147		}
148		panic!("Unsupported query builder type");
149	}
150}
151
152impl QueryStatementWriter for AnalyzeStatement {}
153
154#[cfg(test)]
155mod tests {
156	use super::*;
157	use rstest::*;
158
159	#[rstest]
160	fn test_analyze_new() {
161		let stmt = AnalyzeStatement::new();
162		assert!(stmt.tables.is_empty());
163		assert!(!stmt.verbose);
164	}
165
166	#[rstest]
167	fn test_analyze_with_table() {
168		let mut stmt = AnalyzeStatement::new();
169		stmt.table("users");
170		assert_eq!(stmt.tables.len(), 1);
171		assert_eq!(stmt.tables[0].table.to_string(), "users");
172		assert!(stmt.tables[0].columns.is_empty());
173	}
174
175	#[rstest]
176	fn test_analyze_with_multiple_tables() {
177		let mut stmt = AnalyzeStatement::new();
178		stmt.table("users").table("posts");
179		assert_eq!(stmt.tables.len(), 2);
180		assert_eq!(stmt.tables[0].table.to_string(), "users");
181		assert_eq!(stmt.tables[1].table.to_string(), "posts");
182	}
183
184	#[rstest]
185	fn test_analyze_with_columns() {
186		let mut stmt = AnalyzeStatement::new();
187		stmt.table_columns("users", ["email", "name"]);
188		assert_eq!(stmt.tables.len(), 1);
189		assert_eq!(stmt.tables[0].table.to_string(), "users");
190		assert_eq!(stmt.tables[0].columns.len(), 2);
191		assert_eq!(stmt.tables[0].columns[0].to_string(), "email");
192		assert_eq!(stmt.tables[0].columns[1].to_string(), "name");
193	}
194
195	#[rstest]
196	fn test_analyze_verbose() {
197		let mut stmt = AnalyzeStatement::new();
198		stmt.verbose();
199		assert!(stmt.verbose);
200	}
201
202	#[rstest]
203	fn test_analyze_combined() {
204		let mut stmt = AnalyzeStatement::new();
205		stmt.table("users")
206			.table_columns("posts", ["title", "content"])
207			.verbose();
208		assert_eq!(stmt.tables.len(), 2);
209		assert_eq!(stmt.tables[0].table.to_string(), "users");
210		assert!(stmt.tables[0].columns.is_empty());
211		assert_eq!(stmt.tables[1].table.to_string(), "posts");
212		assert_eq!(stmt.tables[1].columns.len(), 2);
213		assert!(stmt.verbose);
214	}
215
216	#[rstest]
217	fn test_analyze_take() {
218		let mut stmt = AnalyzeStatement::new();
219		stmt.table("users").verbose();
220
221		let taken = stmt.take();
222		assert_eq!(taken.tables.len(), 1);
223		assert!(taken.verbose);
224
225		// Original should be reset
226		assert!(stmt.tables.is_empty());
227		assert!(!stmt.verbose);
228	}
229}