1use 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 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 #[must_use]
78 pub fn new() -> Self {
79 Self::default()
80 }
81
82 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 #[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 #[must_use]
101 pub fn data_only(mut self) -> Self {
102 self.data_only = true;
103 self
104 }
105
106 #[must_use]
108 pub fn large_objects(mut self) -> Self {
109 self.large_objects = true;
110 self
111 }
112
113 #[must_use]
115 pub fn no_large_objects(mut self) -> Self {
116 self.no_large_objects = true;
117 self
118 }
119
120 #[must_use]
122 pub fn clean(mut self) -> Self {
123 self.clean = true;
124 self
125 }
126
127 #[must_use]
129 pub fn create(mut self) -> Self {
130 self.create = true;
131 self
132 }
133
134 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[must_use]
185 pub fn no_owner(mut self) -> Self {
186 self.no_owner = true;
187 self
188 }
189
190 #[must_use]
192 pub fn no_reconnect(mut self) -> Self {
193 self.no_reconnect = true;
194 self
195 }
196
197 #[must_use]
199 pub fn schema_only(mut self) -> Self {
200 self.schema_only = true;
201 self
202 }
203
204 #[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 #[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 #[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 #[must_use]
227 pub fn verbose(mut self) -> Self {
228 self.verbose = true;
229 self
230 }
231
232 #[must_use]
234 pub fn version(mut self) -> Self {
235 self.version = true;
236 self
237 }
238
239 #[must_use]
241 pub fn no_privileges(mut self) -> Self {
242 self.no_privileges = true;
243 self
244 }
245
246 #[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 #[must_use]
255 pub fn binary_upgrade(mut self) -> Self {
256 self.binary_upgrade = true;
257 self
258 }
259
260 #[must_use]
262 pub fn column_inserts(mut self) -> Self {
263 self.column_inserts = true;
264 self
265 }
266
267 #[must_use]
269 pub fn attribute_inserts(mut self) -> Self {
270 self.attribute_inserts = true;
271 self
272 }
273
274 #[must_use]
276 pub fn disable_dollar_quoting(mut self) -> Self {
277 self.disable_dollar_quoting = true;
278 self
279 }
280
281 #[must_use]
283 pub fn disable_triggers(mut self) -> Self {
284 self.disable_triggers = true;
285 self
286 }
287
288 #[must_use]
290 pub fn enable_row_security(mut self) -> Self {
291 self.enable_row_security = true;
292 self
293 }
294
295 #[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 #[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 #[must_use]
315 pub fn if_exists(mut self) -> Self {
316 self.if_exists = true;
317 self
318 }
319
320 #[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 #[must_use]
329 pub fn inserts(mut self) -> Self {
330 self.inserts = true;
331 self
332 }
333
334 #[must_use]
336 pub fn load_via_partition_root(mut self) -> Self {
337 self.load_via_partition_root = true;
338 self
339 }
340
341 #[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 #[must_use]
350 pub fn no_comments(mut self) -> Self {
351 self.no_comments = true;
352 self
353 }
354
355 #[must_use]
357 pub fn no_publications(mut self) -> Self {
358 self.no_publications = true;
359 self
360 }
361
362 #[must_use]
364 pub fn no_security_labels(mut self) -> Self {
365 self.no_security_labels = true;
366 self
367 }
368
369 #[must_use]
371 pub fn no_subscriptions(mut self) -> Self {
372 self.no_subscriptions = true;
373 self
374 }
375
376 #[must_use]
378 pub fn no_table_access_method(mut self) -> Self {
379 self.no_table_access_method = true;
380 self
381 }
382
383 #[must_use]
385 pub fn no_tablespaces(mut self) -> Self {
386 self.no_tablespaces = true;
387 self
388 }
389
390 #[must_use]
392 pub fn no_toast_compression(mut self) -> Self {
393 self.no_toast_compression = true;
394 self
395 }
396
397 #[must_use]
399 pub fn no_unlogged_table_data(mut self) -> Self {
400 self.no_unlogged_table_data = true;
401 self
402 }
403
404 #[must_use]
406 pub fn on_conflict_do_nothing(mut self) -> Self {
407 self.on_conflict_do_nothing = true;
408 self
409 }
410
411 #[must_use]
413 pub fn quote_all_identifiers(mut self) -> Self {
414 self.quote_all_identifiers = true;
415 self
416 }
417
418 #[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 #[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 #[must_use]
434 pub fn serializable_deferrable(mut self) -> Self {
435 self.serializable_deferrable = true;
436 self
437 }
438
439 #[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 #[must_use]
448 pub fn strict_names(mut self) -> Self {
449 self.strict_names = true;
450 self
451 }
452
453 #[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 #[must_use]
462 pub fn use_set_session_authorization(mut self) -> Self {
463 self.use_set_session_authorization = true;
464 self
465 }
466
467 #[must_use]
469 pub fn help(mut self) -> Self {
470 self.help = true;
471 self
472 }
473
474 #[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 #[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 #[must_use]
490 pub fn port(mut self, port: u16) -> Self {
491 self.port = Some(port);
492 self
493 }
494
495 #[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 #[must_use]
504 pub fn no_password(mut self) -> Self {
505 self.no_password = true;
506 self
507 }
508
509 #[must_use]
511 pub fn password(mut self) -> Self {
512 self.password = true;
513 self
514 }
515
516 #[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 #[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 fn get_program(&self) -> &'static OsStr {
534 "pg_dump".as_ref()
535 }
536
537 fn get_program_dir(&self) -> &Option<PathBuf> {
539 &self.program_dir
540 }
541
542 #[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 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 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}