db_pool/common/config/
postgres.rs

1/// Privileged Postgres configuration
2pub struct PrivilegedPostgresConfig {
3    pub(crate) username: String,
4    pub(crate) password: Option<String>,
5    pub(crate) host: String,
6    pub(crate) port: u16,
7}
8
9impl PrivilegedPostgresConfig {
10    const DEFAULT_USERNAME: &'static str = "postgres";
11    const DEFAULT_PASSWORD: Option<String> = None;
12    const DEFAULT_HOST: &'static str = "localhost";
13    const DEFAULT_PORT: u16 = 5432;
14
15    /// Creates a new privileged Postgres configuration with defaults
16    /// # Example
17    /// ```
18    /// # use db_pool::PrivilegedPostgresConfig;
19    /// #
20    /// let config = PrivilegedPostgresConfig::new();
21    /// ```
22    /// # Defaults
23    /// - Username: postgres
24    /// - Password: {blank}
25    /// - Host: localhost
26    /// - Port: 5432
27    #[must_use]
28    pub fn new() -> Self {
29        Self {
30            username: Self::DEFAULT_USERNAME.to_owned(),
31            password: Self::DEFAULT_PASSWORD,
32            host: Self::DEFAULT_HOST.to_owned(),
33            port: Self::DEFAULT_PORT,
34        }
35    }
36
37    /// Creates a new privileged Postgres configuration from environment variables
38    /// # Environment variables
39    /// - `POSTGRES_USERNAME`
40    /// - `POSTGRES_PASSWORD`
41    /// - `POSTGRES_HOST`
42    /// - `POSTGRES_PORT`
43    /// # Defaults
44    /// - Username: postgres
45    /// - Password: {blank}
46    /// - Host: localhost
47    /// - Port: 5432
48    pub fn from_env() -> Result<Self, Error> {
49        use std::env;
50
51        let username = env::var("POSTGRES_USERNAME").unwrap_or(Self::DEFAULT_USERNAME.to_owned());
52        let password = env::var("POSTGRES_PASSWORD").ok();
53        let host = env::var("POSTGRES_HOST").unwrap_or(Self::DEFAULT_HOST.to_owned());
54        let port = env::var("POSTGRES_PORT")
55            .map_or(Ok(Self::DEFAULT_PORT), |port| port.parse())
56            .map_err(Error::InvalidPort)?;
57
58        Ok(Self {
59            username,
60            password,
61            host,
62            port,
63        })
64    }
65
66    /// Sets a new username
67    /// # Example
68    /// ```
69    /// # use db_pool::PrivilegedPostgresConfig;
70    /// #
71    /// let config =
72    ///     PrivilegedPostgresConfig::new().username("postgres".to_owned());
73    /// ```
74    #[must_use]
75    pub fn username(self, value: String) -> Self {
76        Self {
77            username: value,
78            ..self
79        }
80    }
81
82    /// Sets a new password
83    /// # Example
84    /// ```
85    /// # use db_pool::PrivilegedPostgresConfig;
86    /// #
87    /// let config =
88    ///     PrivilegedPostgresConfig::new().password(Some("postgres".to_owned()));
89    /// ```
90    #[must_use]
91    pub fn password(self, value: Option<String>) -> Self {
92        Self {
93            password: value,
94            ..self
95        }
96    }
97
98    /// Sets a new host
99    /// # Example
100    /// ```
101    /// # use db_pool::PrivilegedPostgresConfig;
102    /// #
103    /// let config = PrivilegedPostgresConfig::new().host("localhost".to_owned());
104    /// ```
105    #[must_use]
106    pub fn host(self, value: String) -> Self {
107        Self {
108            host: value,
109            ..self
110        }
111    }
112
113    /// Sets a new port
114    /// # Example
115    /// ```
116    /// # use db_pool::PrivilegedPostgresConfig;
117    /// #
118    /// let config = PrivilegedPostgresConfig::new().port(5432);
119    /// ```
120    #[must_use]
121    pub fn port(self, value: u16) -> Self {
122        Self {
123            port: value,
124            ..self
125        }
126    }
127
128    pub(crate) fn default_connection_url(&self) -> String {
129        let Self {
130            username,
131            password,
132            host,
133            port,
134        } = self;
135        if let Some(password) = password {
136            format!("postgres://{username}:{password}@{host}:{port}")
137        } else {
138            format!("postgres://{username}@{host}:{port}")
139        }
140    }
141
142    pub(crate) fn privileged_database_connection_url(&self, db_name: &str) -> String {
143        let Self {
144            username,
145            password,
146            host,
147            port,
148        } = self;
149        if let Some(password) = password {
150            format!("postgres://{username}:{password}@{host}:{port}/{db_name}")
151        } else {
152            format!("postgres://{username}@{host}:{port}/{db_name}")
153        }
154    }
155
156    pub(crate) fn restricted_database_connection_url(
157        &self,
158        username: &str,
159        password: Option<&str>,
160        db_name: &str,
161    ) -> String {
162        let Self { host, port, .. } = self;
163        if let Some(password) = password {
164            format!("postgres://{username}:{password}@{host}:{port}/{db_name}")
165        } else {
166            format!("postgres://{username}@{host}:{port}/{db_name}")
167        }
168    }
169}
170
171#[derive(Debug)]
172pub enum Error {
173    InvalidPort(std::num::ParseIntError),
174}
175
176impl Default for PrivilegedPostgresConfig {
177    fn default() -> Self {
178        Self::new()
179    }
180}
181
182#[cfg(feature = "postgres")]
183impl From<PrivilegedPostgresConfig> for r2d2_postgres::postgres::Config {
184    fn from(value: PrivilegedPostgresConfig) -> Self {
185        let PrivilegedPostgresConfig {
186            username,
187            password,
188            host,
189            port,
190        } = value;
191
192        let mut config = Self::new();
193
194        config
195            .user(username.as_str())
196            .host(host.as_str())
197            .port(port);
198
199        if let Some(password) = password {
200            config.password(password.as_str());
201        }
202
203        config
204    }
205}
206
207#[cfg(feature = "sqlx-postgres")]
208impl From<PrivilegedPostgresConfig> for sqlx::postgres::PgConnectOptions {
209    fn from(value: PrivilegedPostgresConfig) -> Self {
210        let PrivilegedPostgresConfig {
211            username,
212            password,
213            host,
214            port,
215        } = value;
216
217        let opts = Self::new()
218            .username(username.as_str())
219            .host(host.as_str())
220            .port(port);
221
222        if let Some(password) = password {
223            opts.password(password.as_str())
224        } else {
225            opts
226        }
227    }
228}
229
230#[cfg(feature = "tokio-postgres")]
231impl From<PrivilegedPostgresConfig> for tokio_postgres::Config {
232    fn from(value: PrivilegedPostgresConfig) -> Self {
233        let PrivilegedPostgresConfig {
234            username,
235            password,
236            host,
237            port,
238        } = value;
239
240        let mut config = Self::new();
241
242        config
243            .user(username.as_str())
244            .host(host.as_str())
245            .port(port);
246
247        if let Some(password) = password {
248            config.password(password.as_str());
249        }
250
251        config
252    }
253}