qm_pg/
config.rs

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}