postgresql_commands/
pg_restore.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 PgRestoreBuilder {
10 program_dir: Option<PathBuf>,
11 envs: Vec<(OsString, OsString)>,
12 dbname: Option<OsString>,
13 file: Option<OsString>,
14 format: Option<OsString>,
15 list: bool,
16 verbose: bool,
17 version: bool,
18 help: bool,
19 data_only: bool,
20 clean: bool,
21 create: bool,
22 exit_on_error: bool,
23 index: Option<OsString>,
24 jobs: Option<OsString>,
25 use_list: Option<OsString>,
26 schema: Option<OsString>,
27 exclude_schema: Option<OsString>,
28 no_owner: bool,
29 function: Option<OsString>,
30 schema_only: bool,
31 superuser: Option<OsString>,
32 table: Option<OsString>,
33 trigger: Option<OsString>,
34 no_privileges: bool,
35 single_transaction: bool,
36 disable_triggers: bool,
37 enable_row_security: bool,
38 if_exists: bool,
39 no_comments: bool,
40 no_data_for_failed_tables: bool,
41 no_publications: bool,
42 no_security_labels: bool,
43 no_subscriptions: bool,
44 no_table_access_method: bool,
45 no_tablespaces: bool,
46 section: Option<OsString>,
47 strict_names: bool,
48 use_set_session_authorization: bool,
49 host: Option<OsString>,
50 port: Option<u16>,
51 username: Option<OsString>,
52 no_password: bool,
53 password: bool,
54 pg_password: Option<OsString>,
55 role: Option<OsString>,
56}
57
58impl PgRestoreBuilder {
59 #[must_use]
61 pub fn new() -> Self {
62 Self::default()
63 }
64
65 pub fn from(settings: &dyn Settings) -> Self {
67 Self::new()
68 .program_dir(settings.get_binary_dir())
69 .host(settings.get_host())
70 .port(settings.get_port())
71 .username(settings.get_username())
72 .pg_password(settings.get_password())
73 }
74
75 #[must_use]
77 pub fn program_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
78 self.program_dir = Some(path.into());
79 self
80 }
81
82 #[must_use]
84 pub fn dbname<S: AsRef<OsStr>>(mut self, name: S) -> Self {
85 self.dbname = Some(name.as_ref().to_os_string());
86 self
87 }
88
89 #[must_use]
91 pub fn file<S: AsRef<OsStr>>(mut self, filename: S) -> Self {
92 self.file = Some(filename.as_ref().to_os_string());
93 self
94 }
95
96 #[must_use]
98 pub fn format<S: AsRef<OsStr>>(mut self, format: S) -> Self {
99 self.format = Some(format.as_ref().to_os_string());
100 self
101 }
102
103 #[must_use]
105 pub fn list(mut self) -> Self {
106 self.list = true;
107 self
108 }
109
110 #[must_use]
112 pub fn verbose(mut self) -> Self {
113 self.verbose = true;
114 self
115 }
116
117 #[must_use]
119 pub fn version(mut self) -> Self {
120 self.version = true;
121 self
122 }
123
124 #[must_use]
126 pub fn help(mut self) -> Self {
127 self.help = true;
128 self
129 }
130
131 #[must_use]
133 pub fn data_only(mut self) -> Self {
134 self.data_only = true;
135 self
136 }
137
138 #[must_use]
140 pub fn clean(mut self) -> Self {
141 self.clean = true;
142 self
143 }
144
145 #[must_use]
147 pub fn create(mut self) -> Self {
148 self.create = true;
149 self
150 }
151
152 #[must_use]
154 pub fn exit_on_error(mut self) -> Self {
155 self.exit_on_error = true;
156 self
157 }
158
159 #[must_use]
161 pub fn index<S: AsRef<OsStr>>(mut self, name: S) -> Self {
162 self.index = Some(name.as_ref().to_os_string());
163 self
164 }
165
166 #[must_use]
168 pub fn jobs<S: AsRef<OsStr>>(mut self, num: S) -> Self {
169 self.jobs = Some(num.as_ref().to_os_string());
170 self
171 }
172
173 #[must_use]
175 pub fn use_list<S: AsRef<OsStr>>(mut self, filename: S) -> Self {
176 self.use_list = Some(filename.as_ref().to_os_string());
177 self
178 }
179
180 #[must_use]
182 pub fn schema<S: AsRef<OsStr>>(mut self, name: S) -> Self {
183 self.schema = Some(name.as_ref().to_os_string());
184 self
185 }
186
187 #[must_use]
189 pub fn exclude_schema<S: AsRef<OsStr>>(mut self, name: S) -> Self {
190 self.exclude_schema = Some(name.as_ref().to_os_string());
191 self
192 }
193
194 #[must_use]
196 pub fn no_owner(mut self) -> Self {
197 self.no_owner = true;
198 self
199 }
200
201 #[must_use]
203 pub fn function<S: AsRef<OsStr>>(mut self, name: S) -> Self {
204 self.function = Some(name.as_ref().to_os_string());
205 self
206 }
207
208 #[must_use]
210 pub fn schema_only(mut self) -> Self {
211 self.schema_only = true;
212 self
213 }
214
215 #[must_use]
217 pub fn superuser<S: AsRef<OsStr>>(mut self, name: S) -> Self {
218 self.superuser = Some(name.as_ref().to_os_string());
219 self
220 }
221
222 #[must_use]
224 pub fn table<S: AsRef<OsStr>>(mut self, name: S) -> Self {
225 self.table = Some(name.as_ref().to_os_string());
226 self
227 }
228
229 #[must_use]
231 pub fn trigger<S: AsRef<OsStr>>(mut self, name: S) -> Self {
232 self.trigger = Some(name.as_ref().to_os_string());
233 self
234 }
235
236 #[must_use]
238 pub fn no_privileges(mut self) -> Self {
239 self.no_privileges = true;
240 self
241 }
242
243 #[must_use]
245 pub fn single_transaction(mut self) -> Self {
246 self.single_transaction = true;
247 self
248 }
249
250 #[must_use]
252 pub fn disable_triggers(mut self) -> Self {
253 self.disable_triggers = true;
254 self
255 }
256
257 #[must_use]
259 pub fn enable_row_security(mut self) -> Self {
260 self.enable_row_security = true;
261 self
262 }
263
264 #[must_use]
266 pub fn if_exists(mut self) -> Self {
267 self.if_exists = true;
268 self
269 }
270
271 #[must_use]
273 pub fn no_comments(mut self) -> Self {
274 self.no_comments = true;
275 self
276 }
277
278 #[must_use]
280 pub fn no_data_for_failed_tables(mut self) -> Self {
281 self.no_data_for_failed_tables = true;
282 self
283 }
284
285 #[must_use]
287 pub fn no_publications(mut self) -> Self {
288 self.no_publications = true;
289 self
290 }
291
292 #[must_use]
294 pub fn no_security_labels(mut self) -> Self {
295 self.no_security_labels = true;
296 self
297 }
298
299 #[must_use]
301 pub fn no_subscriptions(mut self) -> Self {
302 self.no_subscriptions = true;
303 self
304 }
305
306 #[must_use]
308 pub fn no_table_access_method(mut self) -> Self {
309 self.no_table_access_method = true;
310 self
311 }
312
313 #[must_use]
315 pub fn no_tablespaces(mut self) -> Self {
316 self.no_tablespaces = true;
317 self
318 }
319
320 #[must_use]
322 pub fn section<S: AsRef<OsStr>>(mut self, section: S) -> Self {
323 self.section = Some(section.as_ref().to_os_string());
324 self
325 }
326
327 #[must_use]
329 pub fn strict_names(mut self) -> Self {
330 self.strict_names = true;
331 self
332 }
333
334 #[must_use]
336 pub fn use_set_session_authorization(mut self) -> Self {
337 self.use_set_session_authorization = true;
338 self
339 }
340
341 #[must_use]
343 pub fn host<S: AsRef<OsStr>>(mut self, hostname: S) -> Self {
344 self.host = Some(hostname.as_ref().to_os_string());
345 self
346 }
347
348 #[must_use]
350 pub fn port(mut self, port: u16) -> Self {
351 self.port = Some(port);
352 self
353 }
354
355 #[must_use]
357 pub fn username<S: AsRef<OsStr>>(mut self, name: S) -> Self {
358 self.username = Some(name.as_ref().to_os_string());
359 self
360 }
361
362 #[must_use]
364 pub fn no_password(mut self) -> Self {
365 self.no_password = true;
366 self
367 }
368
369 #[must_use]
371 pub fn password(mut self) -> Self {
372 self.password = true;
373 self
374 }
375
376 #[must_use]
378 pub fn pg_password<S: AsRef<OsStr>>(mut self, pg_password: S) -> Self {
379 self.pg_password = Some(pg_password.as_ref().to_os_string());
380 self
381 }
382
383 #[must_use]
385 pub fn role<S: AsRef<OsStr>>(mut self, rolename: S) -> Self {
386 self.role = Some(rolename.as_ref().to_os_string());
387 self
388 }
389}
390
391impl CommandBuilder for PgRestoreBuilder {
392 fn get_program(&self) -> &'static OsStr {
394 "pg_restore".as_ref()
395 }
396
397 fn get_program_dir(&self) -> &Option<PathBuf> {
399 &self.program_dir
400 }
401
402 #[expect(clippy::too_many_lines)]
404 fn get_args(&self) -> Vec<OsString> {
405 let mut args: Vec<OsString> = Vec::new();
406
407 if let Some(name) = &self.dbname {
408 args.push("--dbname".into());
409 args.push(name.into());
410 }
411
412 if let Some(filename) = &self.file {
413 args.push("--file".into());
414 args.push(filename.into());
415 }
416
417 if let Some(format) = &self.format {
418 args.push("--format".into());
419 args.push(format.into());
420 }
421
422 if self.list {
423 args.push("--list".into());
424 }
425
426 if self.verbose {
427 args.push("--verbose".into());
428 }
429
430 if self.version {
431 args.push("--version".into());
432 }
433
434 if self.help {
435 args.push("--help".into());
436 }
437
438 if self.data_only {
439 args.push("--data-only".into());
440 }
441
442 if self.clean {
443 args.push("--clean".into());
444 }
445
446 if self.create {
447 args.push("--create".into());
448 }
449
450 if self.exit_on_error {
451 args.push("--exit-on-error".into());
452 }
453
454 if let Some(name) = &self.index {
455 args.push("--index".into());
456 args.push(name.into());
457 }
458
459 if let Some(num) = &self.jobs {
460 args.push("--jobs".into());
461 args.push(num.into());
462 }
463
464 if let Some(filename) = &self.use_list {
465 args.push("--use-list".into());
466 args.push(filename.into());
467 }
468
469 if let Some(name) = &self.schema {
470 args.push("--schema".into());
471 args.push(name.into());
472 }
473
474 if let Some(name) = &self.exclude_schema {
475 args.push("--exclude-schema".into());
476 args.push(name.into());
477 }
478
479 if self.no_owner {
480 args.push("--no-owner".into());
481 }
482
483 if let Some(name) = &self.function {
484 args.push("--function".into());
485 args.push(name.into());
486 }
487
488 if self.schema_only {
489 args.push("--schema-only".into());
490 }
491
492 if let Some(name) = &self.superuser {
493 args.push("--superuser".into());
494 args.push(name.into());
495 }
496
497 if let Some(name) = &self.table {
498 args.push("--table".into());
499 args.push(name.into());
500 }
501
502 if let Some(name) = &self.trigger {
503 args.push("--trigger".into());
504 args.push(name.into());
505 }
506
507 if self.no_privileges {
508 args.push("--no-privileges".into());
509 }
510
511 if self.single_transaction {
512 args.push("--single-transaction".into());
513 }
514
515 if self.disable_triggers {
516 args.push("--disable-triggers".into());
517 }
518
519 if self.enable_row_security {
520 args.push("--enable-row-security".into());
521 }
522
523 if self.if_exists {
524 args.push("--if-exists".into());
525 }
526
527 if self.no_comments {
528 args.push("--no-comments".into());
529 }
530
531 if self.no_data_for_failed_tables {
532 args.push("--no-data-for-failed-tables".into());
533 }
534
535 if self.no_publications {
536 args.push("--no-publications".into());
537 }
538
539 if self.no_security_labels {
540 args.push("--no-security-labels".into());
541 }
542
543 if self.no_subscriptions {
544 args.push("--no-subscriptions".into());
545 }
546
547 if self.no_table_access_method {
548 args.push("--no-table-access-method".into());
549 }
550
551 if self.no_tablespaces {
552 args.push("--no-tablespaces".into());
553 }
554
555 if let Some(section) = &self.section {
556 args.push("--section".into());
557 args.push(section.into());
558 }
559
560 if self.strict_names {
561 args.push("--strict-names".into());
562 }
563
564 if self.use_set_session_authorization {
565 args.push("--use-set-session-authorization".into());
566 }
567
568 if let Some(hostname) = &self.host {
569 args.push("--host".into());
570 args.push(hostname.into());
571 }
572
573 if let Some(port) = &self.port {
574 args.push("--port".into());
575 args.push(port.to_string().into());
576 }
577
578 if let Some(name) = &self.username {
579 args.push("--username".into());
580 args.push(name.into());
581 }
582
583 if self.no_password {
584 args.push("--no-password".into());
585 }
586
587 if self.password {
588 args.push("--password".into());
589 }
590
591 if let Some(role) = &self.role {
592 args.push("--role".into());
593 args.push(role.into());
594 }
595
596 args
597 }
598
599 fn get_envs(&self) -> Vec<(OsString, OsString)> {
601 let mut envs: Vec<(OsString, OsString)> = self.envs.clone();
602
603 if let Some(password) = &self.pg_password {
604 envs.push(("PGPASSWORD".into(), password.into()));
605 }
606
607 envs
608 }
609
610 fn env<S: AsRef<OsStr>>(mut self, key: S, value: S) -> Self {
612 self.envs
613 .push((key.as_ref().to_os_string(), value.as_ref().to_os_string()));
614 self
615 }
616}
617
618#[cfg(test)]
619mod tests {
620 use super::*;
621 use crate::TestSettings;
622 use crate::traits::CommandToString;
623 use test_log::test;
624
625 #[test]
626 fn test_builder_new() {
627 let command = PgRestoreBuilder::new().program_dir(".").build();
628 assert_eq!(
629 PathBuf::from(".").join("pg_restore"),
630 PathBuf::from(command.to_command_string().replace('"', ""))
631 );
632 }
633
634 #[test]
635 fn test_builder_from() {
636 let command = PgRestoreBuilder::from(&TestSettings).build();
637 #[cfg(not(target_os = "windows"))]
638 let command_prefix = r#"PGPASSWORD="password" "./pg_restore" "#;
639 #[cfg(target_os = "windows")]
640 let command_prefix = r#"".\\pg_restore" "#;
641
642 assert_eq!(
643 format!(
644 r#"{command_prefix}"--host" "localhost" "--port" "5432" "--username" "postgres""#
645 ),
646 command.to_command_string()
647 );
648 }
649
650 #[test]
651 fn test_builder() {
652 let command = PgRestoreBuilder::new()
653 .env("PGDATABASE", "database")
654 .dbname("dbname")
655 .file("file")
656 .format("format")
657 .list()
658 .verbose()
659 .version()
660 .help()
661 .data_only()
662 .clean()
663 .create()
664 .exit_on_error()
665 .index("index")
666 .jobs("jobs")
667 .use_list("use_list")
668 .schema("schema")
669 .exclude_schema("exclude_schema")
670 .no_owner()
671 .function("function")
672 .schema_only()
673 .superuser("superuser")
674 .table("table")
675 .trigger("trigger")
676 .no_privileges()
677 .single_transaction()
678 .disable_triggers()
679 .enable_row_security()
680 .if_exists()
681 .no_comments()
682 .no_data_for_failed_tables()
683 .no_publications()
684 .no_security_labels()
685 .no_subscriptions()
686 .no_table_access_method()
687 .no_tablespaces()
688 .section("section")
689 .strict_names()
690 .use_set_session_authorization()
691 .host("localhost")
692 .port(5432)
693 .username("username")
694 .no_password()
695 .password()
696 .pg_password("password")
697 .role("role")
698 .build();
699 #[cfg(not(target_os = "windows"))]
700 let command_prefix = r#"PGDATABASE="database" PGPASSWORD="password" "#;
701 #[cfg(target_os = "windows")]
702 let command_prefix = String::new();
703
704 assert_eq!(
705 format!(
706 r#"{command_prefix}"pg_restore" "--dbname" "dbname" "--file" "file" "--format" "format" "--list" "--verbose" "--version" "--help" "--data-only" "--clean" "--create" "--exit-on-error" "--index" "index" "--jobs" "jobs" "--use-list" "use_list" "--schema" "schema" "--exclude-schema" "exclude_schema" "--no-owner" "--function" "function" "--schema-only" "--superuser" "superuser" "--table" "table" "--trigger" "trigger" "--no-privileges" "--single-transaction" "--disable-triggers" "--enable-row-security" "--if-exists" "--no-comments" "--no-data-for-failed-tables" "--no-publications" "--no-security-labels" "--no-subscriptions" "--no-table-access-method" "--no-tablespaces" "--section" "section" "--strict-names" "--use-set-session-authorization" "--host" "localhost" "--port" "5432" "--username" "username" "--no-password" "--password" "--role" "role""#
707 ),
708 command.to_command_string()
709 );
710 }
711}