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#[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 #[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, }
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,
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}