web_server_abstraction/
database.rs1use std::collections::HashMap;
4
5#[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#[derive(Debug, Clone)]
16pub struct PoolStats {
17 pub total_connections: u32,
18 pub active_connections: u32,
19}
20
21#[derive(Debug, Clone, PartialEq)]
23pub enum DatabaseValue {
24 Text(String),
25 Integer(i64),
26 Real(f64),
27 Null,
28}
29
30#[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 pub fn get(&self, column: &str) -> Option<&DatabaseValue> {
45 self.columns.get(column)
46 }
47
48 pub fn set(&mut self, column: String, value: DatabaseValue) {
50 self.columns.insert(column, value);
51 }
52
53 pub fn contains_key(&self, column: &str) -> bool {
55 self.columns.contains_key(column)
56 }
57
58 pub fn keys(&self) -> impl Iterator<Item = &String> {
60 self.columns.keys()
61 }
62
63 pub fn len(&self) -> usize {
65 self.columns.len()
66 }
67
68 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
80pub struct MockDatabase;
82
83#[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
99pub trait ConnectionPool {
101 fn stats(&self) -> PoolStats;
102}
103
104pub trait DatabaseConnection {
106 fn execute(&mut self, query: &str) -> Result<u64, DatabaseError>;
107}
108
109pub 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
142pub struct Transaction;
144
145pub 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 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 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 assert!(row.contains_key("id"));
199 assert!(row.contains_key("name"));
200 assert!(!row.contains_key("missing"));
201
202 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}