use serde::{Deserialize, Serialize};
fn default_schema() -> String {
"public".to_string()
}
fn default_pool_size() -> u32 {
2
}
fn default_connect_timeout() -> u64 {
5
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", default)]
pub struct DatabaseSettings {
pub url: Option<String>,
pub url_env: Option<String>,
#[serde(default = "default_schema")]
pub schema: String,
#[serde(default = "default_pool_size")]
pub pool_size: u32,
#[serde(default = "default_connect_timeout")]
pub connect_timeout_secs: u64,
}
impl Default for DatabaseSettings {
fn default() -> Self {
Self {
url: None,
url_env: None,
schema: default_schema(),
pool_size: default_pool_size(),
connect_timeout_secs: default_connect_timeout(),
}
}
}
impl DatabaseSettings {
#[must_use]
pub fn resolve_url(&self) -> Option<String> {
if let Some(var) = &self.url_env
&& let Ok(val) = std::env::var(var)
&& !val.is_empty()
{
return Some(val);
}
self.url.clone().filter(|u| !u.is_empty())
}
#[must_use]
pub fn is_configured(&self) -> bool {
self.resolve_url().is_some()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_have_no_connection() {
let db = DatabaseSettings::default();
assert_eq!(db.schema, "public");
assert!(!db.is_configured());
assert!(db.resolve_url().is_none());
}
#[test]
fn inline_url_resolves() {
let db = DatabaseSettings {
url: Some("postgres://localhost/x".into()),
..Default::default()
};
assert_eq!(db.resolve_url().as_deref(), Some("postgres://localhost/x"));
}
#[test]
fn env_takes_precedence() {
let var = "BANSHEE_TEST_DB_URL_PRECEDENCE";
unsafe {
std::env::set_var(var, "postgres://env/db");
}
let db = DatabaseSettings {
url: Some("postgres://inline/db".into()),
url_env: Some(var.into()),
..Default::default()
};
assert_eq!(db.resolve_url().as_deref(), Some("postgres://env/db"));
unsafe {
std::env::remove_var(var);
}
}
}