Skip to main content

uls_db/
config.rs

1//! Database configuration.
2
3use std::path::PathBuf;
4use std::time::Duration;
5
6/// Database configuration options.
7#[derive(Debug, Clone)]
8pub struct DatabaseConfig {
9    /// Path to the SQLite database file.
10    pub path: PathBuf,
11
12    /// Maximum number of connections in the pool.
13    pub max_connections: u32,
14
15    /// Connection timeout.
16    pub connection_timeout: Duration,
17
18    /// Whether to create the database if it doesn't exist.
19    pub create_if_missing: bool,
20
21    /// Enable WAL mode for better concurrent read performance.
22    pub enable_wal: bool,
23
24    /// Cache size in pages (negative = KB).
25    pub cache_size: i32,
26
27    /// Enable foreign key constraints.
28    pub foreign_keys: bool,
29}
30
31impl Default for DatabaseConfig {
32    fn default() -> Self {
33        Self {
34            path: default_db_path(),
35            max_connections: 4,
36            connection_timeout: Duration::from_secs(30),
37            create_if_missing: true,
38            enable_wal: true,
39            cache_size: -64000, // 64MB
40            foreign_keys: true,
41        }
42    }
43}
44
45impl DatabaseConfig {
46    /// Create a config with a specific database path.
47    pub fn with_path(path: impl Into<PathBuf>) -> Self {
48        Self {
49            path: path.into(),
50            ..Default::default()
51        }
52    }
53
54    /// Create an in-memory database configuration (for testing).
55    pub fn in_memory() -> Self {
56        Self {
57            path: PathBuf::from(":memory:"),
58            max_connections: 1, // In-memory only works with single connection
59            create_if_missing: true,
60            enable_wal: false, // WAL not supported for in-memory
61            ..Default::default()
62        }
63    }
64
65    /// Set maximum connections.
66    pub fn with_max_connections(mut self, count: u32) -> Self {
67        self.max_connections = count;
68        self
69    }
70
71    /// Set cache size in megabytes.
72    pub fn with_cache_size_mb(mut self, mb: i32) -> Self {
73        self.cache_size = -mb * 1000;
74        self
75    }
76}
77
78/// Get the default database path.
79fn default_db_path() -> PathBuf {
80    dirs::data_local_dir()
81        .unwrap_or_else(|| PathBuf::from("."))
82        .join("uls")
83        .join("uls.db")
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_default_config() {
92        let config = DatabaseConfig::default();
93        assert!(config.enable_wal);
94        assert!(config.create_if_missing);
95        assert_eq!(config.max_connections, 4);
96    }
97
98    #[test]
99    fn test_in_memory_config() {
100        let config = DatabaseConfig::in_memory();
101        assert_eq!(config.path.to_str(), Some(":memory:"));
102        assert_eq!(config.max_connections, 1);
103        assert!(!config.enable_wal);
104    }
105
106    #[test]
107    fn test_builder_pattern() {
108        let config = DatabaseConfig::default()
109            .with_max_connections(8)
110            .with_cache_size_mb(128);
111
112        assert_eq!(config.max_connections, 8);
113        // Cache size is stored as negative KB, so 128MB = -128000
114        assert_eq!(config.cache_size, -128000);
115    }
116
117    #[test]
118    fn test_with_max_connections() {
119        let config = DatabaseConfig::in_memory().with_max_connections(16);
120        assert_eq!(config.max_connections, 16);
121    }
122
123    #[test]
124    fn test_with_cache_size_mb() {
125        let config = DatabaseConfig::in_memory().with_cache_size_mb(256);
126        // 256MB * 1000 = 256000 pages, stored as negative
127        assert_eq!(config.cache_size, -256000);
128    }
129}