postgresql_commands/
pg_isready.rs

1use crate::Settings;
2use crate::traits::CommandBuilder;
3use std::convert::AsRef;
4use std::ffi::{OsStr, OsString};
5use std::path::PathBuf;
6
7/// `pg_isready` issues a connection check to a `PostgreSQL` database.
8#[derive(Clone, Debug, Default)]
9pub struct PgIsReadyBuilder {
10    program_dir: Option<PathBuf>,
11    envs: Vec<(OsString, OsString)>,
12    dbname: Option<OsString>,
13    quiet: bool,
14    version: bool,
15    help: bool,
16    host: Option<OsString>,
17    port: Option<u16>,
18    timeout: Option<u16>,
19    username: Option<OsString>,
20}
21
22impl PgIsReadyBuilder {
23    /// Create a new [`PgIsReadyBuilder`]
24    #[must_use]
25    pub fn new() -> Self {
26        Self::default()
27    }
28
29    /// Create a new [`PgIsReadyBuilder`] from [Settings]
30    pub fn from(settings: &dyn Settings) -> Self {
31        Self::new()
32            .program_dir(settings.get_binary_dir())
33            .host(settings.get_host())
34            .port(settings.get_port())
35            .username(settings.get_username())
36    }
37
38    /// Location of the program binary
39    #[must_use]
40    pub fn program_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
41        self.program_dir = Some(path.into());
42        self
43    }
44
45    /// Set the database name
46    #[must_use]
47    pub fn dbname<S: AsRef<OsStr>>(mut self, dbname: S) -> Self {
48        self.dbname = Some(dbname.as_ref().to_os_string());
49        self
50    }
51
52    /// Run quietly
53    #[must_use]
54    pub fn quiet(mut self) -> Self {
55        self.quiet = true;
56        self
57    }
58
59    /// Output version information, then exit
60    #[must_use]
61    pub fn version(mut self) -> Self {
62        self.version = true;
63        self
64    }
65
66    /// Show help, then exit
67    #[must_use]
68    pub fn help(mut self) -> Self {
69        self.help = true;
70        self
71    }
72
73    /// Set the database server host or socket directory
74    #[must_use]
75    pub fn host<S: AsRef<OsStr>>(mut self, host: S) -> Self {
76        self.host = Some(host.as_ref().to_os_string());
77        self
78    }
79
80    /// Set the database server port
81    #[must_use]
82    pub fn port(mut self, port: u16) -> Self {
83        self.port = Some(port);
84        self
85    }
86
87    /// Set the seconds to wait when attempting connection, 0 disables (default: 3)
88    #[must_use]
89    pub fn timeout(mut self, timeout: u16) -> Self {
90        self.timeout = Some(timeout);
91        self
92    }
93
94    /// Set the user name to connect as
95    #[must_use]
96    pub fn username<S: AsRef<OsStr>>(mut self, username: S) -> Self {
97        self.username = Some(username.as_ref().to_os_string());
98        self
99    }
100}
101
102impl CommandBuilder for PgIsReadyBuilder {
103    /// Get the program name
104    fn get_program(&self) -> &'static OsStr {
105        "pg_isready".as_ref()
106    }
107
108    /// Location of the program binary
109    fn get_program_dir(&self) -> &Option<PathBuf> {
110        &self.program_dir
111    }
112
113    /// Get the arguments for the command
114    fn get_args(&self) -> Vec<OsString> {
115        let mut args: Vec<OsString> = Vec::new();
116
117        if let Some(dbname) = &self.dbname {
118            args.push("--dbname".into());
119            args.push(dbname.into());
120        }
121
122        if self.quiet {
123            args.push("--quiet".into());
124        }
125
126        if self.version {
127            args.push("--version".into());
128        }
129
130        if self.help {
131            args.push("--help".into());
132        }
133
134        if let Some(host) = &self.host {
135            args.push("--host".into());
136            args.push(host.into());
137        }
138
139        if let Some(port) = &self.port {
140            args.push("--port".into());
141            args.push(port.to_string().into());
142        }
143
144        if let Some(timeout) = &self.timeout {
145            args.push("--timeout".into());
146            args.push(timeout.to_string().into());
147        }
148
149        if let Some(username) = &self.username {
150            args.push("--username".into());
151            args.push(username.into());
152        }
153
154        args
155    }
156
157    /// Get the environment variables for the command
158    fn get_envs(&self) -> Vec<(OsString, OsString)> {
159        self.envs.clone()
160    }
161
162    /// Set an environment variable for the command
163    fn env<S: AsRef<OsStr>>(mut self, key: S, value: S) -> Self {
164        self.envs
165            .push((key.as_ref().to_os_string(), value.as_ref().to_os_string()));
166        self
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    use super::*;
173    use crate::TestSettings;
174    use crate::traits::CommandToString;
175    use test_log::test;
176
177    #[test]
178    fn test_builder_new() {
179        let command = PgIsReadyBuilder::new().program_dir(".").build();
180        assert_eq!(
181            PathBuf::from(".").join("pg_isready"),
182            PathBuf::from(command.to_command_string().replace('"', ""))
183        );
184    }
185
186    #[test]
187    fn test_builder_from() {
188        let command = PgIsReadyBuilder::from(&TestSettings).build();
189        #[cfg(not(target_os = "windows"))]
190        let command_prefix = r#""./pg_isready" "#;
191        #[cfg(target_os = "windows")]
192        let command_prefix = r#"".\\pg_isready" "#;
193
194        assert_eq!(
195            format!(
196                r#"{command_prefix}"--host" "localhost" "--port" "5432" "--username" "postgres""#
197            ),
198            command.to_command_string()
199        );
200    }
201
202    #[test]
203    fn test_builder() {
204        let command = PgIsReadyBuilder::new()
205            .env("PGDATABASE", "database")
206            .dbname("postgres")
207            .quiet()
208            .version()
209            .help()
210            .host("localhost")
211            .port(5432)
212            .timeout(3)
213            .username("postgres")
214            .build();
215        #[cfg(not(target_os = "windows"))]
216        let command_prefix = r#"PGDATABASE="database" "#;
217        #[cfg(target_os = "windows")]
218        let command_prefix = String::new();
219
220        assert_eq!(
221            format!(
222                r#"{command_prefix}"pg_isready" "--dbname" "postgres" "--quiet" "--version" "--help" "--host" "localhost" "--port" "5432" "--timeout" "3" "--username" "postgres""#
223            ),
224            command.to_command_string()
225        );
226    }
227}