web_server_abstraction/
database.rs

1//! Database integration helpers.
2
3use std::collections::HashMap;
4
5/// Simple database error for basic functionality
6#[derive(Debug, thiserror::Error)]
7pub enum DatabaseError {
8    #[error("Connection error: {0}")]
9    Connection(String),
10    #[error("Query error: {0}")]
11    Query(String),
12}
13
14/// Database pool stats for monitoring
15#[derive(Debug, Clone)]
16pub struct PoolStats {
17    pub total_connections: u32,
18    pub active_connections: u32,
19}
20
21/// Simple database value type
22#[derive(Debug, Clone, PartialEq)]
23pub enum DatabaseValue {
24    Text(String),
25    Integer(i64),
26    Real(f64),
27    Null,
28}
29
30/// Database row representation
31#[derive(Debug, Clone)]
32pub struct Row {
33    columns: HashMap<String, DatabaseValue>,
34}
35
36impl Row {
37    pub fn new() -> Self {
38        Self {
39            columns: HashMap::new(),
40        }
41    }
42
43    /// Get a value from the row by column name
44    pub fn get(&self, column: &str) -> Option<&DatabaseValue> {
45        self.columns.get(column)
46    }
47
48    /// Set a value in the row
49    pub fn set(&mut self, column: String, value: DatabaseValue) {
50        self.columns.insert(column, value);
51    }
52
53    /// Check if a column exists
54    pub fn contains_key(&self, column: &str) -> bool {
55        self.columns.contains_key(column)
56    }
57
58    /// Get all column names
59    pub fn keys(&self) -> impl Iterator<Item = &String> {
60        self.columns.keys()
61    }
62
63    /// Get the number of columns
64    pub fn len(&self) -> usize {
65        self.columns.len()
66    }
67
68    /// Check if the row is empty
69    pub fn is_empty(&self) -> bool {
70        self.columns.is_empty()
71    }
72}
73
74impl Default for Row {
75    fn default() -> Self {
76        Self::new()
77    }
78}
79
80/// Mock database for testing
81pub struct MockDatabase;
82
83/// Database configuration
84#[derive(Debug, Clone)]
85pub struct DatabaseConfig {
86    pub url: String,
87    pub max_connections: u32,
88}
89
90impl Default for DatabaseConfig {
91    fn default() -> Self {
92        Self {
93            url: "sqlite://memory".to_string(),
94            max_connections: 10,
95        }
96    }
97}
98
99/// Connection pool trait
100pub trait ConnectionPool {
101    fn stats(&self) -> PoolStats;
102}
103
104/// Database connection trait
105pub trait DatabaseConnection {
106    fn execute(&mut self, query: &str) -> Result<u64, DatabaseError>;
107}
108
109/// Query builder for dynamic queries
110pub struct QueryBuilder {
111    query: String,
112}
113
114impl QueryBuilder {
115    pub fn new() -> Self {
116        Self {
117            query: String::new(),
118        }
119    }
120
121    pub fn select(mut self, columns: &str) -> Self {
122        self.query = format!("SELECT {}", columns);
123        self
124    }
125
126    pub fn from(mut self, table: &str) -> Self {
127        self.query.push_str(&format!(" FROM {}", table));
128        self
129    }
130
131    pub fn build(self) -> String {
132        self.query
133    }
134}
135
136impl Default for QueryBuilder {
137    fn default() -> Self {
138        Self::new()
139    }
140}
141
142/// Transaction handle
143pub struct Transaction;
144
145/// Database value conversion trait
146pub trait FromDatabaseValue {
147    fn from_database_value(value: &DatabaseValue) -> Option<Self>
148    where
149        Self: Sized;
150}
151
152impl FromDatabaseValue for String {
153    fn from_database_value(value: &DatabaseValue) -> Option<Self> {
154        match value {
155            DatabaseValue::Text(s) => Some(s.clone()),
156            _ => None,
157        }
158    }
159}
160
161impl FromDatabaseValue for i64 {
162    fn from_database_value(value: &DatabaseValue) -> Option<Self> {
163        match value {
164            DatabaseValue::Integer(i) => Some(*i),
165            _ => None,
166        }
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    use super::*;
173
174    #[test]
175    fn test_database_row_operations() {
176        let mut row = Row::new();
177        assert!(row.is_empty());
178        assert_eq!(row.len(), 0);
179
180        // Test setting values
181        row.set("id".to_string(), DatabaseValue::Integer(42));
182        row.set("name".to_string(), DatabaseValue::Text("Alice".to_string()));
183        row.set("score".to_string(), DatabaseValue::Real(95.5));
184
185        assert!(!row.is_empty());
186        assert_eq!(row.len(), 3);
187
188        // Test getting values
189        assert_eq!(row.get("id"), Some(&DatabaseValue::Integer(42)));
190        assert_eq!(
191            row.get("name"),
192            Some(&DatabaseValue::Text("Alice".to_string()))
193        );
194        assert_eq!(row.get("score"), Some(&DatabaseValue::Real(95.5)));
195        assert_eq!(row.get("missing"), None);
196
197        // Test contains_key
198        assert!(row.contains_key("id"));
199        assert!(row.contains_key("name"));
200        assert!(!row.contains_key("missing"));
201
202        // Test keys iteration
203        let keys: Vec<&String> = row.keys().collect();
204        assert_eq!(keys.len(), 3);
205        assert!(keys.contains(&&"id".to_string()));
206        assert!(keys.contains(&&"name".to_string()));
207        assert!(keys.contains(&&"score".to_string()));
208    }
209}