1use crate::environment::Environment;
9use serde::Deserialize;
10
11pub use doido_core::logger::LoggerConfig;
15
16#[derive(Debug, Clone, Deserialize)]
18pub struct DatabaseConfig {
19 pub url: String,
22}
23
24impl Default for DatabaseConfig {
25 fn default() -> Self {
26 Self {
27 url: "sqlite://db/development.db".to_string(),
28 }
29 }
30}
31
32pub trait Config: Send + Sync {
35 fn database(&self) -> &DatabaseConfig;
37 fn logger(&self) -> &LoggerConfig;
39}
40
41#[derive(Debug, Clone, Default, Deserialize)]
44pub struct YamlConfig {
45 #[serde(default)]
46 pub database: DatabaseConfig,
47 #[serde(default)]
48 pub logger: LoggerConfig,
49}
50
51impl Config for YamlConfig {
52 fn database(&self) -> &DatabaseConfig {
53 &self.database
54 }
55
56 fn logger(&self) -> &LoggerConfig {
57 &self.logger
58 }
59}
60
61impl YamlConfig {
62 pub fn load() -> std::io::Result<Self> {
64 Self::load_env(Environment::get_env())
65 }
66
67 pub fn load_env(env: Environment) -> std::io::Result<Self> {
69 let path = format!("config/{}.yml", env.as_str());
70 let contents = std::fs::read_to_string(&path)?;
71 Self::from_yaml(&contents)
72 }
73
74 pub fn from_yaml(yaml: &str) -> std::io::Result<Self> {
76 serde_norway::from_str(yaml)
77 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
78 }
79}
80
81pub fn load() -> Box<dyn Config> {
84 Box::new(YamlConfig::load().unwrap_or_default())
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn parses_database_url_and_ignores_other_sections() {
93 let yaml = "server:\n bind: 0.0.0.0\n port: 3000\ndatabase:\n url: postgres://localhost/app_development\n";
94 let config = YamlConfig::from_yaml(yaml).unwrap();
95 assert_eq!(
96 config.database().url,
97 "postgres://localhost/app_development"
98 );
99 }
100
101 #[test]
102 fn defaults_when_database_section_absent() {
103 let config = YamlConfig::from_yaml("server:\n port: 3000\n").unwrap();
104 assert_eq!(config.database().url, "sqlite://db/development.db");
105 }
106}