Skip to main content

reinhardt_query/query/database/
detach_database.rs

1//! DETACH DATABASE statement builder
2//!
3//! This module provides the `DetachDatabaseStatement` type for building SQL DETACH DATABASE queries.
4//! DETACH DATABASE is a SQLite-specific feature for disconnecting previously attached database files.
5
6use crate::types::{DynIden, IntoIden};
7
8use crate::query::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
9
10/// DETACH DATABASE statement builder (SQLite-specific)
11///
12/// This struct provides a fluent API for constructing DETACH DATABASE queries.
13/// DETACH DATABASE allows detaching previously attached database files from the current connection.
14///
15/// # Examples
16///
17/// ```rust
18/// use reinhardt_query::prelude::*;
19///
20/// // DETACH DATABASE auxiliary
21/// let query = Query::detach_database()
22///     .name("auxiliary");
23/// ```
24#[derive(Debug, Clone)]
25pub struct DetachDatabaseStatement {
26	pub(crate) database_name: Option<DynIden>,
27}
28
29impl DetachDatabaseStatement {
30	/// Create a new DETACH DATABASE statement
31	///
32	/// # Examples
33	///
34	/// ```rust
35	/// use reinhardt_query::prelude::*;
36	///
37	/// let query = Query::detach_database();
38	/// ```
39	pub fn new() -> Self {
40		Self {
41			database_name: None,
42		}
43	}
44
45	/// Take the ownership of data in the current [`DetachDatabaseStatement`]
46	pub fn take(&mut self) -> Self {
47		Self {
48			database_name: self.database_name.take(),
49		}
50	}
51
52	/// Set the name of the database to detach
53	///
54	/// # Examples
55	///
56	/// ```rust
57	/// use reinhardt_query::prelude::*;
58	///
59	/// let query = Query::detach_database()
60	///     .name("auxiliary");
61	/// ```
62	pub fn name<N>(&mut self, name: N) -> &mut Self
63	where
64		N: IntoIden,
65	{
66		self.database_name = Some(name.into_iden());
67		self
68	}
69}
70
71impl Default for DetachDatabaseStatement {
72	fn default() -> Self {
73		Self::new()
74	}
75}
76
77impl QueryStatementBuilder for DetachDatabaseStatement {
78	fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, crate::value::Values) {
79		use std::any::Any;
80		if (query_builder as &dyn Any)
81			.downcast_ref::<crate::backend::PostgresQueryBuilder>()
82			.is_some()
83		{
84			panic!("DETACH DATABASE is SQLite-specific and not supported in PostgreSQL");
85		}
86		if (query_builder as &dyn Any)
87			.downcast_ref::<crate::backend::MySqlQueryBuilder>()
88			.is_some()
89		{
90			panic!("DETACH DATABASE is SQLite-specific and not supported in MySQL");
91		}
92		if (query_builder as &dyn Any)
93			.downcast_ref::<crate::backend::SqliteQueryBuilder>()
94			.is_some()
95		{
96			let db_name = self
97				.database_name
98				.as_ref()
99				.expect("DETACH DATABASE requires a database name");
100			let quote = query_builder.quote_char();
101			let sql = format!("DETACH DATABASE {}{}{}", quote, db_name.to_string(), quote,);
102			return (sql, crate::value::Values::new());
103		}
104		if (query_builder as &dyn Any)
105			.downcast_ref::<crate::backend::CockroachDBQueryBuilder>()
106			.is_some()
107		{
108			panic!("DETACH DATABASE is SQLite-specific and not supported in CockroachDB");
109		}
110		panic!("Unsupported query builder type");
111	}
112}
113
114impl QueryStatementWriter for DetachDatabaseStatement {}
115
116#[cfg(test)]
117mod tests {
118	use super::*;
119	use rstest::*;
120
121	#[rstest]
122	fn test_detach_database_new() {
123		let stmt = DetachDatabaseStatement::new();
124		assert!(stmt.database_name.is_none());
125	}
126
127	#[rstest]
128	fn test_detach_database_with_name() {
129		let mut stmt = DetachDatabaseStatement::new();
130		stmt.name("auxiliary");
131		assert_eq!(
132			stmt.database_name.as_ref().unwrap().to_string(),
133			"auxiliary"
134		);
135	}
136
137	#[rstest]
138	fn test_detach_database_take() {
139		let mut stmt = DetachDatabaseStatement::new();
140		stmt.name("auxiliary");
141		let taken = stmt.take();
142		assert!(stmt.database_name.is_none());
143		assert_eq!(
144			taken.database_name.as_ref().unwrap().to_string(),
145			"auxiliary"
146		);
147	}
148
149	#[rstest]
150	fn test_detach_database_default() {
151		let stmt = DetachDatabaseStatement::default();
152		assert!(stmt.database_name.is_none());
153	}
154
155	#[rstest]
156	fn test_detach_database_fluent_api() {
157		let mut stmt = DetachDatabaseStatement::new();
158		let result = stmt.name("test_db");
159		// Verify fluent API returns mutable reference
160		assert_eq!(
161			result.database_name.as_ref().unwrap().to_string(),
162			"test_db"
163		);
164	}
165}