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 #[serde(rename = "_sid", alias = "id")]
208 pub _sid: String,
209 pub data: HashMap<String, Value>,
210}
211
212impl Document {
213 pub fn new() -> Self {
214 Self {
215 _sid: Uuid::now_v7().to_string(),
216 data: HashMap::new(),
217 }
218 }
219}
220
221impl fmt::Display for Document {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 write!(f, "{}", serde_json::to_string_pretty(self).unwrap_or_default())
224 }
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
228#[serde(untagged)]
229pub enum Value {
230 Null,
231 Bool(bool),
232 Int(i64),
233 Float(f64),
234 String(String),
235 Uuid(Uuid),
236 DateTime(DateTime<Utc>),
237 Array(Vec<Value>),
238 Object(HashMap<String, Value>),
239}
240
241impl Eq for Value {}
242
243impl PartialOrd for Value {
244 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
245 Some(self.cmp(other))
246 }
247}
248
249impl Ord for Value {
250 fn cmp(&self, other: &Self) -> Ordering {
251 match (self, other) {
252 (Value::Null, Value::Null) => Ordering::Equal,
253 (Value::Null, _) => Ordering::Less,
254 (_, Value::Null) => Ordering::Greater,
255
256 (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
257 (Value::Bool(_), _) => Ordering::Less,
258 (_, Value::Bool(_)) => Ordering::Greater,
259
260 (Value::Int(a), Value::Int(b)) => a.cmp(b),
261 (Value::Int(_), _) => Ordering::Less,
262 (_, Value::Int(_)) => Ordering::Greater,
263
264 (Value::Float(a), Value::Float(b)) => a.total_cmp(b),
265 (Value::Float(_), _) => Ordering::Less,
266 (_, Value::Float(_)) => Ordering::Greater,
267
268 (Value::String(a), Value::String(b)) => a.cmp(b),
269 (Value::String(_), _) => Ordering::Less,
270 (_, Value::String(_)) => Ordering::Greater,
271
272 (Value::Uuid(a), Value::Uuid(b)) => a.cmp(b),
273 (Value::Uuid(_), _) => Ordering::Less,
274 (_, Value::Uuid(_)) => Ordering::Greater,
275
276 (Value::DateTime(a), Value::DateTime(b)) => a.cmp(b),
277 (Value::DateTime(_), _) => Ordering::Less,
278 (_, Value::DateTime(_)) => Ordering::Greater,
279
280 (Value::Array(a), Value::Array(b)) => a.cmp(b),
281 (Value::Array(_), _) => Ordering::Less,
282 (_, Value::Array(_)) => Ordering::Greater,
283
284 (Value::Object(_), Value::Object(_)) => Ordering::Equal, }
286 }
287}
288
289impl fmt::Display for Value {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 match self {
292 Value::Null => write!(f, "null"),
293 Value::Bool(b) => write!(f, "{}", b),
294 Value::Int(i) => write!(f, "{}", i),
295 Value::Float(fl) => write!(f, "{}", fl),
296 Value::String(s) => write!(f, "{}", s),
297 Value::Uuid(u) => write!(f, "{}", u),
298 Value::DateTime(dt) => write!(f, "{}", dt),
299 Value::Array(arr) => write!(f, "{}", serde_json::to_string(arr).unwrap_or_else(|_| "[]".to_string())),
300 Value::Object(obj) => write!(f, "{}", serde_json::to_string(obj).unwrap_or_else(|_| "{}".to_string())),
301 }
302 }
303}
304
305impl Value {
306 pub fn as_str(&self) -> Option<&str> {
307 if let Value::String(s) = self { Some(s) } else { None }
308 }
309 pub fn as_i64(&self) -> Option<i64> {
310 if let Value::Int(i) = self { Some(*i) } else { None }
311 }
312 pub fn as_f64(&self) -> Option<f64> {
313 if let Value::Float(f) = self { Some(*f) } else { None }
314 }
315 pub fn as_bool(&self) -> Option<bool> {
316 if let Value::Bool(b) = self { Some(*b) } else { None }
317 }
318 pub fn as_array(&self) -> Option<&Vec<Value>> {
319 if let Value::Array(a) = self { Some(a) } else { None }
320 }
321 pub fn as_object(&self) -> Option<&HashMap<String, Value>> {
322 if let Value::Object(o) = self { Some(o) } else { None }
323 }
324}
325
326impl From<String> for Value { fn from(v: String) -> Self { Value::String(v) } }
327impl From<&str> for Value { fn from(v: &str) -> Self { Value::String(v.to_string()) } }
328impl From<bool> for Value { fn from(v: bool) -> Self { Value::Bool(v) } }
329impl From<f64> for Value { fn from(v: f64) -> Self { Value::Float(v) } }
330impl From<i64> for Value { fn from(v: i64) -> Self { Value::Int(v) } }
331
332#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
333pub enum DurabilityMode {
334 None,
335 WAL,
336 Strict,
337 Synchronous,
340}
341
342#[derive(Debug, Clone, Serialize, Deserialize)]
343pub enum ColdStoreMode {
344 HighThroughput,
345 LowSpace,
346}
347
348#[derive(Debug, Clone, Serialize, Deserialize)]
349pub struct AuroraConfig {
350 pub db_path: PathBuf,
351 pub create_dirs: bool,
352 pub hot_cache_size_mb: usize,
353 pub hot_cache_cleanup_interval_secs: u64,
354 pub eviction_policy: crate::storage::EvictionPolicy,
355 pub cold_cache_capacity_mb: usize,
356 pub cold_flush_interval_ms: Option<u64>,
357 pub cold_mode: ColdStoreMode,
358 pub auto_compact: bool,
359 pub compact_interval_mins: u64,
360 pub max_index_entries_per_field: usize,
361 pub enable_write_buffering: bool,
362 pub write_buffer_size: usize,
363 pub write_buffer_flush_interval_ms: u64,
364 pub durability_mode: DurabilityMode,
365 pub enable_wal: bool,
366 pub checkpoint_interval_ms: u64,
367 pub audit_log_path: Option<String>,
368 pub workers_enabled: bool,
369 pub worker_threads: usize,
370}
371
372impl Default for AuroraConfig {
373 fn default() -> Self {
374 Self {
375 db_path: PathBuf::from("aurora_db"),
376 create_dirs: true,
377 hot_cache_size_mb: 256,
378 hot_cache_cleanup_interval_secs: 60,
379 eviction_policy: crate::storage::EvictionPolicy::LRU,
380 cold_cache_capacity_mb: 1024,
381 cold_flush_interval_ms: Some(5000),
382 cold_mode: ColdStoreMode::HighThroughput,
383 auto_compact: true,
384 compact_interval_mins: 60,
385 max_index_entries_per_field: 100_000,
386 enable_write_buffering: true,
387 write_buffer_size: 10_000,
388 write_buffer_flush_interval_ms: 1000,
389 durability_mode: DurabilityMode::WAL,
390 enable_wal: true,
391 checkpoint_interval_ms: 10000,
392 audit_log_path: None,
393 workers_enabled: false,
394 worker_threads: 4,
395 }
396 }
397}