1use ferrox_errors::AppError;
2use figment::{
3 providers::{Env, Format, Toml},
4 Figment,
5};
6use serde::Deserialize;
7use tracing::info;
8
9pub fn load_config<'a, T: Deserialize<'a>>(env_prefix: &str) -> Result<T, AppError> {
12 let environment = std::env::var("FERROX_ENV").unwrap_or_else(|_| "development".into());
13
14 let config: T = Figment::new()
15 .merge(Toml::file("config/default.toml"))
16 .merge(Toml::file(format!("config/{}.toml", environment)))
17 .merge(Env::prefixed(env_prefix))
18 .extract()
19 .map_err(|e| AppError::InternalServerError(Box::new(e)))?;
20
21 info!("Loaded strongly-typed configuration for environment: {}", environment);
22
23 Ok(config)
24}
25
26#[cfg(test)]
27mod tests {
28 use super::*;
29 use serde::Deserialize;
30
31 #[derive(Deserialize, Debug, PartialEq)]
32 struct TestConfig {
33 host: String,
34 port: u16,
35 }
36
37 #[test]
38 fn test_load_config_env_override() {
39 std::env::set_var("APP_HOST", "127.0.0.1");
41 std::env::set_var("APP_PORT", "8080");
42
43 let config: Result<TestConfig, _> = load_config("APP_");
44 assert!(config.is_ok());
45
46 let config = config.unwrap();
47 assert_eq!(config.host, "127.0.0.1");
48 assert_eq!(config.port, 8080);
49 }
50}