Skip to main content

ferro_rs/database/
config.rs

1//! Database configuration for Ferro framework
2
3use crate::config::{env, env_optional};
4
5/// Database type enumeration
6#[derive(Debug, Clone, PartialEq)]
7pub enum DatabaseType {
8    Postgres,
9    Sqlite,
10    Unknown,
11}
12
13/// Database configuration
14///
15/// # Environment Variables
16///
17/// - `DATABASE_URL` - Full connection URL (required for connection, defaults to sqlite://./database.db)
18/// - `DB_MAX_CONNECTIONS` - Maximum pool connections (default: 10)
19/// - `DB_MIN_CONNECTIONS` - Minimum pool connections (default: 1)
20/// - `DB_CONNECT_TIMEOUT` - Connection timeout in seconds (default: 30)
21/// - `DB_LOGGING` - Enable SQL logging (default: false)
22///
23/// # Example
24///
25/// ```rust,ignore
26/// use ferro_rs::{Config, DatabaseConfig};
27///
28/// // Register from environment
29/// Config::register(DatabaseConfig::from_env());
30///
31/// // Or build manually
32/// Config::register(DatabaseConfig::builder()
33///     .url("postgres://localhost/mydb")
34///     .max_connections(20)
35///     .build());
36/// ```
37#[derive(Debug, Clone)]
38pub struct DatabaseConfig {
39    /// Full database connection URL
40    pub url: String,
41    /// Maximum connections in pool
42    pub max_connections: u32,
43    /// Minimum connections in pool
44    pub min_connections: u32,
45    /// Connection timeout in seconds
46    pub connect_timeout: u64,
47    /// Enable SQL query logging
48    pub logging: bool,
49}
50
51impl DatabaseConfig {
52    /// Create configuration from environment variables
53    pub fn from_env() -> Self {
54        Self {
55            url: env_optional("DATABASE_URL")
56                .unwrap_or_else(|| "sqlite://./database.db".to_string()),
57            max_connections: env("DB_MAX_CONNECTIONS", 10),
58            min_connections: env("DB_MIN_CONNECTIONS", 1),
59            connect_timeout: env("DB_CONNECT_TIMEOUT", 30),
60            logging: env("DB_LOGGING", false),
61        }
62    }
63
64    /// Create a builder for manual configuration
65    pub fn builder() -> DatabaseConfigBuilder {
66        DatabaseConfigBuilder::default()
67    }
68
69    /// Detect database type from URL
70    pub fn database_type(&self) -> DatabaseType {
71        if self.url.starts_with("postgres://") || self.url.starts_with("postgresql://") {
72            DatabaseType::Postgres
73        } else if self.url.starts_with("sqlite://") || self.url.starts_with("sqlite:") {
74            DatabaseType::Sqlite
75        } else {
76            DatabaseType::Unknown
77        }
78    }
79
80    /// Check if database URL is configured (not the default)
81    pub fn is_configured(&self) -> bool {
82        self.url != "sqlite://./database.db"
83    }
84}
85
86impl Default for DatabaseConfig {
87    fn default() -> Self {
88        Self::from_env()
89    }
90}
91
92/// Builder for DatabaseConfig
93#[derive(Debug, Default)]
94pub struct DatabaseConfigBuilder {
95    url: Option<String>,
96    max_connections: Option<u32>,
97    min_connections: Option<u32>,
98    connect_timeout: Option<u64>,
99    logging: Option<bool>,
100}
101
102impl DatabaseConfigBuilder {
103    /// Set the database URL
104    pub fn url(mut self, url: impl Into<String>) -> Self {
105        self.url = Some(url.into());
106        self
107    }
108
109    /// Set maximum pool connections
110    pub fn max_connections(mut self, count: u32) -> Self {
111        self.max_connections = Some(count);
112        self
113    }
114
115    /// Set minimum pool connections
116    pub fn min_connections(mut self, count: u32) -> Self {
117        self.min_connections = Some(count);
118        self
119    }
120
121    /// Set connection timeout in seconds
122    pub fn connect_timeout(mut self, seconds: u64) -> Self {
123        self.connect_timeout = Some(seconds);
124        self
125    }
126
127    /// Enable or disable SQL logging
128    pub fn logging(mut self, enabled: bool) -> Self {
129        self.logging = Some(enabled);
130        self
131    }
132
133    /// Build the configuration
134    pub fn build(self) -> DatabaseConfig {
135        let defaults = DatabaseConfig::from_env();
136        DatabaseConfig {
137            url: self.url.unwrap_or(defaults.url),
138            max_connections: self.max_connections.unwrap_or(defaults.max_connections),
139            min_connections: self.min_connections.unwrap_or(defaults.min_connections),
140            connect_timeout: self.connect_timeout.unwrap_or(defaults.connect_timeout),
141            logging: self.logging.unwrap_or(defaults.logging),
142        }
143    }
144}