postgresql_commands/
createuser.rs1use crate::Settings;
2use crate::traits::CommandBuilder;
3use std::convert::AsRef;
4use std::ffi::{OsStr, OsString};
5use std::path::PathBuf;
6
7#[derive(Clone, Debug, Default)]
9pub struct CreateUserBuilder {
10 program_dir: Option<PathBuf>,
11 envs: Vec<(OsString, OsString)>,
12 with_admin: Option<OsString>,
13 connection_limit: Option<u32>,
14 createdb: bool,
15 no_createdb: bool,
16 echo: bool,
17 member_of: Option<OsString>,
18 inherit: bool,
19 no_inherit: bool,
20 login: bool,
21 no_login: bool,
22 with_member: Option<OsString>,
23 pwprompt: bool,
24 createrole: bool,
25 no_createrole: bool,
26 superuser: bool,
27 no_superuser: bool,
28 valid_until: Option<OsString>,
29 version: bool,
30 interactive: bool,
31 bypassrls: bool,
32 no_bypassrls: bool,
33 replication: bool,
34 no_replication: bool,
35 help: bool,
36 host: Option<OsString>,
37 port: Option<u16>,
38 username: Option<OsString>,
39 no_password: bool,
40 password: bool,
41 pg_password: Option<OsString>,
42}
43
44impl CreateUserBuilder {
45 #[must_use]
47 pub fn new() -> Self {
48 Self::default()
49 }
50
51 pub fn from(settings: &dyn Settings) -> Self {
53 let mut builder = Self::new()
54 .program_dir(settings.get_binary_dir())
55 .host(settings.get_host())
56 .port(settings.get_port())
57 .username(settings.get_username())
58 .pg_password(settings.get_password());
59 if let Some(socket_dir) = settings.get_socket_dir() {
60 builder = builder.host(socket_dir.to_string_lossy().to_string());
61 }
62 builder
63 }
64
65 #[must_use]
67 pub fn program_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
68 self.program_dir = Some(path.into());
69 self
70 }
71
72 #[must_use]
74 pub fn with_admin<S: AsRef<OsStr>>(mut self, role: S) -> Self {
75 self.with_admin = Some(role.as_ref().to_os_string());
76 self
77 }
78
79 #[must_use]
81 pub fn connection_limit(mut self, limit: u32) -> Self {
82 self.connection_limit = Some(limit);
83 self
84 }
85
86 #[must_use]
88 pub fn createdb(mut self) -> Self {
89 self.createdb = true;
90 self
91 }
92
93 #[must_use]
95 pub fn no_createdb(mut self) -> Self {
96 self.no_createdb = true;
97 self
98 }
99
100 #[must_use]
102 pub fn echo(mut self) -> Self {
103 self.echo = true;
104 self
105 }
106
107 #[must_use]
109 pub fn member_of<S: AsRef<OsStr>>(mut self, role: S) -> Self {
110 self.member_of = Some(role.as_ref().to_os_string());
111 self
112 }
113
114 #[must_use]
116 pub fn inherit(mut self) -> Self {
117 self.inherit = true;
118 self
119 }
120
121 #[must_use]
123 pub fn no_inherit(mut self) -> Self {
124 self.no_inherit = true;
125 self
126 }
127
128 #[must_use]
130 pub fn login(mut self) -> Self {
131 self.login = true;
132 self
133 }
134
135 #[must_use]
137 pub fn no_login(mut self) -> Self {
138 self.no_login = true;
139 self
140 }
141
142 #[must_use]
144 pub fn with_member<S: AsRef<OsStr>>(mut self, role: S) -> Self {
145 self.with_member = Some(role.as_ref().to_os_string());
146 self
147 }
148
149 #[must_use]
151 pub fn pwprompt(mut self) -> Self {
152 self.pwprompt = true;
153 self
154 }
155
156 #[must_use]
158 pub fn createrole(mut self) -> Self {
159 self.createrole = true;
160 self
161 }
162
163 #[must_use]
165 pub fn no_createrole(mut self) -> Self {
166 self.no_createrole = true;
167 self
168 }
169
170 #[must_use]
172 pub fn superuser(mut self) -> Self {
173 self.superuser = true;
174 self
175 }
176
177 #[must_use]
179 pub fn no_superuser(mut self) -> Self {
180 self.no_superuser = true;
181 self
182 }
183
184 #[must_use]
186 pub fn valid_until<S: AsRef<OsStr>>(mut self, timestamp: S) -> Self {
187 self.valid_until = Some(timestamp.as_ref().to_os_string());
188 self
189 }
190
191 #[must_use]
193 pub fn version(mut self) -> Self {
194 self.version = true;
195 self
196 }
197
198 #[must_use]
200 pub fn interactive(mut self) -> Self {
201 self.interactive = true;
202 self
203 }
204
205 #[must_use]
207 pub fn bypassrls(mut self) -> Self {
208 self.bypassrls = true;
209 self
210 }
211
212 #[must_use]
214 pub fn no_bypassrls(mut self) -> Self {
215 self.no_bypassrls = true;
216 self
217 }
218
219 #[must_use]
221 pub fn replication(mut self) -> Self {
222 self.replication = true;
223 self
224 }
225
226 #[must_use]
228 pub fn no_replication(mut self) -> Self {
229 self.no_replication = true;
230 self
231 }
232
233 #[must_use]
235 pub fn help(mut self) -> Self {
236 self.help = true;
237 self
238 }
239
240 #[must_use]
242 pub fn host<S: AsRef<OsStr>>(mut self, host: S) -> Self {
243 self.host = Some(host.as_ref().to_os_string());
244 self
245 }
246
247 #[must_use]
249 pub fn port(mut self, port: u16) -> Self {
250 self.port = Some(port);
251 self
252 }
253
254 #[must_use]
256 pub fn username<S: AsRef<OsStr>>(mut self, username: S) -> Self {
257 self.username = Some(username.as_ref().to_os_string());
258 self
259 }
260
261 #[must_use]
263 pub fn no_password(mut self) -> Self {
264 self.no_password = true;
265 self
266 }
267
268 #[must_use]
270 pub fn password(mut self) -> Self {
271 self.password = true;
272 self
273 }
274
275 #[must_use]
277 pub fn pg_password<S: AsRef<OsStr>>(mut self, pg_password: S) -> Self {
278 self.pg_password = Some(pg_password.as_ref().to_os_string());
279 self
280 }
281}
282
283impl CommandBuilder for CreateUserBuilder {
284 fn get_program(&self) -> &'static OsStr {
286 "createuser".as_ref()
287 }
288
289 fn get_program_dir(&self) -> &Option<PathBuf> {
291 &self.program_dir
292 }
293
294 fn get_args(&self) -> Vec<OsString> {
296 let mut args: Vec<OsString> = Vec::new();
297
298 if let Some(role) = &self.with_admin {
299 args.push("--with-admin".into());
300 args.push(role.into());
301 }
302
303 if let Some(limit) = &self.connection_limit {
304 args.push("--connection-limit".into());
305 args.push(limit.to_string().into());
306 }
307
308 if self.createdb {
309 args.push("--createdb".into());
310 }
311
312 if self.no_createdb {
313 args.push("--no-createdb".into());
314 }
315
316 if self.echo {
317 args.push("--echo".into());
318 }
319
320 if let Some(role) = &self.member_of {
321 args.push("--member-of".into());
322 args.push(role.into());
323 }
324
325 if self.inherit {
326 args.push("--inherit".into());
327 }
328
329 if self.no_inherit {
330 args.push("--no-inherit".into());
331 }
332
333 if self.login {
334 args.push("--login".into());
335 }
336
337 if self.no_login {
338 args.push("--no-login".into());
339 }
340
341 if let Some(role) = &self.with_member {
342 args.push("--with-member".into());
343 args.push(role.into());
344 }
345
346 if self.pwprompt {
347 args.push("--pwprompt".into());
348 }
349
350 if self.createrole {
351 args.push("--createrole".into());
352 }
353
354 if self.no_createrole {
355 args.push("--no-createrole".into());
356 }
357
358 if self.superuser {
359 args.push("--superuser".into());
360 }
361
362 if self.no_superuser {
363 args.push("--no-superuser".into());
364 }
365
366 if let Some(timestamp) = &self.valid_until {
367 args.push("--valid-until".into());
368 args.push(timestamp.into());
369 }
370
371 if self.version {
372 args.push("--version".into());
373 }
374
375 if self.interactive {
376 args.push("--interactive".into());
377 }
378
379 if self.bypassrls {
380 args.push("--bypassrls".into());
381 }
382
383 if self.no_bypassrls {
384 args.push("--no-bypassrls".into());
385 }
386
387 if self.replication {
388 args.push("--replication".into());
389 }
390
391 if self.no_replication {
392 args.push("--no-replication".into());
393 }
394
395 if self.help {
396 args.push("--help".into());
397 }
398
399 if let Some(host) = &self.host {
400 args.push("--host".into());
401 args.push(host.into());
402 }
403
404 if let Some(port) = &self.port {
405 args.push("--port".into());
406 args.push(port.to_string().into());
407 }
408
409 if let Some(username) = &self.username {
410 args.push("--username".into());
411 args.push(username.into());
412 }
413
414 if self.no_password {
415 args.push("--no-password".into());
416 }
417
418 if self.password {
419 args.push("--password".into());
420 }
421
422 args
423 }
424
425 fn get_envs(&self) -> Vec<(OsString, OsString)> {
427 let mut envs: Vec<(OsString, OsString)> = self.envs.clone();
428
429 if let Some(password) = &self.pg_password {
430 envs.push(("PGPASSWORD".into(), password.into()));
431 }
432
433 envs
434 }
435
436 fn env<S: AsRef<OsStr>>(mut self, key: S, value: S) -> Self {
438 self.envs
439 .push((key.as_ref().to_os_string(), value.as_ref().to_os_string()));
440 self
441 }
442}
443
444#[cfg(test)]
445mod tests {
446 use super::*;
447 use crate::TestSettings;
448 use crate::TestSocketSettings;
449 use crate::traits::CommandToString;
450 use test_log::test;
451
452 #[test]
453 fn test_builder_new() {
454 let command = CreateUserBuilder::new().program_dir(".").build();
455 assert_eq!(
456 PathBuf::from(".").join("createuser"),
457 PathBuf::from(command.to_command_string().replace('"', ""))
458 );
459 }
460
461 #[test]
462 fn test_builder_from() {
463 let command = CreateUserBuilder::from(&TestSettings).build();
464 #[cfg(not(target_os = "windows"))]
465 let command_prefix = r#"PGPASSWORD="password" "./createuser" "#;
466 #[cfg(target_os = "windows")]
467 let command_prefix = r#"".\\createuser" "#;
468
469 assert_eq!(
470 format!(
471 r#"{command_prefix}"--host" "localhost" "--port" "5432" "--username" "postgres""#
472 ),
473 command.to_command_string()
474 );
475 }
476
477 #[test]
478 fn test_builder() {
479 let command = CreateUserBuilder::new()
480 .env("PGDATABASE", "database")
481 .with_admin("admin")
482 .connection_limit(10)
483 .createdb()
484 .no_createdb()
485 .echo()
486 .member_of("member")
487 .inherit()
488 .no_inherit()
489 .login()
490 .no_login()
491 .with_member("member")
492 .pwprompt()
493 .createrole()
494 .no_createrole()
495 .superuser()
496 .no_superuser()
497 .valid_until("2021-12-31")
498 .version()
499 .interactive()
500 .bypassrls()
501 .no_bypassrls()
502 .replication()
503 .no_replication()
504 .help()
505 .host("localhost")
506 .port(5432)
507 .username("username")
508 .no_password()
509 .password()
510 .pg_password("password")
511 .build();
512 #[cfg(not(target_os = "windows"))]
513 let command_prefix = r#"PGDATABASE="database" PGPASSWORD="password" "#;
514 #[cfg(target_os = "windows")]
515 let command_prefix = String::new();
516
517 assert_eq!(
518 format!(
519 r#"{command_prefix}"createuser" "--with-admin" "admin" "--connection-limit" "10" "--createdb" "--no-createdb" "--echo" "--member-of" "member" "--inherit" "--no-inherit" "--login" "--no-login" "--with-member" "member" "--pwprompt" "--createrole" "--no-createrole" "--superuser" "--no-superuser" "--valid-until" "2021-12-31" "--version" "--interactive" "--bypassrls" "--no-bypassrls" "--replication" "--no-replication" "--help" "--host" "localhost" "--port" "5432" "--username" "username" "--no-password" "--password""#
520 ),
521 command.to_command_string()
522 );
523 }
524
525 #[test]
526 fn test_builder_from_socket() {
527 let command = CreateUserBuilder::from(&TestSocketSettings).build();
528 #[cfg(not(target_os = "windows"))]
529 let command_prefix = r#"PGPASSWORD="password" "./createuser" "#;
530 #[cfg(target_os = "windows")]
531 let command_prefix = r#"".\\createuser" "#;
532
533 assert_eq!(
534 format!(
535 r#"{command_prefix}"--host" "/tmp/pg_socket" "--port" "5432" "--username" "postgres""#
536 ),
537 command.to_command_string()
538 );
539 }
540}