postgresql_commands/
pg_dump.rs

1use crate::Settings;
2use crate::traits::CommandBuilder;
3use std::convert::AsRef;
4use std::ffi::{OsStr, OsString};
5use std::path::PathBuf;
6
7/// `pg_dump` dumps a database as a text file or to other formats.
8#[derive(Clone, Debug, Default)]
9pub struct PgDumpBuilder {
10    program_dir: Option<PathBuf>,
11    envs: Vec<(OsString, OsString)>,
12    data_only: bool,
13    large_objects: bool,
14    no_large_objects: bool,
15    clean: bool,
16    create: bool,
17    extension: Option<OsString>,
18    encoding: Option<OsString>,
19    file: Option<OsString>,
20    format: Option<OsString>,
21    jobs: Option<OsString>,
22    schema: Option<OsString>,
23    exclude_schema: Option<OsString>,
24    no_owner: bool,
25    no_reconnect: bool,
26    schema_only: bool,
27    superuser: Option<OsString>,
28    table: Option<OsString>,
29    exclude_table: Option<OsString>,
30    verbose: bool,
31    version: bool,
32    no_privileges: bool,
33    compression: Option<OsString>,
34    binary_upgrade: bool,
35    column_inserts: bool,
36    attribute_inserts: bool,
37    disable_dollar_quoting: bool,
38    disable_triggers: bool,
39    enable_row_security: bool,
40    exclude_table_data_and_children: Option<OsString>,
41    extra_float_digits: Option<OsString>,
42    if_exists: bool,
43    include_foreign_data: Option<OsString>,
44    inserts: bool,
45    load_via_partition_root: bool,
46    lock_wait_timeout: Option<u16>,
47    no_comments: bool,
48    no_publications: bool,
49    no_security_labels: bool,
50    no_subscriptions: bool,
51    no_table_access_method: bool,
52    no_tablespaces: bool,
53    no_toast_compression: bool,
54    no_unlogged_table_data: bool,
55    on_conflict_do_nothing: bool,
56    quote_all_identifiers: bool,
57    rows_per_insert: Option<u64>,
58    section: Option<OsString>,
59    serializable_deferrable: bool,
60    snapshot: Option<OsString>,
61    strict_names: bool,
62    table_and_children: Option<OsString>,
63    use_set_session_authorization: bool,
64    help: bool,
65    dbname: Option<OsString>,
66    host: Option<OsString>,
67    port: Option<u16>,
68    username: Option<OsString>,
69    no_password: bool,
70    password: bool,
71    pg_password: Option<OsString>,
72    role: Option<OsString>,
73}
74
75impl PgDumpBuilder {
76    /// Create a new [`PgDumpBuilder`]
77    #[must_use]
78    pub fn new() -> Self {
79        Self::default()
80    }
81
82    /// Create a new [`PgDumpBuilder`] from [Settings]
83    pub fn from(settings: &dyn Settings) -> Self {
84        Self::new()
85            .program_dir(settings.get_binary_dir())
86            .host(settings.get_host())
87            .port(settings.get_port())
88            .username(settings.get_username())
89            .pg_password(settings.get_password())
90    }
91
92    /// Location of the program binary
93    #[must_use]
94    pub fn program_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
95        self.program_dir = Some(path.into());
96        self
97    }
98
99    /// Dump only the data, not the schema
100    #[must_use]
101    pub fn data_only(mut self) -> Self {
102        self.data_only = true;
103        self
104    }
105
106    /// Dump large objects in binary format
107    #[must_use]
108    pub fn large_objects(mut self) -> Self {
109        self.large_objects = true;
110        self
111    }
112
113    /// Do not dump large objects
114    #[must_use]
115    pub fn no_large_objects(mut self) -> Self {
116        self.no_large_objects = true;
117        self
118    }
119
120    /// Output commands to clean (drop) database objects prior to outputting the commands for creating them
121    #[must_use]
122    pub fn clean(mut self) -> Self {
123        self.clean = true;
124        self
125    }
126
127    /// Output commands to create the database objects (data definition)
128    #[must_use]
129    pub fn create(mut self) -> Self {
130        self.create = true;
131        self
132    }
133
134    /// Dump data for the named extension
135    #[must_use]
136    pub fn extension<S: AsRef<OsStr>>(mut self, extension: S) -> Self {
137        self.extension = Some(extension.as_ref().to_os_string());
138        self
139    }
140
141    /// Dump data in encoding ENCODING
142    #[must_use]
143    pub fn encoding<S: AsRef<OsStr>>(mut self, encoding: S) -> Self {
144        self.encoding = Some(encoding.as_ref().to_os_string());
145        self
146    }
147
148    /// Set the output file or directory name
149    #[must_use]
150    pub fn file<S: AsRef<OsStr>>(mut self, file: S) -> Self {
151        self.file = Some(file.as_ref().to_os_string());
152        self
153    }
154
155    /// Set the output file format (custom, directory, tar, plain text (default))
156    #[must_use]
157    pub fn format<S: AsRef<OsStr>>(mut self, format: S) -> Self {
158        self.format = Some(format.as_ref().to_os_string());
159        self
160    }
161
162    /// Use this many parallel jobs to dump
163    #[must_use]
164    pub fn jobs<S: AsRef<OsStr>>(mut self, jobs: S) -> Self {
165        self.jobs = Some(jobs.as_ref().to_os_string());
166        self
167    }
168
169    /// Dump data for the named schema(s) only
170    #[must_use]
171    pub fn schema<S: AsRef<OsStr>>(mut self, schema: S) -> Self {
172        self.schema = Some(schema.as_ref().to_os_string());
173        self
174    }
175
176    /// Do not output commands to set ownership of objects to match the original database
177    #[must_use]
178    pub fn exclude_schema<S: AsRef<OsStr>>(mut self, exclude_schema: S) -> Self {
179        self.exclude_schema = Some(exclude_schema.as_ref().to_os_string());
180        self
181    }
182
183    /// Do not output commands to set ownership of objects to match the original database
184    #[must_use]
185    pub fn no_owner(mut self) -> Self {
186        self.no_owner = true;
187        self
188    }
189
190    /// Do not reconnect to the database
191    #[must_use]
192    pub fn no_reconnect(mut self) -> Self {
193        self.no_reconnect = true;
194        self
195    }
196
197    /// Dump only the schema, no data
198    #[must_use]
199    pub fn schema_only(mut self) -> Self {
200        self.schema_only = true;
201        self
202    }
203
204    /// Dump data as a superuser
205    #[must_use]
206    pub fn superuser<S: AsRef<OsStr>>(mut self, superuser: S) -> Self {
207        self.superuser = Some(superuser.as_ref().to_os_string());
208        self
209    }
210
211    /// Dump data for the named table(s) only
212    #[must_use]
213    pub fn table<S: AsRef<OsStr>>(mut self, table: S) -> Self {
214        self.table = Some(table.as_ref().to_os_string());
215        self
216    }
217
218    /// Do not output commands to create the table(s) containing the data
219    #[must_use]
220    pub fn exclude_table<S: AsRef<OsStr>>(mut self, exclude_table: S) -> Self {
221        self.exclude_table = Some(exclude_table.as_ref().to_os_string());
222        self
223    }
224
225    /// Enable verbose mode
226    #[must_use]
227    pub fn verbose(mut self) -> Self {
228        self.verbose = true;
229        self
230    }
231
232    /// Output version information, then exit
233    #[must_use]
234    pub fn version(mut self) -> Self {
235        self.version = true;
236        self
237    }
238
239    /// Do not output commands to set object privileges
240    #[must_use]
241    pub fn no_privileges(mut self) -> Self {
242        self.no_privileges = true;
243        self
244    }
245
246    /// Set the compression level to use
247    #[must_use]
248    pub fn compression<S: AsRef<OsStr>>(mut self, compress: S) -> Self {
249        self.compression = Some(compress.as_ref().to_os_string());
250        self
251    }
252
253    /// Dump data in a format suitable for binary upgrade
254    #[must_use]
255    pub fn binary_upgrade(mut self) -> Self {
256        self.binary_upgrade = true;
257        self
258    }
259
260    /// Dump data as INSERT commands with column names
261    #[must_use]
262    pub fn column_inserts(mut self) -> Self {
263        self.column_inserts = true;
264        self
265    }
266
267    /// Dump data as INSERT commands with column names
268    #[must_use]
269    pub fn attribute_inserts(mut self) -> Self {
270        self.attribute_inserts = true;
271        self
272    }
273
274    /// Disable dollar quoting, use SQL standard quoting
275    #[must_use]
276    pub fn disable_dollar_quoting(mut self) -> Self {
277        self.disable_dollar_quoting = true;
278        self
279    }
280
281    /// Disable triggers during data-only restore
282    #[must_use]
283    pub fn disable_triggers(mut self) -> Self {
284        self.disable_triggers = true;
285        self
286    }
287
288    /// Dump data with row security enabled
289    #[must_use]
290    pub fn enable_row_security(mut self) -> Self {
291        self.enable_row_security = true;
292        self
293    }
294
295    /// Dump data for the named table(s) but exclude data for their child tables
296    #[must_use]
297    pub fn exclude_table_data_and_children<S: AsRef<OsStr>>(
298        mut self,
299        exclude_table_data_and_children: S,
300    ) -> Self {
301        self.exclude_table_data_and_children =
302            Some(exclude_table_data_and_children.as_ref().to_os_string());
303        self
304    }
305
306    /// Set the number of digits displayed for floating-point values
307    #[must_use]
308    pub fn extra_float_digits<S: AsRef<OsStr>>(mut self, extra_float_digits: S) -> Self {
309        self.extra_float_digits = Some(extra_float_digits.as_ref().to_os_string());
310        self
311    }
312
313    /// Use IF EXISTS when dropping objects
314    #[must_use]
315    pub fn if_exists(mut self) -> Self {
316        self.if_exists = true;
317        self
318    }
319
320    /// Include foreign-data wrappers in the dump
321    #[must_use]
322    pub fn include_foreign_data<S: AsRef<OsStr>>(mut self, include_foreign_data: S) -> Self {
323        self.include_foreign_data = Some(include_foreign_data.as_ref().to_os_string());
324        self
325    }
326
327    /// Dump data as INSERT commands
328    #[must_use]
329    pub fn inserts(mut self) -> Self {
330        self.inserts = true;
331        self
332    }
333
334    /// Load data via the partition root table
335    #[must_use]
336    pub fn load_via_partition_root(mut self) -> Self {
337        self.load_via_partition_root = true;
338        self
339    }
340
341    /// Fail after waiting TIMEOUT for a table lock
342    #[must_use]
343    pub fn lock_wait_timeout(mut self, lock_wait_timeout: u16) -> Self {
344        self.lock_wait_timeout = Some(lock_wait_timeout);
345        self
346    }
347
348    /// Do not output comments
349    #[must_use]
350    pub fn no_comments(mut self) -> Self {
351        self.no_comments = true;
352        self
353    }
354
355    /// Do not output publications
356    #[must_use]
357    pub fn no_publications(mut self) -> Self {
358        self.no_publications = true;
359        self
360    }
361
362    /// Do not output security labels
363    #[must_use]
364    pub fn no_security_labels(mut self) -> Self {
365        self.no_security_labels = true;
366        self
367    }
368
369    /// Do not output subscriptions
370    #[must_use]
371    pub fn no_subscriptions(mut self) -> Self {
372        self.no_subscriptions = true;
373        self
374    }
375
376    /// Do not output table access method
377    #[must_use]
378    pub fn no_table_access_method(mut self) -> Self {
379        self.no_table_access_method = true;
380        self
381    }
382
383    /// Do not output tablespace assignments
384    #[must_use]
385    pub fn no_tablespaces(mut self) -> Self {
386        self.no_tablespaces = true;
387        self
388    }
389
390    /// Do not output TOAST table compression
391    #[must_use]
392    pub fn no_toast_compression(mut self) -> Self {
393        self.no_toast_compression = true;
394        self
395    }
396
397    /// Do not output unlogged table data
398    #[must_use]
399    pub fn no_unlogged_table_data(mut self) -> Self {
400        self.no_unlogged_table_data = true;
401        self
402    }
403
404    /// Use ON CONFLICT DO NOTHING for INSERTs
405    #[must_use]
406    pub fn on_conflict_do_nothing(mut self) -> Self {
407        self.on_conflict_do_nothing = true;
408        self
409    }
410
411    /// Quote all identifiers, even if not key words
412    #[must_use]
413    pub fn quote_all_identifiers(mut self) -> Self {
414        self.quote_all_identifiers = true;
415        self
416    }
417
418    /// Set the number of rows per INSERT
419    #[must_use]
420    pub fn rows_per_insert(mut self, rows_per_insert: u64) -> Self {
421        self.rows_per_insert = Some(rows_per_insert);
422        self
423    }
424
425    /// Dump data for the named section(s) only
426    #[must_use]
427    pub fn section<S: AsRef<OsStr>>(mut self, section: S) -> Self {
428        self.section = Some(section.as_ref().to_os_string());
429        self
430    }
431
432    /// Dump data as a serializable transaction
433    #[must_use]
434    pub fn serializable_deferrable(mut self) -> Self {
435        self.serializable_deferrable = true;
436        self
437    }
438
439    /// Use a snapshot with the specified name
440    #[must_use]
441    pub fn snapshot<S: AsRef<OsStr>>(mut self, snapshot: S) -> Self {
442        self.snapshot = Some(snapshot.as_ref().to_os_string());
443        self
444    }
445
446    /// Use strict SQL identifier syntax
447    #[must_use]
448    pub fn strict_names(mut self) -> Self {
449        self.strict_names = true;
450        self
451    }
452
453    /// Dump data for the named table(s) and their children
454    #[must_use]
455    pub fn table_and_children<S: AsRef<OsStr>>(mut self, table_and_children: S) -> Self {
456        self.table_and_children = Some(table_and_children.as_ref().to_os_string());
457        self
458    }
459
460    /// Use SET SESSION AUTHORIZATION commands instead of ALTER OWNER
461    #[must_use]
462    pub fn use_set_session_authorization(mut self) -> Self {
463        self.use_set_session_authorization = true;
464        self
465    }
466
467    /// Show help, then exit
468    #[must_use]
469    pub fn help(mut self) -> Self {
470        self.help = true;
471        self
472    }
473
474    /// database to connect to
475    #[must_use]
476    pub fn dbname<S: AsRef<OsStr>>(mut self, dbname: S) -> Self {
477        self.dbname = Some(dbname.as_ref().to_os_string());
478        self
479    }
480
481    /// database server host or socket directory
482    #[must_use]
483    pub fn host<S: AsRef<OsStr>>(mut self, host: S) -> Self {
484        self.host = Some(host.as_ref().to_os_string());
485        self
486    }
487
488    /// database server port
489    #[must_use]
490    pub fn port(mut self, port: u16) -> Self {
491        self.port = Some(port);
492        self
493    }
494
495    /// database user name
496    #[must_use]
497    pub fn username<S: AsRef<OsStr>>(mut self, username: S) -> Self {
498        self.username = Some(username.as_ref().to_os_string());
499        self
500    }
501
502    /// never prompt for password
503    #[must_use]
504    pub fn no_password(mut self) -> Self {
505        self.no_password = true;
506        self
507    }
508
509    /// force password prompt (should happen automatically)
510    #[must_use]
511    pub fn password(mut self) -> Self {
512        self.password = true;
513        self
514    }
515
516    /// user password
517    #[must_use]
518    pub fn pg_password<S: AsRef<OsStr>>(mut self, pg_password: S) -> Self {
519        self.pg_password = Some(pg_password.as_ref().to_os_string());
520        self
521    }
522
523    /// Specifies a role name to be used to create the dump
524    #[must_use]
525    pub fn role<S: AsRef<OsStr>>(mut self, rolename: S) -> Self {
526        self.role = Some(rolename.as_ref().to_os_string());
527        self
528    }
529}
530
531impl CommandBuilder for PgDumpBuilder {
532    /// Get the program name
533    fn get_program(&self) -> &'static OsStr {
534        "pg_dump".as_ref()
535    }
536
537    /// Location of the program binary
538    fn get_program_dir(&self) -> &Option<PathBuf> {
539        &self.program_dir
540    }
541
542    /// Get the arguments for the command
543    #[expect(clippy::too_many_lines)]
544    fn get_args(&self) -> Vec<OsString> {
545        let mut args: Vec<OsString> = Vec::new();
546
547        if self.data_only {
548            args.push("--data-only".into());
549        }
550
551        if self.large_objects {
552            args.push("--large-objects".into());
553        }
554
555        if self.no_large_objects {
556            args.push("--no-large-objects".into());
557        }
558
559        if self.clean {
560            args.push("--clean".into());
561        }
562
563        if self.create {
564            args.push("--create".into());
565        }
566
567        if let Some(extension) = &self.extension {
568            args.push("--extension".into());
569            args.push(extension.into());
570        }
571
572        if let Some(encoding) = &self.encoding {
573            args.push("--encoding".into());
574            args.push(encoding.into());
575        }
576
577        if let Some(file) = &self.file {
578            args.push("--file".into());
579            args.push(file.into());
580        }
581
582        if let Some(format) = &self.format {
583            args.push("--format".into());
584            args.push(format.into());
585        }
586
587        if let Some(jobs) = &self.jobs {
588            args.push("--jobs".into());
589            args.push(jobs.into());
590        }
591
592        if let Some(schema) = &self.schema {
593            args.push("--schema".into());
594            args.push(schema.into());
595        }
596
597        if let Some(exclude_schema) = &self.exclude_schema {
598            args.push("--exclude-schema".into());
599            args.push(exclude_schema.into());
600        }
601
602        if self.no_owner {
603            args.push("--no-owner".into());
604        }
605
606        if self.no_reconnect {
607            args.push("--no-reconnect".into());
608        }
609
610        if self.schema_only {
611            args.push("--schema-only".into());
612        }
613
614        if let Some(superuser) = &self.superuser {
615            args.push("--superuser".into());
616            args.push(superuser.into());
617        }
618
619        if let Some(table) = &self.table {
620            args.push("--table".into());
621            args.push(table.into());
622        }
623
624        if let Some(exclude_table) = &self.exclude_table {
625            args.push("--exclude-table".into());
626            args.push(exclude_table.into());
627        }
628
629        if self.verbose {
630            args.push("--verbose".into());
631        }
632
633        if self.version {
634            args.push("--version".into());
635        }
636
637        if self.no_privileges {
638            args.push("--no-privileges".into());
639        }
640
641        if let Some(compression) = &self.compression {
642            args.push("--compression".into());
643            args.push(compression.into());
644        }
645
646        if self.binary_upgrade {
647            args.push("--binary-upgrade".into());
648        }
649
650        if self.column_inserts {
651            args.push("--column-inserts".into());
652        }
653
654        if self.attribute_inserts {
655            args.push("--attribute-inserts".into());
656        }
657
658        if self.disable_dollar_quoting {
659            args.push("--disable-dollar-quoting".into());
660        }
661
662        if self.disable_triggers {
663            args.push("--disable-triggers".into());
664        }
665
666        if self.enable_row_security {
667            args.push("--enable-row-security".into());
668        }
669
670        if let Some(exclude_table_data_and_children) = &self.exclude_table_data_and_children {
671            args.push("--exclude-table-data-and-children".into());
672            args.push(exclude_table_data_and_children.into());
673        }
674
675        if let Some(extra_float_digits) = &self.extra_float_digits {
676            args.push("--extra-float-digits".into());
677            args.push(extra_float_digits.into());
678        }
679
680        if self.if_exists {
681            args.push("--if-exists".into());
682        }
683
684        if let Some(include_foreign_data) = &self.include_foreign_data {
685            args.push("--include-foreign-data".into());
686            args.push(include_foreign_data.into());
687        }
688
689        if self.inserts {
690            args.push("--inserts".into());
691        }
692
693        if self.load_via_partition_root {
694            args.push("--load-via-partition-root".into());
695        }
696
697        if let Some(lock_wait_timeout) = &self.lock_wait_timeout {
698            args.push("--lock-wait-timeout".into());
699            args.push(lock_wait_timeout.to_string().into());
700        }
701
702        if self.no_comments {
703            args.push("--no-comments".into());
704        }
705
706        if self.no_publications {
707            args.push("--no-publications".into());
708        }
709
710        if self.no_security_labels {
711            args.push("--no-security-labels".into());
712        }
713
714        if self.no_subscriptions {
715            args.push("--no-subscriptions".into());
716        }
717
718        if self.no_table_access_method {
719            args.push("--no-table-access-method".into());
720        }
721
722        if self.no_tablespaces {
723            args.push("--no-tablespaces".into());
724        }
725
726        if self.no_toast_compression {
727            args.push("--no-toast-compression".into());
728        }
729
730        if self.no_unlogged_table_data {
731            args.push("--no-unlogged-table-data".into());
732        }
733
734        if self.on_conflict_do_nothing {
735            args.push("--on-conflict-do-nothing".into());
736        }
737
738        if self.quote_all_identifiers {
739            args.push("--quote-all-identifiers".into());
740        }
741
742        if let Some(rows_per_insert) = &self.rows_per_insert {
743            args.push("--rows-per-insert".into());
744            args.push(rows_per_insert.to_string().into());
745        }
746
747        if let Some(section) = &self.section {
748            args.push("--section".into());
749            args.push(section.into());
750        }
751
752        if self.serializable_deferrable {
753            args.push("--serializable-deferrable".into());
754        }
755
756        if let Some(snapshot) = &self.snapshot {
757            args.push("--snapshot".into());
758            args.push(snapshot.into());
759        }
760
761        if self.strict_names {
762            args.push("--strict-names".into());
763        }
764
765        if let Some(table_and_children) = &self.table_and_children {
766            args.push("--table-and-children".into());
767            args.push(table_and_children.into());
768        }
769
770        if self.use_set_session_authorization {
771            args.push("--use-set-session-authorization".into());
772        }
773
774        if self.help {
775            args.push("--help".into());
776        }
777
778        if let Some(dbname) = &self.dbname {
779            args.push("--dbname".into());
780            args.push(dbname.into());
781        }
782
783        if let Some(host) = &self.host {
784            args.push("--host".into());
785            args.push(host.into());
786        }
787
788        if let Some(port) = &self.port {
789            args.push("--port".into());
790            args.push(port.to_string().into());
791        }
792
793        if let Some(username) = &self.username {
794            args.push("--username".into());
795            args.push(username.into());
796        }
797
798        if self.no_password {
799            args.push("--no-password".into());
800        }
801
802        if self.password {
803            args.push("--password".into());
804        }
805
806        if let Some(role) = &self.role {
807            args.push("--role".into());
808            args.push(role.into());
809        }
810
811        args
812    }
813
814    /// Get the environment variables for the command
815    fn get_envs(&self) -> Vec<(OsString, OsString)> {
816        let mut envs: Vec<(OsString, OsString)> = self.envs.clone();
817
818        if let Some(password) = &self.pg_password {
819            envs.push(("PGPASSWORD".into(), password.into()));
820        }
821
822        envs
823    }
824
825    /// Set an environment variable for the command
826    fn env<S: AsRef<OsStr>>(mut self, key: S, value: S) -> Self {
827        self.envs
828            .push((key.as_ref().to_os_string(), value.as_ref().to_os_string()));
829        self
830    }
831}
832
833#[cfg(test)]
834mod tests {
835    use super::*;
836    use crate::TestSettings;
837    use crate::traits::CommandToString;
838    use test_log::test;
839
840    #[test]
841    fn test_builder_new() {
842        let command = PgDumpBuilder::new().program_dir(".").build();
843        assert_eq!(
844            PathBuf::from(".").join("pg_dump"),
845            PathBuf::from(command.to_command_string().replace('"', ""))
846        );
847    }
848
849    #[test]
850    fn test_builder_from() {
851        let command = PgDumpBuilder::from(&TestSettings).build();
852        #[cfg(not(target_os = "windows"))]
853        let command_prefix = r#"PGPASSWORD="password" "./pg_dump" "#;
854        #[cfg(target_os = "windows")]
855        let command_prefix = r#"".\\pg_dump" "#;
856
857        assert_eq!(
858            format!(
859                r#"{command_prefix}"--host" "localhost" "--port" "5432" "--username" "postgres""#
860            ),
861            command.to_command_string()
862        );
863    }
864
865    #[test]
866    fn test_builder() {
867        let command = PgDumpBuilder::new()
868            .env("PGDATABASE", "database")
869            .data_only()
870            .large_objects()
871            .no_large_objects()
872            .clean()
873            .create()
874            .extension("extension")
875            .encoding("UTF8")
876            .file("file")
877            .format("format")
878            .jobs("jobs")
879            .schema("schema")
880            .exclude_schema("exclude_schema")
881            .no_owner()
882            .no_reconnect()
883            .schema_only()
884            .superuser("superuser")
885            .table("table")
886            .exclude_table("exclude_table")
887            .verbose()
888            .version()
889            .no_privileges()
890            .compression("compression")
891            .binary_upgrade()
892            .column_inserts()
893            .attribute_inserts()
894            .disable_dollar_quoting()
895            .disable_triggers()
896            .enable_row_security()
897            .exclude_table_data_and_children("exclude_table_data_and_children")
898            .extra_float_digits("extra_float_digits")
899            .if_exists()
900            .include_foreign_data("include_foreign_data")
901            .inserts()
902            .load_via_partition_root()
903            .lock_wait_timeout(10)
904            .no_comments()
905            .no_publications()
906            .no_security_labels()
907            .no_subscriptions()
908            .no_table_access_method()
909            .no_tablespaces()
910            .no_toast_compression()
911            .no_unlogged_table_data()
912            .on_conflict_do_nothing()
913            .quote_all_identifiers()
914            .rows_per_insert(100)
915            .section("section")
916            .serializable_deferrable()
917            .snapshot("snapshot")
918            .strict_names()
919            .table_and_children("table_and_children")
920            .use_set_session_authorization()
921            .help()
922            .dbname("dbname")
923            .host("localhost")
924            .port(5432)
925            .username("postgres")
926            .no_password()
927            .password()
928            .pg_password("password")
929            .role("role")
930            .build();
931        #[cfg(not(target_os = "windows"))]
932        let command_prefix = r#"PGDATABASE="database" PGPASSWORD="password" "#;
933        #[cfg(target_os = "windows")]
934        let command_prefix = String::new();
935
936        assert_eq!(
937            format!(
938                r#"{command_prefix}"pg_dump" "--data-only" "--large-objects" "--no-large-objects" "--clean" "--create" "--extension" "extension" "--encoding" "UTF8" "--file" "file" "--format" "format" "--jobs" "jobs" "--schema" "schema" "--exclude-schema" "exclude_schema" "--no-owner" "--no-reconnect" "--schema-only" "--superuser" "superuser" "--table" "table" "--exclude-table" "exclude_table" "--verbose" "--version" "--no-privileges" "--compression" "compression" "--binary-upgrade" "--column-inserts" "--attribute-inserts" "--disable-dollar-quoting" "--disable-triggers" "--enable-row-security" "--exclude-table-data-and-children" "exclude_table_data_and_children" "--extra-float-digits" "extra_float_digits" "--if-exists" "--include-foreign-data" "include_foreign_data" "--inserts" "--load-via-partition-root" "--lock-wait-timeout" "10" "--no-comments" "--no-publications" "--no-security-labels" "--no-subscriptions" "--no-table-access-method" "--no-tablespaces" "--no-toast-compression" "--no-unlogged-table-data" "--on-conflict-do-nothing" "--quote-all-identifiers" "--rows-per-insert" "100" "--section" "section" "--serializable-deferrable" "--snapshot" "snapshot" "--strict-names" "--table-and-children" "table_and_children" "--use-set-session-authorization" "--help" "--dbname" "dbname" "--host" "localhost" "--port" "5432" "--username" "postgres" "--no-password" "--password" "--role" "role""#
939            ),
940            command.to_command_string()
941        );
942    }
943}