Skip to main content

rskit_database/
config.rs

1//! Database configuration types.
2
3use std::time::Duration;
4
5use rskit_validation::Validate;
6use serde::{Deserialize, Deserializer, Serialize};
7use validator::ValidationErrors;
8
9/// Config-driven database backend selection.
10#[derive(Debug, Clone, Deserialize, Serialize)]
11pub struct DatabaseConfig {
12    /// Backend name looked up in an injected [`crate::DatabaseRegistry`].
13    #[serde(default = "default_backend")]
14    pub backend: String,
15    /// In-memory backend options.
16    #[serde(default)]
17    pub memory: MemoryDatabaseConfig,
18    /// Maximum number of logical connections in the selected backend.
19    #[serde(default = "default_max_connections")]
20    pub max_connections: u32,
21    /// Minimum number of idle logical connections to maintain.
22    #[serde(default = "default_min_connections")]
23    pub min_connections: u32,
24    /// Timeout for establishing a backend connection.
25    #[serde(
26        default = "default_connect_timeout",
27        deserialize_with = "deserialize_duration_secs"
28    )]
29    pub connect_timeout: Duration,
30    /// Queries slower than this threshold are reported by backends that support slow-query logging.
31    #[serde(
32        default = "default_slow_query_threshold",
33        deserialize_with = "deserialize_duration_secs"
34    )]
35    pub slow_query_threshold: Duration,
36}
37
38impl Validate for DatabaseConfig {
39    fn validate(&self) -> Result<(), ValidationErrors> {
40        self.memory.validate()
41    }
42}
43
44impl Default for DatabaseConfig {
45    fn default() -> Self {
46        Self {
47            backend: default_backend(),
48            memory: MemoryDatabaseConfig::default(),
49            max_connections: default_max_connections(),
50            min_connections: default_min_connections(),
51            connect_timeout: default_connect_timeout(),
52            slow_query_threshold: default_slow_query_threshold(),
53        }
54    }
55}
56
57/// In-memory database backend configuration.
58#[derive(Debug, Clone, Deserialize, Serialize)]
59pub struct MemoryDatabaseConfig {
60    /// Logical database name used for diagnostics.
61    #[serde(default = "default_memory_name")]
62    pub name: String,
63    /// Maximum number of recorded statements kept for diagnostics. `0` disables recording.
64    #[serde(default = "default_statement_history")]
65    pub statement_history: usize,
66}
67
68impl Validate for MemoryDatabaseConfig {
69    fn validate(&self) -> Result<(), ValidationErrors> {
70        Ok(())
71    }
72}
73
74impl Default for MemoryDatabaseConfig {
75    fn default() -> Self {
76        Self {
77            name: default_memory_name(),
78            statement_history: default_statement_history(),
79        }
80    }
81}
82
83fn default_backend() -> String {
84    "memory".to_owned()
85}
86
87fn default_memory_name() -> String {
88    "default".to_owned()
89}
90
91fn default_statement_history() -> usize {
92    256
93}
94
95fn default_max_connections() -> u32 {
96    10
97}
98
99fn default_min_connections() -> u32 {
100    1
101}
102
103fn default_connect_timeout() -> Duration {
104    Duration::from_secs(30)
105}
106
107fn default_slow_query_threshold() -> Duration {
108    Duration::from_secs(1)
109}
110
111fn deserialize_duration_secs<'de, D>(deserializer: D) -> Result<Duration, D::Error>
112where
113    D: Deserializer<'de>,
114{
115    let secs = u64::deserialize(deserializer)?;
116    Ok(Duration::from_secs(secs))
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn default_config_selects_memory() {
125        let cfg = DatabaseConfig::default();
126
127        assert_eq!(cfg.backend, "memory");
128        assert_eq!(cfg.memory.name, "default");
129        assert_eq!(cfg.memory.statement_history, 256);
130        assert_eq!(cfg.max_connections, 10);
131        assert_eq!(cfg.min_connections, 1);
132        assert_eq!(cfg.connect_timeout, Duration::from_secs(30));
133        assert_eq!(cfg.slow_query_threshold, Duration::from_secs(1));
134    }
135
136    #[test]
137    fn deserialize_config_from_json() {
138        let json = r#"{
139            "backend": "memory",
140            "memory": {"name": "testdb", "statement_history": 32}
141        }"#;
142        let cfg: DatabaseConfig = serde_json::from_str(json).unwrap();
143
144        assert_eq!(cfg.backend, "memory");
145        assert_eq!(cfg.memory.name, "testdb");
146        assert_eq!(cfg.memory.statement_history, 32);
147    }
148}