Skip to main content

aurora_db/
types.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::cmp::Ordering;
4use std::collections::HashMap;
5use std::fmt;
6use std::hash::{Hash, Hasher};
7use std::path::PathBuf;
8use uuid::Uuid;
9
10/// Validation constraint stored on a field definition.
11/// Applied during insert/update to enforce data integrity.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub enum FieldValidationConstraint {
14    Format(String),
15    Min(f64),
16    Max(f64),
17    MinLength(i64),
18    MaxLength(i64),
19    Pattern(String),
20}
21
22impl PartialEq for FieldValidationConstraint {
23    fn eq(&self, other: &Self) -> bool {
24        match (self, other) {
25            (Self::Format(a), Self::Format(b)) | (Self::Pattern(a), Self::Pattern(b)) => a == b,
26            (Self::Min(a), Self::Min(b)) | (Self::Max(a), Self::Max(b)) => {
27                a.to_bits() == b.to_bits()
28            }
29            (Self::MinLength(a), Self::MinLength(b)) | (Self::MaxLength(a), Self::MaxLength(b)) => {
30                a == b
31            }
32            _ => false,
33        }
34    }
35}
36
37impl Eq for FieldValidationConstraint {}
38
39impl Hash for FieldValidationConstraint {
40    fn hash<H: Hasher>(&self, state: &mut H) {
41        std::mem::discriminant(self).hash(state);
42        match self {
43            Self::Format(s) | Self::Pattern(s) => s.hash(state),
44            Self::Min(f) | Self::Max(f) => f.to_bits().hash(state),
45            Self::MinLength(i) | Self::MaxLength(i) => i.hash(state),
46        }
47    }
48}
49
50#[derive(
51    Debug,
52    Clone,
53    Serialize,
54    Deserialize,
55    PartialEq,
56    Eq,
57    PartialOrd,
58    Ord,
59    Hash,
60)]
61pub enum ScalarType {
62    String,
63    Int,
64    Uuid,
65    Bool,
66    Float,
67    Object,
68    Array,
69    Any,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
73pub enum FieldType {
74    Scalar(ScalarType),
75    Object,
76    Array(ScalarType),
77    Nested(Box<HashMap<String, FieldDefinition>>),
78    Any,
79}
80
81impl Hash for FieldType {
82    fn hash<H: Hasher>(&self, state: &mut H) {
83        std::mem::discriminant(self).hash(state);
84        match self {
85            FieldType::Scalar(s) => s.hash(state),
86            FieldType::Array(s) => s.hash(state),
87            FieldType::Nested(m) => {
88                let mut keys: Vec<_> = m.keys().collect();
89                keys.sort();
90                for k in keys {
91                    k.hash(state);
92                    m.get(k).unwrap().hash(state);
93                }
94            }
95            _ => {}
96        }
97    }
98}
99
100impl fmt::Display for ScalarType {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        match self {
103            ScalarType::String => write!(f, "String"),
104            ScalarType::Int => write!(f, "Int"),
105            ScalarType::Uuid => write!(f, "Uuid"),
106            ScalarType::Bool => write!(f, "Bool"),
107            ScalarType::Float => write!(f, "Float"),
108            ScalarType::Object => write!(f, "Object"),
109            ScalarType::Array => write!(f, "Array"),
110            ScalarType::Any => write!(f, "Any"),
111        }
112    }
113}
114
115impl fmt::Display for FieldType {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        match self {
118            FieldType::Scalar(s) => write!(f, "{}", s),
119            FieldType::Object => write!(f, "Object"),
120            FieldType::Array(s) => write!(f, "Array<{}>", s),
121            FieldType::Nested(_) => write!(f, "Nested"),
122            FieldType::Any => write!(f, "Any"),
123        }
124    }
125}
126
127impl fmt::Display for FieldDefinition {
128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129        write!(
130            f,
131            "{}{} (indexed: {}, unique: {})",
132            self.field_type,
133            if self.nullable { "?" } else { "!" },
134            self.indexed,
135            self.unique,
136        )
137    }
138}
139
140impl fmt::Display for Collection {
141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142        write!(f, "{}", serde_json::to_string_pretty(self).unwrap_or_default())
143    }
144}
145
146impl fmt::Display for DurabilityMode {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        match self {
149            DurabilityMode::None => write!(f, "None"),
150            DurabilityMode::WAL => write!(f, "WAL"),
151            DurabilityMode::Strict => write!(f, "Strict"),
152            DurabilityMode::Synchronous => write!(f, "Synchronous"),
153        }
154    }
155}
156
157impl fmt::Display for ColdStoreMode {
158    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159        match self {
160            ColdStoreMode::HighThroughput => write!(f, "HighThroughput"),
161            ColdStoreMode::LowSpace => write!(f, "LowSpace"),
162        }
163    }
164}
165
166impl fmt::Display for AuroraConfig {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        write!(f, "{}", serde_json::to_string_pretty(self).unwrap_or_default())
169    }
170}
171
172impl Default for FieldType {
173    fn default() -> Self {
174        FieldType::Any
175    }
176}
177
178impl FieldType {
179    pub const SCALAR_STRING: FieldType = FieldType::Scalar(ScalarType::String);
180    pub const SCALAR_INT: FieldType = FieldType::Scalar(ScalarType::Int);
181    pub const SCALAR_BOOL: FieldType = FieldType::Scalar(ScalarType::Bool);
182    pub const SCALAR_FLOAT: FieldType = FieldType::Scalar(ScalarType::Float);
183    pub const SCALAR_UUID: FieldType = FieldType::Scalar(ScalarType::Uuid);
184    pub const SCALAR_OBJECT: FieldType = FieldType::Scalar(ScalarType::Object);
185    pub const SCALAR_ARRAY: FieldType = FieldType::Scalar(ScalarType::Array);
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Default)]
189pub struct FieldDefinition {
190    pub field_type: FieldType,
191    pub unique: bool,
192    pub indexed: bool,
193    pub nullable: bool,
194    /// Validation constraints applied on insert/update.
195    #[serde(default)]
196    pub validations: Vec<FieldValidationConstraint>,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct Collection {
201    pub name: String,
202    pub fields: HashMap<String, FieldDefinition>,
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
206pub struct Document {
207    pub id: String,
208    pub data: HashMap<String, Value>,
209}
210
211impl Document {
212    pub fn new() -> Self {
213        Self {
214            id: Uuid::new_v4().to_string(),
215            data: HashMap::new(),
216        }
217    }
218}
219
220impl fmt::Display for Document {
221    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222        write!(f, "{}", serde_json::to_string_pretty(self).unwrap_or_default())
223    }
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
227#[serde(untagged)]
228pub enum Value {
229    Null,
230    Bool(bool),
231    Int(i64),
232    Float(f64),
233    String(String),
234    Uuid(Uuid),
235    DateTime(DateTime<Utc>),
236    Array(Vec<Value>),
237    Object(HashMap<String, Value>),
238}
239
240impl Eq for Value {}
241
242impl PartialOrd for Value {
243    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
244        Some(self.cmp(other))
245    }
246}
247
248impl Ord for Value {
249    fn cmp(&self, other: &Self) -> Ordering {
250        match (self, other) {
251            (Value::Null, Value::Null) => Ordering::Equal,
252            (Value::Null, _) => Ordering::Less,
253            (_, Value::Null) => Ordering::Greater,
254            
255            (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
256            (Value::Bool(_), _) => Ordering::Less,
257            (_, Value::Bool(_)) => Ordering::Greater,
258
259            (Value::Int(a), Value::Int(b)) => a.cmp(b),
260            (Value::Int(_), _) => Ordering::Less,
261            (_, Value::Int(_)) => Ordering::Greater,
262
263            (Value::Float(a), Value::Float(b)) => a.total_cmp(b),
264            (Value::Float(_), _) => Ordering::Less,
265            (_, Value::Float(_)) => Ordering::Greater,
266
267            (Value::String(a), Value::String(b)) => a.cmp(b),
268            (Value::String(_), _) => Ordering::Less,
269            (_, Value::String(_)) => Ordering::Greater,
270            
271            (Value::Uuid(a), Value::Uuid(b)) => a.cmp(b),
272            (Value::Uuid(_), _) => Ordering::Less,
273            (_, Value::Uuid(_)) => Ordering::Greater,
274            
275            (Value::DateTime(a), Value::DateTime(b)) => a.cmp(b),
276            (Value::DateTime(_), _) => Ordering::Less,
277            (_, Value::DateTime(_)) => Ordering::Greater,
278
279            (Value::Array(a), Value::Array(b)) => a.cmp(b),
280            (Value::Array(_), _) => Ordering::Less,
281            (_, Value::Array(_)) => Ordering::Greater,
282
283            (Value::Object(_), Value::Object(_)) => Ordering::Equal, // Simplified for brevity
284        }
285    }
286}
287
288impl fmt::Display for Value {
289    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290        match self {
291            Value::Null => write!(f, "null"),
292            Value::Bool(b) => write!(f, "{}", b),
293            Value::Int(i) => write!(f, "{}", i),
294            Value::Float(fl) => write!(f, "{}", fl),
295            Value::String(s) => write!(f, "{}", s),
296            Value::Uuid(u) => write!(f, "{}", u),
297            Value::DateTime(dt) => write!(f, "{}", dt),
298            Value::Array(arr) => write!(f, "{}", serde_json::to_string(arr).unwrap_or_else(|_| "[]".to_string())),
299            Value::Object(obj) => write!(f, "{}", serde_json::to_string(obj).unwrap_or_else(|_| "{}".to_string())),
300        }
301    }
302}
303
304impl Value {
305    pub fn as_str(&self) -> Option<&str> {
306        if let Value::String(s) = self { Some(s) } else { None }
307    }
308    pub fn as_i64(&self) -> Option<i64> {
309        if let Value::Int(i) = self { Some(*i) } else { None }
310    }
311    pub fn as_f64(&self) -> Option<f64> {
312        if let Value::Float(f) = self { Some(*f) } else { None }
313    }
314    pub fn as_bool(&self) -> Option<bool> {
315        if let Value::Bool(b) = self { Some(*b) } else { None }
316    }
317    pub fn as_array(&self) -> Option<&Vec<Value>> {
318        if let Value::Array(a) = self { Some(a) } else { None }
319    }
320    pub fn as_object(&self) -> Option<&HashMap<String, Value>> {
321        if let Value::Object(o) = self { Some(o) } else { None }
322    }
323}
324
325impl From<String> for Value { fn from(v: String) -> Self { Value::String(v) } }
326impl From<&str> for Value { fn from(v: &str) -> Self { Value::String(v.to_string()) } }
327impl From<bool> for Value { fn from(v: bool) -> Self { Value::Bool(v) } }
328impl From<f64> for Value { fn from(v: f64) -> Self { Value::Float(v) } }
329impl From<i64> for Value { fn from(v: i64) -> Self { Value::Int(v) } }
330
331#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
332pub enum DurabilityMode {
333    None,
334    WAL,
335    Strict,
336    /// Synchronous mode: every write blocks until it reaches durable storage.
337    /// No buffering, no WAL — safest but slowest.
338    Synchronous,
339}
340
341#[derive(Debug, Clone, Serialize, Deserialize)]
342pub enum ColdStoreMode {
343    HighThroughput,
344    LowSpace,
345}
346
347#[derive(Debug, Clone, Serialize, Deserialize)]
348pub struct AuroraConfig {
349    pub db_path: PathBuf,
350    pub create_dirs: bool,
351    pub hot_cache_size_mb: usize,
352    pub hot_cache_cleanup_interval_secs: u64,
353    pub eviction_policy: crate::storage::EvictionPolicy,
354    pub cold_cache_capacity_mb: usize,
355    pub cold_flush_interval_ms: Option<u64>,
356    pub cold_mode: ColdStoreMode,
357    pub auto_compact: bool,
358    pub compact_interval_mins: u64,
359    pub max_index_entries_per_field: usize,
360    pub enable_write_buffering: bool,
361    pub write_buffer_size: usize,
362    pub write_buffer_flush_interval_ms: u64,
363    pub durability_mode: DurabilityMode,
364    pub enable_wal: bool,
365    pub checkpoint_interval_ms: u64,
366    pub audit_log_path: Option<String>,
367}
368
369impl Default for AuroraConfig {
370    fn default() -> Self {
371        Self {
372            db_path: PathBuf::from("aurora_db"),
373            create_dirs: true,
374            hot_cache_size_mb: 256,
375            hot_cache_cleanup_interval_secs: 60,
376            eviction_policy: crate::storage::EvictionPolicy::LRU,
377            cold_cache_capacity_mb: 1024,
378            cold_flush_interval_ms: Some(5000),
379            cold_mode: ColdStoreMode::HighThroughput,
380            auto_compact: true,
381            compact_interval_mins: 60,
382            max_index_entries_per_field: 100_000,
383            enable_write_buffering: true,
384            write_buffer_size: 10_000,
385            write_buffer_flush_interval_ms: 1000,
386            durability_mode: DurabilityMode::WAL,
387            enable_wal: true,
388            checkpoint_interval_ms: 10000,
389            audit_log_path: None,
390        }
391    }
392}