1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
use clap::Parser;
use serde::{Deserialize, Serialize};
use url::Url;
use crate::WardenError;
#[derive(Parser, Clone, Deserialize, Serialize, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct Database {
/// Full database URL (if provided, overrides individual components)
#[arg(long, env = "DATABASE_URL")]
pub database_url: Option<Url>,
#[arg(long, env = "DB_USER")]
/// Database username
#[serde(rename = "username")]
pub database_username: Option<String>,
/// Database password
#[arg(long, env = "DB_PASSWORD")]
#[serde(rename = "password")]
pub database_password: Option<String>,
/// Database host
#[arg(long, env = "DB_HOST", default_value = "localhost")]
#[serde(rename = "host")]
pub database_host: Option<String>,
/// Database port
#[arg(long, env = "DB_PORT")]
#[serde(rename = "port")]
pub database_port: Option<u16>,
/// Database name
#[arg(long, env = "DB_NAME")]
#[serde(rename = "name")]
pub database_name: Option<String>,
/// Database pool size
#[arg(long, env = "DATABASE_POOL_SIZE", default_value = "10")]
#[serde(rename = "pool-size")]
pub database_pool_size: Option<u32>,
}
impl Default for Database {
fn default() -> Self {
Self {
database_url: Default::default(),
database_username: Some(String::from("postgres")),
database_password: Some(String::from("password")),
database_host: Some(String::from("localhost")),
database_port: Some(5432),
database_name: Some(String::from("warden")),
database_pool_size: Some(10),
}
}
}
impl Database {
pub fn merge(cli: &Self, file: &Self) -> Result<Self, WardenError> {
let url = cli.database_url.clone().or(file.database_url.clone());
let pool_size = cli
.database_pool_size
.or(file.database_pool_size)
.unwrap_or(10);
let final_url = match url {
Some(u) => u,
None => {
let host = cli
.database_host
.clone()
.or(file.database_host.clone())
.unwrap_or_else(|| "localhost".to_string());
let mut u = Url::parse(&format!("postgresql://{}", host))?;
let user = cli
.database_username
.as_ref()
.or(file.database_username.as_ref());
let pass = cli
.database_password
.as_ref()
.or(file.database_password.as_ref());
let port = cli.database_port.or(file.database_port);
let name = cli.database_name.as_ref().or(file.database_name.as_ref());
if let Some(user) = user {
u.set_username(user).ok();
}
if let Some(pass) = pass {
u.set_password(Some(pass)).ok();
}
if let Some(port) = port {
u.set_port(Some(port)).ok();
}
if let Some(name) = name {
u.set_path(name);
}
u
}
};
Ok(Self {
database_url: Some(final_url),
database_pool_size: Some(pool_size),
..cli.clone()
})
}
pub fn get_url(&self) -> Result<Url, url::ParseError> {
if let Some(ref url) = self.database_url {
return Ok(url.clone());
}
let host = "localhost".to_owned();
let host = self.database_host.as_ref().unwrap_or_else(|| &host);
let mut url = Url::parse(&format!("postgres://{host}"))?;
if let Some(ref u) = self.database_username {
url.set_username(u).ok();
}
if let Some(ref p) = self.database_password {
url.set_password(Some(p)).ok();
}
url.set_port(self.database_port).ok();
if let Some(ref name) = self.database_name {
url.set_path(name);
}
Ok(url)
}
}
|