use crate::ConfigError;
use sea_orm::ConnectOptions;
use secrecy::{ExposeSecret, SecretString};
use serde_aux::field_attributes::deserialize_number_from_string;
#[derive(serde::Deserialize, Clone)]
pub struct Settings {
pub application: AppSettings,
pub database: DatabaseSettings,
}
#[derive(serde::Deserialize, Clone)]
pub struct AppSettings {
pub host: String,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub port: u16,
}
#[derive(serde::Deserialize, Clone)]
pub struct DatabaseSettings {
pub dbms: String,
pub user: String,
pub password: SecretString,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub port: u16,
pub host: String,
pub database_name: String,
}
impl DatabaseSettings {
pub fn get_connect_options(&self) -> ConnectOptions {
ConnectOptions::new(format!(
"{}://{}:{}@{}:{}/{}", &self.dbms,
&self.user,
&self.password.expose_secret(),
&self.host,
&self.port,
&self.database_name
))
}
}
pub fn get_configuration() -> Result<Settings, ConfigError> {
let base_path = std::env::current_dir().expect("Failed to determine the current directory");
let config_dir = std::env::var("MOLTEN_CONFIG_DIR").unwrap_or_else(|_| "config".to_string());
let config_dir = base_path.join(config_dir);
let settings = config::Config::builder()
.add_source(config::File::from(config_dir.join("app")).required(true))
.add_source(
config::Environment::with_prefix("molten")
.prefix_separator("_")
.separator("__"),
)
.build()?
.try_deserialize()?;
Ok(settings)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::TempDir;
fn setup_config_dir() -> TempDir {
let tmp = TempDir::new().unwrap();
let config_dir = tmp.path();
fs::write(
config_dir.join("app.yaml"),
r#"
application:
host: 127.0.0.1
port: 8000
database:
dbms: "postgres"
host: "localhost"
port: 5432
user: "molten_user"
password: "molten_password"
database_name: "molten_db"
"#,
)
.unwrap();
tmp
}
#[test]
fn loads_settings_from_custom_config_dir() {
let config_dir = setup_config_dir();
temp_env::with_var("MOLTEN_CONFIG_DIR", Some(config_dir.path()), || {
let settings = get_configuration().unwrap();
assert_eq!(settings.application.port, 8000);
});
}
#[test]
fn overwrite_config_setting_with_env_var() {
let config_dir = setup_config_dir();
temp_env::with_vars(
[
(
"MOLTEN_CONFIG_DIR",
Some(config_dir.path().to_str().unwrap()),
),
("MOLTEN_APPLICATION__PORT", Some("1234")),
],
|| {
let settings = get_configuration().unwrap();
assert_eq!(settings.application.port, 1234);
},
)
}
}