Skip to main content

ferro_rs/config/
mod.rs

1//! Configuration module for Ferro framework
2//!
3//! This module provides Laravel-like configuration management including:
4//! - Automatic `.env` file loading with environment-based precedence
5//! - Type-safe configuration structs
6//! - Simple API for accessing config values
7//!
8//! # Example
9//!
10//! ```rust,ignore
11//! use ferro_rs::{Config, ServerConfig};
12//!
13//! // Initialize config (loads .env files)
14//! Config::init(std::path::Path::new("."));
15//!
16//! // Get typed config
17//! let server = Config::get::<ServerConfig>().unwrap();
18//! println!("Server port: {}", server.port);
19//! ```
20
21pub mod env;
22pub mod providers;
23pub mod repository;
24
25pub use env::{env, env_optional, env_required, load_dotenv, Environment};
26pub use providers::{
27    AppConfig, AppConfigBuilder, LangConfig, LangConfigBuilder, ServerConfig, ServerConfigBuilder,
28};
29
30use std::path::Path;
31
32/// Main Config facade for accessing configuration
33///
34/// The Config struct provides a centralized way to initialize and access
35/// application configuration. It follows the Laravel pattern of type-safe
36/// configuration with environment variable support.
37pub struct Config;
38
39impl Config {
40    /// Initialize the configuration system
41    ///
42    /// This should be called at application startup, before creating the server.
43    /// It loads environment variables from `.env` files and registers default configs.
44    ///
45    /// # Arguments
46    ///
47    /// * `project_root` - Path to the project root where `.env` files are located
48    ///
49    /// # Returns
50    ///
51    /// The detected environment (Local, Development, Production, etc.)
52    ///
53    /// # Example
54    ///
55    /// ```rust,no_run
56    /// use ferro_rs::Config;
57    ///
58    /// let env = Config::init(std::path::Path::new("."));
59    /// println!("Running in {} environment", env);
60    /// ```
61    pub fn init(project_root: &Path) -> Environment {
62        let env = env::load_dotenv(project_root);
63
64        // Register default configs
65        repository::register(AppConfig::from_env());
66        repository::register(ServerConfig::from_env());
67        repository::register(LangConfig::from_env());
68
69        env
70    }
71
72    /// Get a typed config struct from the repository
73    ///
74    /// # Example
75    ///
76    /// ```rust,no_run
77    /// use ferro_rs::{Config, ServerConfig};
78    ///
79    /// let server_config = Config::get::<ServerConfig>().unwrap();
80    /// println!("Port: {}", server_config.port);
81    /// ```
82    pub fn get<T: std::any::Any + Send + Sync + Clone + 'static>() -> Option<T> {
83        repository::get::<T>()
84    }
85
86    /// Register a custom config struct
87    ///
88    /// Use this to register your own configuration structs that can be
89    /// retrieved later with `Config::get::<T>()`.
90    ///
91    /// # Example
92    ///
93    /// ```rust,no_run
94    /// use ferro_rs::Config;
95    ///
96    /// #[derive(Clone)]
97    /// struct DatabaseConfig {
98    ///     host: String,
99    ///     port: u16,
100    /// }
101    ///
102    /// Config::register(DatabaseConfig {
103    ///     host: "localhost".to_string(),
104    ///     port: 5432,
105    /// });
106    /// ```
107    pub fn register<T: std::any::Any + Send + Sync + 'static>(config: T) {
108        repository::register(config);
109    }
110
111    /// Check if a config type is registered
112    pub fn has<T: std::any::Any + 'static>() -> bool {
113        repository::has::<T>()
114    }
115
116    /// Get the current environment
117    ///
118    /// Returns the environment from AppConfig if initialized,
119    /// otherwise detects from the APP_ENV environment variable.
120    pub fn environment() -> Environment {
121        Config::get::<AppConfig>()
122            .map(|c| c.environment)
123            .unwrap_or_else(Environment::detect)
124    }
125
126    /// Check if running in production environment
127    pub fn is_production() -> bool {
128        Self::environment().is_production()
129    }
130
131    /// Check if running in development environment (local or development)
132    pub fn is_development() -> bool {
133        Self::environment().is_development()
134    }
135
136    /// Check if debug mode is enabled
137    pub fn is_debug() -> bool {
138        Config::get::<AppConfig>().map(|c| c.debug).unwrap_or(true)
139    }
140}