use clap::Parser; use serde::{Deserialize, Serialize}; use url::Url; use crate::WardenError; #[derive(Parser, Clone, Deserialize, Serialize, Debug)] #[serde(rename_all = "kebab-case")] pub struct Database { /// Full database URL (if provided, overrides individual components) #[arg(long, env = "DATABASE_URL")] pub database_url: Option, #[arg(long, env = "DB_USER")] /// Database username #[serde(rename = "username")] pub database_username: Option, /// Database password #[arg(long, env = "DB_PASSWORD")] #[serde(rename = "password")] pub database_password: Option, /// Database host #[arg(long, env = "DB_HOST", default_value = "localhost")] #[serde(rename = "host")] pub database_host: Option, /// Database port #[arg(long, env = "DB_PORT")] #[serde(rename = "port")] pub database_port: Option, /// Database name #[arg(long, env = "DB_NAME")] #[serde(rename = "name")] pub database_name: Option, /// Database pool size #[arg(long, env = "DATABASE_POOL_SIZE", default_value = "10")] #[serde(rename = "pool-size")] pub database_pool_size: Option, } impl Default for Database { fn default() -> Self { Self { database_url: Default::default(), database_username: Some(String::from("postgres")), database_password: Some(String::from("password")), database_host: Some(String::from("localhost")), database_port: Some(5432), database_name: Some(String::from("warden")), database_pool_size: Some(10), } } } impl Database { pub fn merge(cli: &Self, file: &Self) -> Result { let url = cli.database_url.clone().or(file.database_url.clone()); let pool_size = cli .database_pool_size .or(file.database_pool_size) .unwrap_or(10); let final_url = match url { Some(u) => u, None => { let host = cli .database_host .clone() .or(file.database_host.clone()) .unwrap_or_else(|| "localhost".to_string()); let mut u = Url::parse(&format!("postgresql://{}", host))?; let user = cli .database_username .as_ref() .or(file.database_username.as_ref()); let pass = cli .database_password .as_ref() .or(file.database_password.as_ref()); let port = cli.database_port.or(file.database_port); let name = cli.database_name.as_ref().or(file.database_name.as_ref()); if let Some(user) = user { u.set_username(user).ok(); } if let Some(pass) = pass { u.set_password(Some(pass)).ok(); } if let Some(port) = port { u.set_port(Some(port)).ok(); } if let Some(name) = name { u.set_path(name); } u } }; Ok(Self { database_url: Some(final_url), database_pool_size: Some(pool_size), ..cli.clone() }) } pub fn get_url(&self) -> Result { if let Some(ref url) = self.database_url { return Ok(url.clone()); } let host = "localhost".to_owned(); let host = self.database_host.as_ref().unwrap_or_else(|| &host); let mut url = Url::parse(&format!("postgres://{host}"))?; if let Some(ref u) = self.database_username { url.set_username(u).ok(); } if let Some(ref p) = self.database_password { url.set_password(Some(p)).ok(); } url.set_port(self.database_port).ok(); if let Some(ref name) = self.database_name { url.set_path(name); } Ok(url) } }