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}