reinhardt_query/dcl/set_default_role.rs
1//! SET DEFAULT ROLE statement builder (MySQL only)
2//!
3//! This module provides a fluent API for building SET DEFAULT ROLE statements for MySQL.
4//!
5//! # MySQL Only
6//!
7//! SET DEFAULT ROLE is a MySQL-specific command that sets which roles should be
8//! activated by default when a user connects.
9//!
10//! # PostgreSQL & SQLite
11//!
12//! These databases do not support SET DEFAULT ROLE. Attempting to generate SQL for
13//! these backends will result in a panic.
14//!
15//! # Examples
16//!
17//! Set specific default roles:
18//!
19//! ```
20//! use reinhardt_query::dcl::{SetDefaultRoleStatement, DefaultRoleSpec};
21//!
22//! let stmt = SetDefaultRoleStatement::new()
23//! .roles(DefaultRoleSpec::RoleList(vec!["app_role".to_string()]))
24//! .user("app_user@localhost");
25//! ```
26//!
27//! Set all roles as default:
28//!
29//! ```
30//! use reinhardt_query::dcl::{SetDefaultRoleStatement, DefaultRoleSpec};
31//!
32//! let stmt = SetDefaultRoleStatement::new()
33//! .roles(DefaultRoleSpec::All)
34//! .user("app_user@localhost");
35//! ```
36
37use super::validate_name;
38
39/// Default role specification for SET DEFAULT ROLE statement
40///
41/// This enum specifies which roles should be set as default.
42///
43/// # Variants
44///
45/// - `` `RoleList` `` - Specific list of roles
46/// - `` `All` `` - All granted roles
47/// - `` `None` `` - No default roles
48#[derive(Debug, Clone, PartialEq)]
49pub enum DefaultRoleSpec {
50 /// SET DEFAULT ROLE role1, role2, ... TO user
51 RoleList(Vec<String>),
52 /// SET DEFAULT ROLE ALL TO user
53 All,
54 /// SET DEFAULT ROLE NONE TO user
55 None,
56}
57
58/// SET DEFAULT ROLE statement builder (MySQL only)
59///
60/// This struct provides a fluent API for building SET DEFAULT ROLE statements.
61/// This is a MySQL-specific feature.
62///
63/// # MySQL
64///
65/// MySQL SET DEFAULT ROLE sets which roles are activated by default when users connect.
66/// Supports:
67/// - Specific roles: `SET DEFAULT ROLE role1, role2 TO user`
68/// - All roles: `SET DEFAULT ROLE ALL TO user`
69/// - No roles: `SET DEFAULT ROLE NONE TO user`
70///
71/// # Examples
72///
73/// Set specific default roles:
74///
75/// ```
76/// use reinhardt_query::dcl::{SetDefaultRoleStatement, DefaultRoleSpec};
77///
78/// let stmt = SetDefaultRoleStatement::new()
79/// .roles(DefaultRoleSpec::RoleList(vec!["app_role".to_string()]))
80/// .user("app_user@localhost");
81/// ```
82///
83/// Set all roles as default:
84///
85/// ```
86/// use reinhardt_query::dcl::{SetDefaultRoleStatement, DefaultRoleSpec};
87///
88/// let stmt = SetDefaultRoleStatement::new()
89/// .roles(DefaultRoleSpec::All)
90/// .users(vec!["user1@localhost".to_string(), "user2@localhost".to_string()]);
91/// ```
92///
93/// Clear default roles:
94///
95/// ```
96/// use reinhardt_query::dcl::{SetDefaultRoleStatement, DefaultRoleSpec};
97///
98/// let stmt = SetDefaultRoleStatement::new()
99/// .roles(DefaultRoleSpec::None)
100/// .user("app_user@localhost");
101/// ```
102#[derive(Debug, Clone, Default)]
103pub struct SetDefaultRoleStatement {
104 /// Role specification (ALL, NONE, or specific roles)
105 pub role_spec: Option<DefaultRoleSpec>,
106 /// Target users (with optional @host)
107 pub user_names: Vec<String>,
108}
109
110impl SetDefaultRoleStatement {
111 /// Create a new SET DEFAULT ROLE statement
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use reinhardt_query::dcl::SetDefaultRoleStatement;
117 ///
118 /// let stmt = SetDefaultRoleStatement::new();
119 /// ```
120 pub fn new() -> Self {
121 Self::default()
122 }
123
124 /// Set the role specification
125 ///
126 /// # Examples
127 ///
128 /// ```
129 /// use reinhardt_query::dcl::{SetDefaultRoleStatement, DefaultRoleSpec};
130 ///
131 /// let stmt = SetDefaultRoleStatement::new()
132 /// .roles(DefaultRoleSpec::RoleList(vec!["app_role".to_string()]));
133 /// ```
134 pub fn roles(mut self, spec: DefaultRoleSpec) -> Self {
135 self.role_spec = Some(spec);
136 self
137 }
138
139 /// Add a single target user
140 ///
141 /// # Examples
142 ///
143 /// ```
144 /// use reinhardt_query::dcl::{SetDefaultRoleStatement, DefaultRoleSpec};
145 ///
146 /// let stmt = SetDefaultRoleStatement::new()
147 /// .roles(DefaultRoleSpec::All)
148 /// .user("app_user@localhost");
149 /// ```
150 pub fn user(mut self, name: impl Into<String>) -> Self {
151 self.user_names.push(name.into());
152 self
153 }
154
155 /// Set all target users at once
156 ///
157 /// # Examples
158 ///
159 /// ```
160 /// use reinhardt_query::dcl::{SetDefaultRoleStatement, DefaultRoleSpec};
161 ///
162 /// let stmt = SetDefaultRoleStatement::new()
163 /// .roles(DefaultRoleSpec::All)
164 /// .users(vec!["user1@localhost".to_string(), "user2@localhost".to_string()]);
165 /// ```
166 pub fn users(mut self, names: Vec<String>) -> Self {
167 self.user_names = names;
168 self
169 }
170
171 /// Validate the SET DEFAULT ROLE statement
172 ///
173 /// # Validation Rules
174 ///
175 /// 1. Role specification must be set
176 /// 2. At least one user must be specified
177 /// 3. For RoleList variant, role list cannot be empty
178 ///
179 /// # Examples
180 ///
181 /// ```
182 /// use reinhardt_query::dcl::{SetDefaultRoleStatement, DefaultRoleSpec};
183 ///
184 /// let stmt = SetDefaultRoleStatement::new()
185 /// .roles(DefaultRoleSpec::All)
186 /// .user("app_user@localhost");
187 ///
188 /// assert!(stmt.validate().is_ok());
189 /// ```
190 ///
191 /// ```
192 /// use reinhardt_query::dcl::SetDefaultRoleStatement;
193 ///
194 /// let stmt = SetDefaultRoleStatement::new();
195 /// assert!(stmt.validate().is_err());
196 /// ```
197 pub fn validate(&self) -> Result<(), String> {
198 if self.role_spec.is_none() {
199 return Err("Role specification must be set".to_string());
200 }
201 if self.user_names.is_empty() {
202 return Err("At least one user must be specified".to_string());
203 }
204 for user_name in &self.user_names {
205 validate_name(user_name, "User name")?;
206 }
207 if let Some(DefaultRoleSpec::RoleList(roles)) = &self.role_spec
208 && roles.is_empty()
209 {
210 return Err("Role list cannot be empty".to_string());
211 }
212 Ok(())
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn test_set_default_role_new() {
222 let stmt = SetDefaultRoleStatement::new();
223 assert!(stmt.role_spec.is_none());
224 assert!(stmt.user_names.is_empty());
225 }
226
227 #[test]
228 fn test_set_default_role_basic() {
229 let stmt = SetDefaultRoleStatement::new()
230 .roles(DefaultRoleSpec::All)
231 .user("app_user@localhost");
232 assert!(matches!(stmt.role_spec, Some(DefaultRoleSpec::All)));
233 assert_eq!(stmt.user_names.len(), 1);
234 assert!(stmt.validate().is_ok());
235 }
236
237 #[test]
238 fn test_set_default_role_role_list() {
239 let stmt = SetDefaultRoleStatement::new()
240 .roles(DefaultRoleSpec::RoleList(vec!["role1".to_string()]))
241 .user("app_user");
242 assert!(matches!(stmt.role_spec, Some(DefaultRoleSpec::RoleList(_))));
243 assert!(stmt.validate().is_ok());
244 }
245
246 #[test]
247 fn test_set_default_role_none() {
248 let stmt = SetDefaultRoleStatement::new()
249 .roles(DefaultRoleSpec::None)
250 .user("app_user");
251 assert!(matches!(stmt.role_spec, Some(DefaultRoleSpec::None)));
252 assert!(stmt.validate().is_ok());
253 }
254
255 #[test]
256 fn test_set_default_role_multiple_users() {
257 let stmt = SetDefaultRoleStatement::new()
258 .roles(DefaultRoleSpec::All)
259 .user("user1")
260 .user("user2");
261 assert_eq!(stmt.user_names.len(), 2);
262 }
263
264 #[test]
265 fn test_set_default_role_validation_no_spec() {
266 let stmt = SetDefaultRoleStatement::new().user("app_user");
267 assert!(stmt.validate().is_err());
268 }
269
270 #[test]
271 fn test_set_default_role_validation_no_users() {
272 let stmt = SetDefaultRoleStatement::new().roles(DefaultRoleSpec::All);
273 assert!(stmt.validate().is_err());
274 }
275
276 #[test]
277 fn test_set_default_role_validation_empty_role_list() {
278 let stmt = SetDefaultRoleStatement::new()
279 .roles(DefaultRoleSpec::RoleList(vec![]))
280 .user("app_user");
281 assert!(stmt.validate().is_err());
282 }
283}