postgresql_commands/
createdb.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 CreateDbBuilder {
10 program_dir: Option<PathBuf>,
11 envs: Vec<(OsString, OsString)>,
12 tablespace: Option<OsString>,
13 echo: bool,
14 encoding: Option<OsString>,
15 locale: Option<OsString>,
16 lc_collate: Option<OsString>,
17 lc_ctype: Option<OsString>,
18 icu_locale: Option<OsString>,
19 icu_rules: Option<OsString>,
20 locale_provider: Option<OsString>,
21 owner: Option<OsString>,
22 strategy: Option<OsString>,
23 template: Option<OsString>,
24 version: bool,
25 help: bool,
26 host: Option<OsString>,
27 port: Option<u16>,
28 username: Option<OsString>,
29 no_password: bool,
30 password: bool,
31 pg_password: Option<OsString>,
32 maintenance_db: Option<OsString>,
33 dbname: Option<OsString>,
34 description: Option<OsString>,
35}
36
37impl CreateDbBuilder {
38 #[must_use]
40 pub fn new() -> Self {
41 Self::default()
42 }
43
44 pub fn from(settings: &dyn Settings) -> Self {
46 Self::new()
47 .program_dir(settings.get_binary_dir())
48 .host(settings.get_host())
49 .port(settings.get_port())
50 .username(settings.get_username())
51 .pg_password(settings.get_password())
52 }
53
54 #[must_use]
56 pub fn program_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
57 self.program_dir = Some(path.into());
58 self
59 }
60
61 #[must_use]
63 pub fn tablespace<S: AsRef<OsStr>>(mut self, tablespace: S) -> Self {
64 self.tablespace = Some(tablespace.as_ref().to_os_string());
65 self
66 }
67
68 #[must_use]
70 pub fn echo(mut self) -> Self {
71 self.echo = true;
72 self
73 }
74
75 #[must_use]
77 pub fn encoding<S: AsRef<OsStr>>(mut self, encoding: S) -> Self {
78 self.encoding = Some(encoding.as_ref().to_os_string());
79 self
80 }
81
82 #[must_use]
84 pub fn locale<S: AsRef<OsStr>>(mut self, locale: S) -> Self {
85 self.locale = Some(locale.as_ref().to_os_string());
86 self
87 }
88
89 #[must_use]
91 pub fn lc_collate<S: AsRef<OsStr>>(mut self, lc_collate: S) -> Self {
92 self.lc_collate = Some(lc_collate.as_ref().to_os_string());
93 self
94 }
95
96 #[must_use]
98 pub fn lc_ctype<S: AsRef<OsStr>>(mut self, lc_ctype: S) -> Self {
99 self.lc_ctype = Some(lc_ctype.as_ref().to_os_string());
100 self
101 }
102
103 #[must_use]
105 pub fn icu_locale<S: AsRef<OsStr>>(mut self, icu_locale: S) -> Self {
106 self.icu_locale = Some(icu_locale.as_ref().to_os_string());
107 self
108 }
109
110 #[must_use]
112 pub fn icu_rules<S: AsRef<OsStr>>(mut self, icu_rules: S) -> Self {
113 self.icu_rules = Some(icu_rules.as_ref().to_os_string());
114 self
115 }
116
117 #[must_use]
119 pub fn locale_provider<S: AsRef<OsStr>>(mut self, locale_provider: S) -> Self {
120 self.locale_provider = Some(locale_provider.as_ref().to_os_string());
121 self
122 }
123
124 #[must_use]
126 pub fn owner<S: AsRef<OsStr>>(mut self, owner: S) -> Self {
127 self.owner = Some(owner.as_ref().to_os_string());
128 self
129 }
130
131 #[must_use]
133 pub fn strategy<S: AsRef<OsStr>>(mut self, strategy: S) -> Self {
134 self.strategy = Some(strategy.as_ref().to_os_string());
135 self
136 }
137
138 #[must_use]
140 pub fn template<S: AsRef<OsStr>>(mut self, template: S) -> Self {
141 self.template = Some(template.as_ref().to_os_string());
142 self
143 }
144
145 #[must_use]
147 pub fn version(mut self) -> Self {
148 self.version = true;
149 self
150 }
151
152 #[must_use]
154 pub fn help(mut self) -> Self {
155 self.help = true;
156 self
157 }
158
159 #[must_use]
161 pub fn host<S: AsRef<OsStr>>(mut self, host: S) -> Self {
162 self.host = Some(host.as_ref().to_os_string());
163 self
164 }
165
166 #[must_use]
168 pub fn port(mut self, port: u16) -> Self {
169 self.port = Some(port);
170 self
171 }
172
173 #[must_use]
175 pub fn username<S: AsRef<OsStr>>(mut self, username: S) -> Self {
176 self.username = Some(username.as_ref().to_os_string());
177 self
178 }
179
180 #[must_use]
182 pub fn no_password(mut self) -> Self {
183 self.no_password = true;
184 self
185 }
186
187 #[must_use]
189 pub fn password(mut self) -> Self {
190 self.password = true;
191 self
192 }
193
194 #[must_use]
196 pub fn pg_password<S: AsRef<OsStr>>(mut self, pg_password: S) -> Self {
197 self.pg_password = Some(pg_password.as_ref().to_os_string());
198 self
199 }
200
201 #[must_use]
203 pub fn maintenance_db<S: AsRef<OsStr>>(mut self, db: S) -> Self {
204 self.maintenance_db = Some(db.as_ref().to_os_string());
205 self
206 }
207
208 #[must_use]
210 pub fn dbname<S: AsRef<OsStr>>(mut self, dbname: S) -> Self {
211 self.dbname = Some(dbname.as_ref().to_os_string());
212 self
213 }
214
215 #[must_use]
217 pub fn description<S: AsRef<OsStr>>(mut self, description: S) -> Self {
218 self.description = Some(description.as_ref().to_os_string());
219 self
220 }
221}
222
223impl CommandBuilder for CreateDbBuilder {
224 fn get_program(&self) -> &'static OsStr {
226 "createdb".as_ref()
227 }
228
229 fn get_program_dir(&self) -> &Option<PathBuf> {
231 &self.program_dir
232 }
233
234 fn get_args(&self) -> Vec<OsString> {
236 let mut args: Vec<OsString> = Vec::new();
237
238 if let Some(tablespace) = &self.tablespace {
239 args.push("--tablespace".into());
240 args.push(tablespace.into());
241 }
242
243 if self.echo {
244 args.push("--echo".into());
245 }
246
247 if let Some(encoding) = &self.encoding {
248 args.push("--encoding".into());
249 args.push(encoding.into());
250 }
251
252 if let Some(locale) = &self.locale {
253 args.push("--locale".into());
254 args.push(locale.into());
255 }
256
257 if let Some(lc_collate) = &self.lc_collate {
258 args.push("--lc-collate".into());
259 args.push(lc_collate.into());
260 }
261
262 if let Some(lc_ctype) = &self.lc_ctype {
263 args.push("--lc-ctype".into());
264 args.push(lc_ctype.into());
265 }
266
267 if let Some(icu_locale) = &self.icu_locale {
268 args.push("--icu-locale".into());
269 args.push(icu_locale.into());
270 }
271
272 if let Some(icu_rules) = &self.icu_rules {
273 args.push("--icu-rules".into());
274 args.push(icu_rules.into());
275 }
276
277 if let Some(locale_provider) = &self.locale_provider {
278 args.push("--locale-provider".into());
279 args.push(locale_provider.into());
280 }
281
282 if let Some(owner) = &self.owner {
283 args.push("--owner".into());
284 args.push(owner.into());
285 }
286
287 if let Some(strategy) = &self.strategy {
288 args.push("--strategy".into());
289 args.push(strategy.into());
290 }
291
292 if let Some(template) = &self.template {
293 args.push("--template".into());
294 args.push(template.into());
295 }
296
297 if self.version {
298 args.push("--version".into());
299 }
300
301 if self.help {
302 args.push("--help".into());
303 }
304
305 if let Some(host) = &self.host {
306 args.push("--host".into());
307 args.push(host.into());
308 }
309
310 if let Some(port) = &self.port {
311 args.push("--port".into());
312 args.push(port.to_string().into());
313 }
314
315 if let Some(username) = &self.username {
316 args.push("--username".into());
317 args.push(username.into());
318 }
319
320 if self.no_password {
321 args.push("--no-password".into());
322 }
323
324 if self.password {
325 args.push("--password".into());
326 }
327
328 if let Some(maintenance_db) = &self.maintenance_db {
329 args.push("--maintenance-db".into());
330 args.push(maintenance_db.into());
331 }
332
333 if let Some(dbname) = &self.dbname {
334 args.push(dbname.into());
335 }
336
337 if let Some(description) = &self.description {
338 args.push(description.into());
339 }
340
341 args
342 }
343
344 fn get_envs(&self) -> Vec<(OsString, OsString)> {
346 let mut envs: Vec<(OsString, OsString)> = self.envs.clone();
347
348 if let Some(password) = &self.pg_password {
349 envs.push(("PGPASSWORD".into(), password.into()));
350 }
351
352 envs
353 }
354
355 fn env<S: AsRef<OsStr>>(mut self, key: S, value: S) -> Self {
357 self.envs
358 .push((key.as_ref().to_os_string(), value.as_ref().to_os_string()));
359 self
360 }
361}
362
363#[cfg(test)]
364mod tests {
365 use super::*;
366 use crate::TestSettings;
367 use crate::traits::CommandToString;
368 use test_log::test;
369
370 #[test]
371 fn test_builder_new() {
372 let command = CreateDbBuilder::new().program_dir(".").build();
373 assert_eq!(
374 PathBuf::from(".").join("createdb"),
375 PathBuf::from(command.to_command_string().replace('"', ""))
376 );
377 }
378
379 #[test]
380 fn test_builder_from() {
381 let command = CreateDbBuilder::from(&TestSettings).build();
382 #[cfg(not(target_os = "windows"))]
383 let command_prefix = r#"PGPASSWORD="password" "./createdb" "#;
384 #[cfg(target_os = "windows")]
385 let command_prefix = r#"".\\createdb" "#;
386
387 assert_eq!(
388 format!(
389 r#"{command_prefix}"--host" "localhost" "--port" "5432" "--username" "postgres""#
390 ),
391 command.to_command_string()
392 );
393 }
394
395 #[test]
396 fn test_builder() {
397 let command = CreateDbBuilder::new()
398 .env("PGDATABASE", "database")
399 .tablespace("pg_default")
400 .echo()
401 .encoding("UTF8")
402 .locale("en_US.UTF-8")
403 .lc_collate("en_US.UTF-8")
404 .lc_ctype("en_US.UTF-8")
405 .icu_locale("en_US")
406 .icu_rules("standard")
407 .locale_provider("icu")
408 .owner("postgres")
409 .strategy("wal_log")
410 .template("template0")
411 .version()
412 .help()
413 .host("localhost")
414 .port(5432)
415 .username("postgres")
416 .no_password()
417 .password()
418 .pg_password("password")
419 .maintenance_db("postgres")
420 .dbname("testdb")
421 .description("Test Database")
422 .build();
423 #[cfg(not(target_os = "windows"))]
424 let command_prefix = r#"PGDATABASE="database" PGPASSWORD="password" "#;
425 #[cfg(target_os = "windows")]
426 let command_prefix = String::new();
427
428 assert_eq!(
429 format!(
430 r#"{command_prefix}"createdb" "--tablespace" "pg_default" "--echo" "--encoding" "UTF8" "--locale" "en_US.UTF-8" "--lc-collate" "en_US.UTF-8" "--lc-ctype" "en_US.UTF-8" "--icu-locale" "en_US" "--icu-rules" "standard" "--locale-provider" "icu" "--owner" "postgres" "--strategy" "wal_log" "--template" "template0" "--version" "--help" "--host" "localhost" "--port" "5432" "--username" "postgres" "--no-password" "--password" "--maintenance-db" "postgres" "testdb" "Test Database""#
431 ),
432 command.to_command_string()
433 );
434 }
435}