postgresql_commands/
clusterdb.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 ClusterDbBuilder {
10 program_dir: Option<PathBuf>,
11 envs: Vec<(OsString, OsString)>,
12 all: bool,
13 dbname: Option<OsString>,
14 echo: bool,
15 quiet: bool,
16 table: Option<OsString>,
17 verbose: bool,
18 version: bool,
19 help: bool,
20 host: Option<OsString>,
21 port: Option<u16>,
22 username: Option<OsString>,
23 no_password: bool,
24 password: bool,
25 pg_password: Option<OsString>,
26 maintenance_db: Option<OsString>,
27}
28
29impl ClusterDbBuilder {
30 #[must_use]
32 pub fn new() -> Self {
33 Self::default()
34 }
35
36 pub fn from(settings: &dyn Settings) -> Self {
38 let mut builder = Self::new()
39 .program_dir(settings.get_binary_dir())
40 .host(settings.get_host())
41 .port(settings.get_port())
42 .username(settings.get_username())
43 .pg_password(settings.get_password());
44 if let Some(socket_dir) = settings.get_socket_dir() {
45 builder = builder.host(socket_dir.to_string_lossy().to_string());
46 }
47 builder
48 }
49
50 #[must_use]
52 fn program_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
53 self.program_dir = Some(path.into());
54 self
55 }
56
57 #[must_use]
59 pub fn all(mut self) -> Self {
60 self.all = true;
61 self
62 }
63
64 #[must_use]
66 pub fn dbname<S: AsRef<OsStr>>(mut self, dbname: S) -> Self {
67 self.dbname = Some(dbname.as_ref().to_os_string());
68 self
69 }
70
71 #[must_use]
73 pub fn echo(mut self) -> Self {
74 self.echo = true;
75 self
76 }
77
78 #[must_use]
80 pub fn quiet(mut self) -> Self {
81 self.quiet = true;
82 self
83 }
84
85 #[must_use]
87 pub fn table<S: AsRef<OsStr>>(mut self, table: S) -> Self {
88 self.table = Some(table.as_ref().to_os_string());
89 self
90 }
91
92 #[must_use]
94 pub fn verbose(mut self) -> Self {
95 self.verbose = true;
96 self
97 }
98
99 #[must_use]
101 pub fn version(mut self) -> Self {
102 self.version = true;
103 self
104 }
105
106 #[must_use]
108 pub fn help(mut self) -> Self {
109 self.help = true;
110 self
111 }
112
113 #[must_use]
115 pub fn host<S: AsRef<OsStr>>(mut self, host: S) -> Self {
116 self.host = Some(host.as_ref().to_os_string());
117 self
118 }
119
120 #[must_use]
122 pub fn port(mut self, port: u16) -> Self {
123 self.port = Some(port);
124 self
125 }
126
127 #[must_use]
129 pub fn username<S: AsRef<OsStr>>(mut self, username: S) -> Self {
130 self.username = Some(username.as_ref().to_os_string());
131 self
132 }
133
134 #[must_use]
136 pub fn no_password(mut self) -> Self {
137 self.no_password = true;
138 self
139 }
140
141 #[must_use]
143 pub fn password(mut self) -> Self {
144 self.password = true;
145 self
146 }
147
148 #[must_use]
150 pub fn pg_password<S: AsRef<OsStr>>(mut self, pg_password: S) -> Self {
151 self.pg_password = Some(pg_password.as_ref().to_os_string());
152 self
153 }
154
155 #[must_use]
157 pub fn maintenance_db<S: AsRef<OsStr>>(mut self, db: S) -> Self {
158 self.maintenance_db = Some(db.as_ref().to_os_string());
159 self
160 }
161}
162
163impl CommandBuilder for ClusterDbBuilder {
164 fn get_program(&self) -> &'static OsStr {
166 "clusterdb".as_ref()
167 }
168
169 fn get_program_dir(&self) -> &Option<PathBuf> {
171 &self.program_dir
172 }
173
174 fn get_args(&self) -> Vec<OsString> {
176 let mut args: Vec<OsString> = Vec::new();
177
178 if self.all {
179 args.push("--all".into());
180 }
181
182 if let Some(dbname) = &self.dbname {
183 args.push("--dbname".into());
184 args.push(dbname.into());
185 }
186
187 if self.echo {
188 args.push("--echo".into());
189 }
190
191 if self.quiet {
192 args.push("--quiet".into());
193 }
194
195 if let Some(table) = &self.table {
196 args.push("--table".into());
197 args.push(table.into());
198 }
199
200 if self.verbose {
201 args.push("--verbose".into());
202 }
203
204 if self.version {
205 args.push("--version".into());
206 }
207
208 if self.help {
209 args.push("--help".into());
210 }
211
212 if let Some(host) = &self.host {
213 args.push("--host".into());
214 args.push(host.into());
215 }
216
217 if let Some(port) = &self.port {
218 args.push("--port".into());
219 args.push(port.to_string().into());
220 }
221
222 if let Some(username) = &self.username {
223 args.push("--username".into());
224 args.push(username.into());
225 }
226
227 if self.no_password {
228 args.push("--no-password".into());
229 }
230
231 if self.password {
232 args.push("--password".into());
233 }
234
235 if let Some(maintenance_db) = &self.maintenance_db {
236 args.push("--maintenance-db".into());
237 args.push(maintenance_db.into());
238 }
239
240 args
241 }
242
243 fn get_envs(&self) -> Vec<(OsString, OsString)> {
245 let mut envs: Vec<(OsString, OsString)> = self.envs.clone();
246
247 if let Some(password) = &self.pg_password {
248 envs.push(("PGPASSWORD".into(), password.into()));
249 }
250
251 envs
252 }
253
254 fn env<S: AsRef<OsStr>>(mut self, key: S, value: S) -> Self {
256 self.envs
257 .push((key.as_ref().to_os_string(), value.as_ref().to_os_string()));
258 self
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265 use crate::TestSettings;
266 use crate::TestSocketSettings;
267 use crate::traits::CommandToString;
268 use test_log::test;
269
270 #[test]
271 fn test_builder_new() {
272 let command = ClusterDbBuilder::new().program_dir(".").build();
273 assert_eq!(
274 PathBuf::from(".").join("clusterdb"),
275 PathBuf::from(command.to_command_string().replace('"', ""))
276 );
277 }
278
279 #[test]
280 fn test_builder_from() {
281 let command = ClusterDbBuilder::from(&TestSettings).build();
282 #[cfg(not(target_os = "windows"))]
283 let command_prefix = r#"PGPASSWORD="password" "./clusterdb" "#;
284 #[cfg(target_os = "windows")]
285 let command_prefix = r#"".\\clusterdb" "#;
286
287 assert_eq!(
288 format!(
289 r#"{command_prefix}"--host" "localhost" "--port" "5432" "--username" "postgres""#
290 ),
291 command.to_command_string()
292 );
293 }
294
295 #[test]
296 fn test_builder() {
297 let command = ClusterDbBuilder::new()
298 .env("PGDATABASE", "database")
299 .all()
300 .dbname("dbname")
301 .echo()
302 .quiet()
303 .table("table")
304 .verbose()
305 .version()
306 .help()
307 .host("localhost")
308 .port(5432)
309 .username("postgres")
310 .no_password()
311 .password()
312 .pg_password("password")
313 .maintenance_db("postgres")
314 .build();
315 #[cfg(not(target_os = "windows"))]
316 let command_prefix = r#"PGDATABASE="database" PGPASSWORD="password" "#;
317 #[cfg(target_os = "windows")]
318 let command_prefix = String::new();
319
320 assert_eq!(
321 format!(
322 r#"{command_prefix}"clusterdb" "--all" "--dbname" "dbname" "--echo" "--quiet" "--table" "table" "--verbose" "--version" "--help" "--host" "localhost" "--port" "5432" "--username" "postgres" "--no-password" "--password" "--maintenance-db" "postgres""#
323 ),
324 command.to_command_string()
325 );
326 }
327
328 #[test]
329 fn test_builder_from_socket() {
330 let command = ClusterDbBuilder::from(&TestSocketSettings).build();
331 #[cfg(not(target_os = "windows"))]
332 let command_prefix = r#"PGPASSWORD="password" "./clusterdb" "#;
333 #[cfg(target_os = "windows")]
334 let command_prefix = r#"".\\clusterdb" "#;
335
336 assert_eq!(
337 format!(
338 r#"{command_prefix}"--host" "/tmp/pg_socket" "--port" "5432" "--username" "postgres""#
339 ),
340 command.to_command_string()
341 );
342 }
343}