Skip to main content

reinhardt_query/dcl/
create_role.rs

1//! CREATE ROLE statement builder
2//!
3//! This module provides a fluent API for building CREATE ROLE statements for both
4//! PostgreSQL and MySQL databases.
5//!
6//! # Examples
7//!
8//! PostgreSQL example:
9//!
10//! ```
11//! use reinhardt_query::dcl::{CreateRoleStatement, RoleAttribute};
12//!
13//! let stmt = CreateRoleStatement::new()
14//!     .role("app_user")
15//!     .attribute(RoleAttribute::Login)
16//!     .attribute(RoleAttribute::Password("secret".to_string()));
17//! ```
18//!
19//! MySQL example:
20//!
21//! ```
22//! use reinhardt_query::dcl::{CreateRoleStatement, UserOption};
23//!
24//! let stmt = CreateRoleStatement::new()
25//!     .role("app_role")
26//!     .if_not_exists(true)
27//!     .option(UserOption::Comment("Application role".to_string()));
28//! ```
29
30use super::{RoleAttribute, UserOption, validate_name};
31
32/// CREATE ROLE statement builder
33///
34/// This struct provides a fluent API for building CREATE ROLE statements.
35/// It supports both PostgreSQL attributes and MySQL options.
36///
37/// # PostgreSQL
38///
39/// PostgreSQL CREATE ROLE accepts various attributes that control role privileges
40/// and settings. Use the `` `attribute()` `` method to add attributes.
41///
42/// # MySQL
43///
44/// MySQL CREATE ROLE supports IF NOT EXISTS clause and user options.
45/// Use the `` `if_not_exists()` `` and `` `option()` `` methods.
46///
47/// # Examples
48///
49/// Create a simple role:
50///
51/// ```
52/// use reinhardt_query::dcl::CreateRoleStatement;
53///
54/// let stmt = CreateRoleStatement::new()
55///     .role("developer");
56/// ```
57///
58/// Create a login role with password (PostgreSQL):
59///
60/// ```
61/// use reinhardt_query::dcl::{CreateRoleStatement, RoleAttribute};
62///
63/// let stmt = CreateRoleStatement::new()
64///     .role("app_user")
65///     .attribute(RoleAttribute::Login)
66///     .attribute(RoleAttribute::Password("password123".to_string()))
67///     .attribute(RoleAttribute::ConnectionLimit(5));
68/// ```
69///
70/// Create a role with IF NOT EXISTS (MySQL):
71///
72/// ```
73/// use reinhardt_query::dcl::{CreateRoleStatement, UserOption};
74///
75/// let stmt = CreateRoleStatement::new()
76///     .role("app_role")
77///     .if_not_exists(true)
78///     .option(UserOption::Comment("My application role".to_string()));
79/// ```
80#[derive(Debug, Clone, Default)]
81pub struct CreateRoleStatement {
82	/// Role name
83	pub role_name: String,
84	/// IF NOT EXISTS clause (MySQL only)
85	pub if_not_exists: bool,
86	/// PostgreSQL role attributes
87	pub attributes: Vec<RoleAttribute>,
88	/// MySQL user options
89	pub options: Vec<UserOption>,
90}
91
92impl CreateRoleStatement {
93	/// Create a new CREATE ROLE statement
94	///
95	/// # Examples
96	///
97	/// ```
98	/// use reinhardt_query::dcl::CreateRoleStatement;
99	///
100	/// let stmt = CreateRoleStatement::new();
101	/// ```
102	pub fn new() -> Self {
103		Self::default()
104	}
105
106	/// Set the role name
107	///
108	/// # Examples
109	///
110	/// ```
111	/// use reinhardt_query::dcl::CreateRoleStatement;
112	///
113	/// let stmt = CreateRoleStatement::new()
114	///     .role("developer");
115	/// ```
116	pub fn role(mut self, name: impl Into<String>) -> Self {
117		self.role_name = name.into();
118		self
119	}
120
121	/// Set IF NOT EXISTS flag (MySQL only)
122	///
123	/// # Examples
124	///
125	/// ```
126	/// use reinhardt_query::dcl::CreateRoleStatement;
127	///
128	/// let stmt = CreateRoleStatement::new()
129	///     .role("app_role")
130	///     .if_not_exists(true);
131	/// ```
132	pub fn if_not_exists(mut self, flag: bool) -> Self {
133		self.if_not_exists = flag;
134		self
135	}
136
137	/// Add a single PostgreSQL role attribute
138	///
139	/// # Examples
140	///
141	/// ```
142	/// use reinhardt_query::dcl::{CreateRoleStatement, RoleAttribute};
143	///
144	/// let stmt = CreateRoleStatement::new()
145	///     .role("app_user")
146	///     .attribute(RoleAttribute::Login)
147	///     .attribute(RoleAttribute::CreateDb);
148	/// ```
149	pub fn attribute(mut self, attr: RoleAttribute) -> Self {
150		self.attributes.push(attr);
151		self
152	}
153
154	/// Set all PostgreSQL role attributes at once
155	///
156	/// # Examples
157	///
158	/// ```
159	/// use reinhardt_query::dcl::{CreateRoleStatement, RoleAttribute};
160	///
161	/// let stmt = CreateRoleStatement::new()
162	///     .role("app_user")
163	///     .attributes(vec![
164	///         RoleAttribute::Login,
165	///         RoleAttribute::CreateDb,
166	///         RoleAttribute::ConnectionLimit(10),
167	///     ]);
168	/// ```
169	pub fn attributes(mut self, attrs: Vec<RoleAttribute>) -> Self {
170		self.attributes = attrs;
171		self
172	}
173
174	/// Add a single MySQL user option
175	///
176	/// # Examples
177	///
178	/// ```
179	/// use reinhardt_query::dcl::{CreateRoleStatement, UserOption};
180	///
181	/// let stmt = CreateRoleStatement::new()
182	///     .role("app_role")
183	///     .option(UserOption::Comment("Application role".to_string()));
184	/// ```
185	pub fn option(mut self, opt: UserOption) -> Self {
186		self.options.push(opt);
187		self
188	}
189
190	/// Set all MySQL user options at once
191	///
192	/// # Examples
193	///
194	/// ```
195	/// use reinhardt_query::dcl::{CreateRoleStatement, UserOption};
196	///
197	/// let stmt = CreateRoleStatement::new()
198	///     .role("app_role")
199	///     .options(vec![
200	///         UserOption::Comment("Application role".to_string()),
201	///         UserOption::AccountLock,
202	///     ]);
203	/// ```
204	pub fn options(mut self, opts: Vec<UserOption>) -> Self {
205		self.options = opts;
206		self
207	}
208
209	/// Validate the CREATE ROLE statement
210	///
211	/// # Validation Rules
212	///
213	/// 1. Role name cannot be empty
214	///
215	/// # Examples
216	///
217	/// ```
218	/// use reinhardt_query::dcl::CreateRoleStatement;
219	///
220	/// let stmt = CreateRoleStatement::new()
221	///     .role("developer");
222	///
223	/// assert!(stmt.validate().is_ok());
224	/// ```
225	///
226	/// ```
227	/// use reinhardt_query::dcl::CreateRoleStatement;
228	///
229	/// let stmt = CreateRoleStatement::new();
230	/// assert!(stmt.validate().is_err());
231	/// ```
232	pub fn validate(&self) -> Result<(), String> {
233		validate_name(&self.role_name, "Role name")?;
234		Ok(())
235	}
236}