1use serde::Deserialize;
2use std::sync::Arc;
3
4#[derive(Deserialize)]
6pub struct Config {
7 host: Option<Arc<str>>,
8 port: Option<u16>,
9 max_connections: Option<u32>,
10 min_connections: Option<u32>,
11 acquire_timeout: Option<u64>,
12 idle_timeout: Option<u64>,
13 max_lifetime: Option<u64>,
14 username: Option<Arc<str>>,
15 password: Option<Arc<str>>,
16 database: Option<Arc<str>>,
17 root_username: Option<Arc<str>>,
18 root_password: Option<Arc<str>>,
19 root_database: Option<Arc<str>>,
20 #[serde(skip)]
21 address: Option<Arc<str>>,
22 #[serde(skip)]
23 root_address: Option<Arc<str>>,
24}
25
26impl Config {
27 pub fn new() -> envy::Result<Self> {
29 ConfigBuilder::default().build()
30 }
31
32 pub fn builder<'a>() -> ConfigBuilder<'a> {
34 ConfigBuilder::default()
35 }
36
37 pub fn max_connections(&self) -> u32 {
39 self.max_connections.unwrap_or(32)
40 }
41
42 pub fn min_connections(&self) -> u32 {
44 self.min_connections.unwrap_or(0)
45 }
46
47 pub fn acquire_timeout(&self) -> u64 {
49 self.acquire_timeout.unwrap_or(30)
50 }
51
52 pub fn idle_timeout(&self) -> u64 {
54 self.idle_timeout.unwrap_or(10 * 60)
55 }
56
57 pub fn max_lifetime(&self) -> u64 {
59 self.max_lifetime.unwrap_or(30 * 60)
60 }
61
62 pub fn database(&self) -> Option<&str> {
64 self.database.as_deref()
65 }
66
67 pub fn username(&self) -> Option<&str> {
69 self.username.as_deref()
70 }
71
72 pub fn password(&self) -> Option<&str> {
74 self.password.as_deref()
75 }
76
77 pub fn root_database(&self) -> Option<&str> {
79 self.root_database.as_deref()
80 }
81
82 pub fn address(&self) -> &str {
84 self.address.as_deref().unwrap()
85 }
86
87 pub fn root_address(&self) -> &str {
89 self.root_address.as_deref().unwrap()
90 }
91}
92
93#[derive(Default)]
95pub struct ConfigBuilder<'a> {
96 prefix: Option<&'a str>,
97}
98
99impl<'a> ConfigBuilder<'a> {
100 pub fn with_prefix(mut self, prefix: &'a str) -> Self {
102 self.prefix = Some(prefix);
103 self
104 }
105
106 pub fn build(self) -> envy::Result<Config> {
108 let mut cfg: Config = if let Some(prefix) = self.prefix {
109 envy::prefixed(prefix)
110 } else {
111 envy::prefixed("PG_")
112 }
113 .from_env()?;
114 let host = cfg.host.as_deref().unwrap_or("127.0.0.1");
115 let port = cfg.port.unwrap_or(5432);
116 let mut address = match (cfg.username.as_deref(), cfg.password.as_deref()) {
117 (Some(username), Some(password)) => {
118 format!("postgresql://{}:{}@{}:{}/", username, password, host, port)
119 }
120 (Some(username), None) => format!("postgresql://{}@{}:{}/", username, host, port),
121 _ => format!("postgresql://{}:{}/", host, port),
122 };
123 if let Some(database) = cfg.database.as_deref() {
124 address.push_str(database);
125 }
126 cfg.address = Some(Arc::from(address));
127 let mut root_address = match (cfg.root_username.as_deref(), cfg.root_password.as_deref()) {
128 (Some(root_username), Some(root_password)) => format!(
129 "postgresql://{}:{}@{}:{}/",
130 root_username, root_password, host, port
131 ),
132 (Some(root_username), None) => {
133 format!("postgresql://{}@{}:{}/", root_username, host, port)
134 }
135 _ => format!("postgresql://{}:{}/", host, port),
136 };
137 if let Some(root_database) = cfg.root_database.as_deref() {
138 root_address.push_str(root_database);
139 }
140 cfg.root_address = Some(Arc::from(root_address));
141 Ok(cfg)
142 }
143}