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