Skip to main content

reinhardt_query/query/
comment.rs

1//! COMMENT ON statement builder
2//!
3//! This module provides the `CommentStatement` type for building SQL COMMENT ON queries.
4
5use crate::{backend::QueryBuilder, types::CommentTarget};
6
7use super::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
8
9/// COMMENT ON statement builder
10///
11/// This struct provides a fluent API for constructing COMMENT ON queries.
12///
13/// # Examples
14///
15/// ```rust
16/// use reinhardt_query::prelude::*;
17/// use reinhardt_query::types::CommentTarget;
18///
19/// // COMMENT ON TABLE "users" IS 'User account information'
20/// let query = Query::comment()
21///     .target(CommentTarget::Table("users".into_iden()))
22///     .comment("User account information");
23///
24/// // COMMENT ON COLUMN "users"."email" IS 'User email address'
25/// let query = Query::comment()
26///     .target(CommentTarget::Column("users".into_iden(), "email".into_iden()))
27///     .comment("User email address");
28///
29/// // COMMENT ON TABLE "users" IS NULL (remove comment)
30/// let query = Query::comment()
31///     .target(CommentTarget::Table("users".into_iden()))
32///     .comment_null();
33/// ```
34#[derive(Debug, Clone)]
35pub struct CommentStatement {
36	pub(crate) target: Option<CommentTarget>,
37	pub(crate) comment: Option<String>,
38	pub(crate) is_null: bool,
39}
40
41impl CommentStatement {
42	/// Create a new COMMENT ON statement
43	///
44	/// # Examples
45	///
46	/// ```rust
47	/// use reinhardt_query::prelude::*;
48	///
49	/// let query = Query::comment();
50	/// ```
51	pub fn new() -> Self {
52		Self {
53			target: None,
54			comment: None,
55			is_null: false,
56		}
57	}
58
59	/// Take the ownership of data in the current [`CommentStatement`]
60	pub fn take(&mut self) -> Self {
61		Self {
62			target: self.target.take(),
63			comment: self.comment.take(),
64			is_null: self.is_null,
65		}
66	}
67
68	/// Set the target object for the comment
69	///
70	/// # Examples
71	///
72	/// ```rust
73	/// use reinhardt_query::prelude::*;
74	/// use reinhardt_query::types::CommentTarget;
75	///
76	/// let query = Query::comment()
77	///     .target(CommentTarget::Table("users".into_iden()));
78	/// ```
79	pub fn target(mut self, target: CommentTarget) -> Self {
80		self.target = Some(target);
81		self
82	}
83
84	/// Set the comment text
85	///
86	/// # Examples
87	///
88	/// ```rust
89	/// use reinhardt_query::prelude::*;
90	/// use reinhardt_query::types::CommentTarget;
91	///
92	/// let query = Query::comment()
93	///     .target(CommentTarget::Table("users".into_iden()))
94	///     .comment("User account information");
95	/// ```
96	pub fn comment<S: Into<String>>(mut self, comment: S) -> Self {
97		self.comment = Some(comment.into());
98		self.is_null = false;
99		self
100	}
101
102	/// Set the comment to NULL (remove comment)
103	///
104	/// # Examples
105	///
106	/// ```rust
107	/// use reinhardt_query::prelude::*;
108	/// use reinhardt_query::types::CommentTarget;
109	///
110	/// let query = Query::comment()
111	///     .target(CommentTarget::Table("users".into_iden()))
112	///     .comment_null();
113	/// ```
114	pub fn comment_null(mut self) -> Self {
115		self.comment = None;
116		self.is_null = true;
117		self
118	}
119}
120
121impl Default for CommentStatement {
122	fn default() -> Self {
123		Self::new()
124	}
125}
126
127impl QueryStatementBuilder for CommentStatement {
128	fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, crate::value::Values) {
129		// Downcast QueryBuilderTrait to concrete QueryBuilder types
130		use std::any::Any;
131		if let Some(builder) =
132			(query_builder as &dyn Any).downcast_ref::<crate::backend::PostgresQueryBuilder>()
133		{
134			return builder.build_comment(self);
135		}
136		if let Some(builder) =
137			(query_builder as &dyn Any).downcast_ref::<crate::backend::MySqlQueryBuilder>()
138		{
139			return builder.build_comment(self);
140		}
141		if let Some(builder) =
142			(query_builder as &dyn Any).downcast_ref::<crate::backend::SqliteQueryBuilder>()
143		{
144			return builder.build_comment(self);
145		}
146		if let Some(builder) =
147			(query_builder as &dyn Any).downcast_ref::<crate::backend::CockroachDBQueryBuilder>()
148		{
149			return builder.build_comment(self);
150		}
151		panic!("Unsupported query builder type");
152	}
153}
154
155impl QueryStatementWriter for CommentStatement {}
156
157#[cfg(test)]
158mod tests {
159	use super::*;
160	use crate::{backend::PostgresQueryBuilder, types::IntoIden};
161	use rstest::*;
162
163	#[fixture]
164	fn builder() -> PostgresQueryBuilder {
165		PostgresQueryBuilder
166	}
167
168	#[rstest]
169	fn test_comment_on_table(builder: PostgresQueryBuilder) {
170		let query = CommentStatement::new()
171			.target(CommentTarget::Table("users".into_iden()))
172			.comment("User account information");
173		let (sql, _) = builder.build_comment(&query);
174		assert_eq!(
175			sql,
176			"COMMENT ON TABLE \"users\" IS 'User account information'"
177		);
178	}
179
180	#[rstest]
181	fn test_comment_on_column(builder: PostgresQueryBuilder) {
182		let query = CommentStatement::new()
183			.target(CommentTarget::Column(
184				"users".into_iden(),
185				"email".into_iden(),
186			))
187			.comment("User email address");
188		let (sql, _) = builder.build_comment(&query);
189		assert_eq!(
190			sql,
191			"COMMENT ON COLUMN \"users\".\"email\" IS 'User email address'"
192		);
193	}
194
195	#[rstest]
196	fn test_comment_on_index(builder: PostgresQueryBuilder) {
197		let query = CommentStatement::new()
198			.target(CommentTarget::Index("idx_users_email".into_iden()))
199			.comment("Email index");
200		let (sql, _) = builder.build_comment(&query);
201		assert_eq!(sql, "COMMENT ON INDEX \"idx_users_email\" IS 'Email index'");
202	}
203
204	#[rstest]
205	fn test_comment_on_view(builder: PostgresQueryBuilder) {
206		let query = CommentStatement::new()
207			.target(CommentTarget::View("active_users".into_iden()))
208			.comment("Active users view");
209		let (sql, _) = builder.build_comment(&query);
210		assert_eq!(
211			sql,
212			"COMMENT ON VIEW \"active_users\" IS 'Active users view'"
213		);
214	}
215
216	#[rstest]
217	fn test_comment_on_materialized_view(builder: PostgresQueryBuilder) {
218		let query = CommentStatement::new()
219			.target(CommentTarget::MaterializedView("user_stats".into_iden()))
220			.comment("User statistics");
221		let (sql, _) = builder.build_comment(&query);
222		assert_eq!(
223			sql,
224			"COMMENT ON MATERIALIZED VIEW \"user_stats\" IS 'User statistics'"
225		);
226	}
227
228	#[rstest]
229	fn test_comment_on_sequence(builder: PostgresQueryBuilder) {
230		let query = CommentStatement::new()
231			.target(CommentTarget::Sequence("user_id_seq".into_iden()))
232			.comment("User ID sequence");
233		let (sql, _) = builder.build_comment(&query);
234		assert_eq!(
235			sql,
236			"COMMENT ON SEQUENCE \"user_id_seq\" IS 'User ID sequence'"
237		);
238	}
239
240	#[rstest]
241	fn test_comment_on_schema(builder: PostgresQueryBuilder) {
242		let query = CommentStatement::new()
243			.target(CommentTarget::Schema("public".into_iden()))
244			.comment("Public schema");
245		let (sql, _) = builder.build_comment(&query);
246		assert_eq!(sql, "COMMENT ON SCHEMA \"public\" IS 'Public schema'");
247	}
248
249	#[rstest]
250	fn test_comment_on_database(builder: PostgresQueryBuilder) {
251		let query = CommentStatement::new()
252			.target(CommentTarget::Database("mydb".into_iden()))
253			.comment("My database");
254		let (sql, _) = builder.build_comment(&query);
255		assert_eq!(sql, "COMMENT ON DATABASE \"mydb\" IS 'My database'");
256	}
257
258	#[rstest]
259	fn test_comment_on_function(builder: PostgresQueryBuilder) {
260		let query = CommentStatement::new()
261			.target(CommentTarget::Function("calculate_total".into_iden()))
262			.comment("Calculate total amount");
263		let (sql, _) = builder.build_comment(&query);
264		assert_eq!(
265			sql,
266			"COMMENT ON FUNCTION \"calculate_total\" IS 'Calculate total amount'"
267		);
268	}
269
270	#[rstest]
271	fn test_comment_on_trigger(builder: PostgresQueryBuilder) {
272		let query = CommentStatement::new()
273			.target(CommentTarget::Trigger(
274				"update_timestamp".into_iden(),
275				"users".into_iden(),
276			))
277			.comment("Update timestamp trigger");
278		let (sql, _) = builder.build_comment(&query);
279		assert_eq!(
280			sql,
281			"COMMENT ON TRIGGER \"update_timestamp\" ON \"users\" IS 'Update timestamp trigger'"
282		);
283	}
284
285	#[rstest]
286	fn test_comment_on_type(builder: PostgresQueryBuilder) {
287		let query = CommentStatement::new()
288			.target(CommentTarget::Type("user_status".into_iden()))
289			.comment("User status enum");
290		let (sql, _) = builder.build_comment(&query);
291		assert_eq!(sql, "COMMENT ON TYPE \"user_status\" IS 'User status enum'");
292	}
293
294	#[rstest]
295	fn test_comment_null(builder: PostgresQueryBuilder) {
296		let query = CommentStatement::new()
297			.target(CommentTarget::Table("users".into_iden()))
298			.comment_null();
299		let (sql, _) = builder.build_comment(&query);
300		assert_eq!(sql, "COMMENT ON TABLE \"users\" IS NULL");
301	}
302}