Skip to main content

reinhardt_query/query/database/
create_database.rs

1//! CREATE DATABASE statement builder
2//!
3//! This module provides the `CreateDatabaseStatement` type for building SQL CREATE DATABASE queries.
4
5use crate::{
6	backend::QueryBuilder,
7	types::{DynIden, IntoIden},
8};
9
10use crate::query::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
11
12/// CREATE DATABASE statement builder
13///
14/// This struct provides a fluent API for constructing CREATE DATABASE queries.
15/// It supports both PostgreSQL and MySQL database creation options.
16///
17/// # Examples
18///
19/// ```rust
20/// use reinhardt_query::prelude::*;
21///
22/// // CREATE DATABASE mydb
23/// let query = Query::create_database()
24///     .name("mydb");
25///
26/// // CREATE DATABASE IF NOT EXISTS mydb
27/// let query = Query::create_database()
28///     .name("mydb")
29///     .if_not_exists();
30///
31/// // CREATE DATABASE mydb OWNER alice (PostgreSQL)
32/// let query = Query::create_database()
33///     .name("mydb")
34///     .owner("alice");
35///
36/// // CREATE DATABASE mydb TEMPLATE template0 ENCODING 'UTF8' (PostgreSQL)
37/// let query = Query::create_database()
38///     .name("mydb")
39///     .template("template0")
40///     .encoding("UTF8");
41///
42/// // CREATE DATABASE mydb CHARACTER SET utf8mb4 (MySQL)
43/// let query = Query::create_database()
44///     .name("mydb")
45///     .character_set("utf8mb4");
46/// ```
47#[derive(Debug, Clone)]
48pub struct CreateDatabaseStatement {
49	pub(crate) database_name: Option<DynIden>,
50	pub(crate) if_not_exists: bool,
51	pub(crate) owner: Option<DynIden>,
52	pub(crate) template: Option<DynIden>,
53	pub(crate) encoding: Option<String>,
54	pub(crate) lc_collate: Option<String>,
55	pub(crate) lc_ctype: Option<String>,
56	pub(crate) character_set: Option<String>,
57	pub(crate) collate: Option<String>,
58}
59
60impl CreateDatabaseStatement {
61	/// Create a new CREATE DATABASE statement
62	///
63	/// # Examples
64	///
65	/// ```rust
66	/// use reinhardt_query::prelude::*;
67	///
68	/// let query = Query::create_database();
69	/// ```
70	pub fn new() -> Self {
71		Self {
72			database_name: None,
73			if_not_exists: false,
74			owner: None,
75			template: None,
76			encoding: None,
77			lc_collate: None,
78			lc_ctype: None,
79			character_set: None,
80			collate: None,
81		}
82	}
83
84	/// Take the ownership of data in the current [`CreateDatabaseStatement`]
85	pub fn take(&mut self) -> Self {
86		Self {
87			database_name: self.database_name.take(),
88			if_not_exists: self.if_not_exists,
89			owner: self.owner.take(),
90			template: self.template.take(),
91			encoding: self.encoding.take(),
92			lc_collate: self.lc_collate.take(),
93			lc_ctype: self.lc_ctype.take(),
94			character_set: self.character_set.take(),
95			collate: self.collate.take(),
96		}
97	}
98
99	/// Set the database name
100	///
101	/// # Examples
102	///
103	/// ```rust
104	/// use reinhardt_query::prelude::*;
105	///
106	/// let query = Query::create_database()
107	///     .name("mydb");
108	/// ```
109	pub fn name<N>(&mut self, name: N) -> &mut Self
110	where
111		N: IntoIden,
112	{
113		self.database_name = Some(name.into_iden());
114		self
115	}
116
117	/// Add IF NOT EXISTS clause
118	///
119	/// # Examples
120	///
121	/// ```rust
122	/// use reinhardt_query::prelude::*;
123	///
124	/// let query = Query::create_database()
125	///     .name("mydb")
126	///     .if_not_exists();
127	/// ```
128	pub fn if_not_exists(&mut self) -> &mut Self {
129		self.if_not_exists = true;
130		self
131	}
132
133	/// Set OWNER (PostgreSQL)
134	///
135	/// # Examples
136	///
137	/// ```rust
138	/// use reinhardt_query::prelude::*;
139	///
140	/// let query = Query::create_database()
141	///     .name("mydb")
142	///     .owner("alice");
143	/// ```
144	pub fn owner<O>(&mut self, owner: O) -> &mut Self
145	where
146		O: IntoIden,
147	{
148		self.owner = Some(owner.into_iden());
149		self
150	}
151
152	/// Set TEMPLATE database (PostgreSQL)
153	///
154	/// # Examples
155	///
156	/// ```rust
157	/// use reinhardt_query::prelude::*;
158	///
159	/// let query = Query::create_database()
160	///     .name("mydb")
161	///     .template("template0");
162	/// ```
163	pub fn template<T>(&mut self, template: T) -> &mut Self
164	where
165		T: IntoIden,
166	{
167		self.template = Some(template.into_iden());
168		self
169	}
170
171	/// Set ENCODING (PostgreSQL)
172	///
173	/// # Examples
174	///
175	/// ```rust
176	/// use reinhardt_query::prelude::*;
177	///
178	/// let query = Query::create_database()
179	///     .name("mydb")
180	///     .encoding("UTF8");
181	/// ```
182	pub fn encoding<S>(&mut self, encoding: S) -> &mut Self
183	where
184		S: Into<String>,
185	{
186		self.encoding = Some(encoding.into());
187		self
188	}
189
190	/// Set LC_COLLATE (PostgreSQL)
191	///
192	/// # Examples
193	///
194	/// ```rust
195	/// use reinhardt_query::prelude::*;
196	///
197	/// let query = Query::create_database()
198	///     .name("mydb")
199	///     .lc_collate("en_US.UTF-8");
200	/// ```
201	pub fn lc_collate<S>(&mut self, lc_collate: S) -> &mut Self
202	where
203		S: Into<String>,
204	{
205		self.lc_collate = Some(lc_collate.into());
206		self
207	}
208
209	/// Set LC_CTYPE (PostgreSQL)
210	///
211	/// # Examples
212	///
213	/// ```rust
214	/// use reinhardt_query::prelude::*;
215	///
216	/// let query = Query::create_database()
217	///     .name("mydb")
218	///     .lc_ctype("en_US.UTF-8");
219	/// ```
220	pub fn lc_ctype<S>(&mut self, lc_ctype: S) -> &mut Self
221	where
222		S: Into<String>,
223	{
224		self.lc_ctype = Some(lc_ctype.into());
225		self
226	}
227
228	/// Set CHARACTER SET (MySQL)
229	///
230	/// # Examples
231	///
232	/// ```rust
233	/// use reinhardt_query::prelude::*;
234	///
235	/// let query = Query::create_database()
236	///     .name("mydb")
237	///     .character_set("utf8mb4");
238	/// ```
239	pub fn character_set<S>(&mut self, charset: S) -> &mut Self
240	where
241		S: Into<String>,
242	{
243		self.character_set = Some(charset.into());
244		self
245	}
246
247	/// Set COLLATE (MySQL/PostgreSQL)
248	///
249	/// # Examples
250	///
251	/// ```rust
252	/// use reinhardt_query::prelude::*;
253	///
254	/// let query = Query::create_database()
255	///     .name("mydb")
256	///     .collate("utf8mb4_unicode_ci");
257	/// ```
258	pub fn collate<S>(&mut self, collate: S) -> &mut Self
259	where
260		S: Into<String>,
261	{
262		self.collate = Some(collate.into());
263		self
264	}
265}
266
267impl Default for CreateDatabaseStatement {
268	fn default() -> Self {
269		Self::new()
270	}
271}
272
273impl QueryStatementBuilder for CreateDatabaseStatement {
274	fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, crate::value::Values) {
275		// Downcast to concrete QueryBuilder type
276		use std::any::Any;
277		if let Some(builder) =
278			(query_builder as &dyn Any).downcast_ref::<crate::backend::PostgresQueryBuilder>()
279		{
280			return builder.build_create_database(self);
281		}
282		if let Some(builder) =
283			(query_builder as &dyn Any).downcast_ref::<crate::backend::MySqlQueryBuilder>()
284		{
285			return builder.build_create_database(self);
286		}
287		if let Some(builder) =
288			(query_builder as &dyn Any).downcast_ref::<crate::backend::SqliteQueryBuilder>()
289		{
290			return builder.build_create_database(self);
291		}
292		if let Some(builder) =
293			(query_builder as &dyn Any).downcast_ref::<crate::backend::CockroachDBQueryBuilder>()
294		{
295			return builder.build_create_database(self);
296		}
297		panic!("Unsupported query builder type");
298	}
299}
300
301impl QueryStatementWriter for CreateDatabaseStatement {}
302
303#[cfg(test)]
304mod tests {
305	use super::*;
306	use rstest::*;
307
308	#[rstest]
309	fn test_create_database_new() {
310		let stmt = CreateDatabaseStatement::new();
311		assert!(stmt.database_name.is_none());
312		assert!(!stmt.if_not_exists);
313		assert!(stmt.owner.is_none());
314		assert!(stmt.template.is_none());
315		assert!(stmt.encoding.is_none());
316		assert!(stmt.lc_collate.is_none());
317		assert!(stmt.lc_ctype.is_none());
318		assert!(stmt.character_set.is_none());
319		assert!(stmt.collate.is_none());
320	}
321
322	#[rstest]
323	fn test_create_database_with_name() {
324		let mut stmt = CreateDatabaseStatement::new();
325		stmt.name("mydb");
326		assert_eq!(stmt.database_name.as_ref().unwrap().to_string(), "mydb");
327	}
328
329	#[rstest]
330	fn test_create_database_if_not_exists() {
331		let mut stmt = CreateDatabaseStatement::new();
332		stmt.name("mydb").if_not_exists();
333		assert!(stmt.if_not_exists);
334	}
335
336	#[rstest]
337	fn test_create_database_with_owner() {
338		let mut stmt = CreateDatabaseStatement::new();
339		stmt.name("mydb").owner("alice");
340		assert_eq!(stmt.owner.as_ref().unwrap().to_string(), "alice");
341	}
342
343	#[rstest]
344	fn test_create_database_with_template() {
345		let mut stmt = CreateDatabaseStatement::new();
346		stmt.name("mydb").template("template0");
347		assert_eq!(stmt.template.as_ref().unwrap().to_string(), "template0");
348	}
349
350	#[rstest]
351	fn test_create_database_with_encoding() {
352		let mut stmt = CreateDatabaseStatement::new();
353		stmt.name("mydb").encoding("UTF8");
354		assert_eq!(stmt.encoding.as_ref().unwrap(), "UTF8");
355	}
356
357	#[rstest]
358	fn test_create_database_with_lc_collate() {
359		let mut stmt = CreateDatabaseStatement::new();
360		stmt.name("mydb").lc_collate("en_US.UTF-8");
361		assert_eq!(stmt.lc_collate.as_ref().unwrap(), "en_US.UTF-8");
362	}
363
364	#[rstest]
365	fn test_create_database_with_lc_ctype() {
366		let mut stmt = CreateDatabaseStatement::new();
367		stmt.name("mydb").lc_ctype("en_US.UTF-8");
368		assert_eq!(stmt.lc_ctype.as_ref().unwrap(), "en_US.UTF-8");
369	}
370
371	#[rstest]
372	fn test_create_database_with_character_set() {
373		let mut stmt = CreateDatabaseStatement::new();
374		stmt.name("mydb").character_set("utf8mb4");
375		assert_eq!(stmt.character_set.as_ref().unwrap(), "utf8mb4");
376	}
377
378	#[rstest]
379	fn test_create_database_with_collate() {
380		let mut stmt = CreateDatabaseStatement::new();
381		stmt.name("mydb").collate("utf8mb4_unicode_ci");
382		assert_eq!(stmt.collate.as_ref().unwrap(), "utf8mb4_unicode_ci");
383	}
384
385	#[rstest]
386	fn test_create_database_postgresql_full() {
387		let mut stmt = CreateDatabaseStatement::new();
388		stmt.name("mydb")
389			.if_not_exists()
390			.owner("alice")
391			.template("template0")
392			.encoding("UTF8")
393			.lc_collate("en_US.UTF-8")
394			.lc_ctype("en_US.UTF-8");
395		assert_eq!(stmt.database_name.as_ref().unwrap().to_string(), "mydb");
396		assert!(stmt.if_not_exists);
397		assert_eq!(stmt.owner.as_ref().unwrap().to_string(), "alice");
398		assert_eq!(stmt.template.as_ref().unwrap().to_string(), "template0");
399		assert_eq!(stmt.encoding.as_ref().unwrap(), "UTF8");
400		assert_eq!(stmt.lc_collate.as_ref().unwrap(), "en_US.UTF-8");
401		assert_eq!(stmt.lc_ctype.as_ref().unwrap(), "en_US.UTF-8");
402	}
403
404	#[rstest]
405	fn test_create_database_mysql_full() {
406		let mut stmt = CreateDatabaseStatement::new();
407		stmt.name("mydb")
408			.if_not_exists()
409			.character_set("utf8mb4")
410			.collate("utf8mb4_unicode_ci");
411		assert_eq!(stmt.database_name.as_ref().unwrap().to_string(), "mydb");
412		assert!(stmt.if_not_exists);
413		assert_eq!(stmt.character_set.as_ref().unwrap(), "utf8mb4");
414		assert_eq!(stmt.collate.as_ref().unwrap(), "utf8mb4_unicode_ci");
415	}
416
417	#[rstest]
418	fn test_create_database_take() {
419		let mut stmt = CreateDatabaseStatement::new();
420		stmt.name("mydb").owner("alice");
421		let taken = stmt.take();
422		assert!(stmt.database_name.is_none());
423		assert!(stmt.owner.is_none());
424		assert_eq!(taken.database_name.as_ref().unwrap().to_string(), "mydb");
425		assert_eq!(taken.owner.as_ref().unwrap().to_string(), "alice");
426	}
427}