Skip to main content

fraiseql_server/config/
loader.rs

1use std::{env, path::Path};
2
3use fraiseql_error::ConfigError;
4
5use crate::config::{RuntimeConfig, validation::ConfigValidator};
6
7impl RuntimeConfig {
8    /// Load configuration from file with full validation
9    pub fn from_file(path: impl AsRef<Path>) -> Result<Self, ConfigError> {
10        let path = path.as_ref();
11
12        let content = std::fs::read_to_string(path).map_err(|e| ConfigError::ReadError {
13            path:   path.to_path_buf(),
14            source: e,
15        })?;
16
17        let config: RuntimeConfig =
18            toml::from_str(&content).map_err(|e| ConfigError::ParseError { source: e })?;
19
20        // Run comprehensive validation
21        let validation = ConfigValidator::new(&config).validate();
22        let warnings = validation.into_result()?;
23
24        // Log warnings
25        for warning in warnings {
26            tracing::warn!("Configuration warning: {}", warning);
27        }
28
29        Ok(config)
30    }
31
32    /// Load configuration from default locations
33    pub fn load() -> Result<Self, ConfigError> {
34        // Check FRAISEQL_CONFIG environment variable
35        if let Ok(path) = env::var("FRAISEQL_CONFIG") {
36            return Self::from_file(&path);
37        }
38
39        // Check current directory
40        let local_config = Path::new("./fraiseql.toml");
41        if local_config.exists() {
42            return Self::from_file(local_config);
43        }
44
45        // Check user config directory
46        if let Some(config_dir) = dirs::config_dir() {
47            let user_config = config_dir.join("fraiseql/config.toml");
48            if user_config.exists() {
49                return Self::from_file(&user_config);
50            }
51        }
52
53        Err(ConfigError::NotFound)
54    }
55
56    /// Load configuration with optional file path (CLI argument)
57    pub fn load_with_path(path: Option<&Path>) -> Result<Self, ConfigError> {
58        match path {
59            Some(p) => Self::from_file(p),
60            None => Self::load(),
61        }
62    }
63
64    /// Validate configuration without loading env vars (for dry-run/testing)
65    pub fn validate_syntax(content: &str) -> Result<(), ConfigError> {
66        let _config: RuntimeConfig =
67            toml::from_str(content).map_err(|e| ConfigError::ParseError { source: e })?;
68        Ok(())
69    }
70}