use crate::traits::CommandBuilder;
use crate::Settings;
use std::convert::AsRef;
use std::ffi::{OsStr, OsString};
use std::path::PathBuf;
#[derive(Clone, Debug, Default)]
pub struct PgRecvLogicalBuilder {
program_dir: Option<PathBuf>,
create_slot: bool,
drop_slot: bool,
start: bool,
endpos: Option<OsString>,
file: Option<OsString>,
fsync_interval: Option<OsString>,
if_not_exists: bool,
startpos: Option<OsString>,
no_loop: bool,
option: Option<OsString>,
plugin: Option<OsString>,
status_interval: Option<OsString>,
slot: Option<OsString>,
two_phase: bool,
verbose: bool,
version: bool,
help: bool,
dbname: Option<OsString>,
host: Option<OsString>,
port: Option<u16>,
username: Option<OsString>,
no_password: bool,
password: bool,
pg_password: Option<OsString>,
}
impl PgRecvLogicalBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn from(settings: &dyn Settings) -> Self {
Self::new()
.program_dir(settings.get_binary_dir())
.host(settings.get_host())
.port(settings.get_port())
.username(settings.get_username())
.pg_password(settings.get_password())
}
pub fn program_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
self.program_dir = Some(path.into());
self
}
pub fn create_slot(mut self) -> Self {
self.create_slot = true;
self
}
pub fn drop_slot(mut self) -> Self {
self.drop_slot = true;
self
}
pub fn start(mut self) -> Self {
self.start = true;
self
}
pub fn endpos<S: AsRef<OsStr>>(mut self, endpos: S) -> Self {
self.endpos = Some(endpos.as_ref().to_os_string());
self
}
pub fn file<S: AsRef<OsStr>>(mut self, file: S) -> Self {
self.file = Some(file.as_ref().to_os_string());
self
}
pub fn fsync_interval<S: AsRef<OsStr>>(mut self, fsync_interval: S) -> Self {
self.fsync_interval = Some(fsync_interval.as_ref().to_os_string());
self
}
pub fn if_not_exists(mut self) -> Self {
self.if_not_exists = true;
self
}
pub fn startpos<S: AsRef<OsStr>>(mut self, startpos: S) -> Self {
self.startpos = Some(startpos.as_ref().to_os_string());
self
}
pub fn no_loop(mut self) -> Self {
self.no_loop = true;
self
}
pub fn option<S: AsRef<OsStr>>(mut self, option: S) -> Self {
self.option = Some(option.as_ref().to_os_string());
self
}
pub fn plugin<S: AsRef<OsStr>>(mut self, plugin: S) -> Self {
self.plugin = Some(plugin.as_ref().to_os_string());
self
}
pub fn status_interval<S: AsRef<OsStr>>(mut self, status_interval: S) -> Self {
self.status_interval = Some(status_interval.as_ref().to_os_string());
self
}
pub fn slot<S: AsRef<OsStr>>(mut self, slot: S) -> Self {
self.slot = Some(slot.as_ref().to_os_string());
self
}
pub fn two_phase(mut self) -> Self {
self.two_phase = true;
self
}
pub fn verbose(mut self) -> Self {
self.verbose = true;
self
}
pub fn version(mut self) -> Self {
self.version = true;
self
}
pub fn help(mut self) -> Self {
self.help = true;
self
}
pub fn dbname<S: AsRef<OsStr>>(mut self, dbname: S) -> Self {
self.dbname = Some(dbname.as_ref().to_os_string());
self
}
pub fn host<S: AsRef<OsStr>>(mut self, host: S) -> Self {
self.host = Some(host.as_ref().to_os_string());
self
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn username<S: AsRef<OsStr>>(mut self, username: S) -> Self {
self.username = Some(username.as_ref().to_os_string());
self
}
pub fn no_password(mut self) -> Self {
self.no_password = true;
self
}
pub fn password(mut self) -> Self {
self.password = true;
self
}
pub fn pg_password<S: AsRef<OsStr>>(mut self, pg_password: S) -> Self {
self.pg_password = Some(pg_password.as_ref().to_os_string());
self
}
}
impl CommandBuilder for PgRecvLogicalBuilder {
fn get_program(&self) -> &'static OsStr {
"pg_recvlogical".as_ref()
}
fn get_program_dir(&self) -> &Option<PathBuf> {
&self.program_dir
}
fn get_args(&self) -> Vec<OsString> {
let mut args: Vec<OsString> = Vec::new();
if self.create_slot {
args.push("--create-slot".into());
}
if self.drop_slot {
args.push("--drop-slot".into());
}
if self.start {
args.push("--start".into());
}
if let Some(endpos) = &self.endpos {
args.push("--endpos".into());
args.push(endpos.into());
}
if let Some(file) = &self.file {
args.push("--file".into());
args.push(file.into());
}
if let Some(fsync_interval) = &self.fsync_interval {
args.push("--fsync-interval".into());
args.push(fsync_interval.into());
}
if self.if_not_exists {
args.push("--if-not-exists".into());
}
if let Some(startpos) = &self.startpos {
args.push("--startpos".into());
args.push(startpos.into());
}
if self.no_loop {
args.push("--no-loop".into());
}
if let Some(option) = &self.option {
args.push("--option".into());
args.push(option.into());
}
if let Some(plugin) = &self.plugin {
args.push("--plugin".into());
args.push(plugin.into());
}
if let Some(status_interval) = &self.status_interval {
args.push("--status-interval".into());
args.push(status_interval.into());
}
if let Some(slot) = &self.slot {
args.push("--slot".into());
args.push(slot.into());
}
if self.two_phase {
args.push("--two-phase".into());
}
if self.verbose {
args.push("--verbose".into());
}
if self.version {
args.push("--version".into());
}
if self.help {
args.push("--help".into());
}
if let Some(dbname) = &self.dbname {
args.push("--dbname".into());
args.push(dbname.into());
}
if let Some(host) = &self.host {
args.push("--host".into());
args.push(host.into());
}
if let Some(port) = &self.port {
args.push("--port".into());
args.push(port.to_string().into());
}
if let Some(username) = &self.username {
args.push("--username".into());
args.push(username.into());
}
if self.no_password {
args.push("--no-password".into());
}
if self.password {
args.push("--password".into());
}
args
}
fn get_envs(&self) -> Vec<(OsString, OsString)> {
let mut envs: Vec<(OsString, OsString)> = Vec::new();
if let Some(password) = &self.pg_password {
envs.push(("PGPASSWORD".into(), password.into()));
}
envs
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::traits::CommandToString;
use crate::TestSettings;
use test_log::test;
#[test]
fn test_builder_new() {
let command = PgRecvLogicalBuilder::new().program_dir(".").build();
assert_eq!(
PathBuf::from(".").join("pg_recvlogical"),
PathBuf::from(command.to_command_string().replace("\"", ""))
);
}
#[test]
fn test_builder_from() {
let command = PgRecvLogicalBuilder::from(&TestSettings).build();
assert_eq!(
r#"PGPASSWORD="password" "./pg_recvlogical" "--host" "localhost" "--port" "5432" "--username" "postgres""#,
command.to_command_string()
)
}
#[test]
fn test_builder() {
let command = PgRecvLogicalBuilder::new()
.create_slot()
.drop_slot()
.start()
.endpos("endpos")
.file("file")
.fsync_interval("fsync_interval")
.if_not_exists()
.startpos("startpos")
.no_loop()
.option("option")
.plugin("plugin")
.status_interval("status_interval")
.slot("slot")
.two_phase()
.verbose()
.version()
.help()
.dbname("dbname")
.host("localhost")
.port(5432)
.username("username")
.no_password()
.password()
.pg_password("password")
.build();
assert_eq!(
r#"PGPASSWORD="password" "pg_recvlogical" "--create-slot" "--drop-slot" "--start" "--endpos" "endpos" "--file" "file" "--fsync-interval" "fsync_interval" "--if-not-exists" "--startpos" "startpos" "--no-loop" "--option" "option" "--plugin" "plugin" "--status-interval" "status_interval" "--slot" "slot" "--two-phase" "--verbose" "--version" "--help" "--dbname" "dbname" "--host" "localhost" "--port" "5432" "--username" "username" "--no-password" "--password""#,
command.to_command_string()
);
}
}