1use serde::{Deserialize, Serialize};
2use std::cmp::Ordering;
3use std::collections::HashMap;
4use std::fmt;
5use std::hash::{Hash, Hasher};
6use std::path::{Path, PathBuf};
7use uuid::Uuid;
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
10pub enum FieldType {
11 String,
12 Int,
13 Uuid,
14 Boolean,
15 Float,
16 Array,
17 Object,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
21pub struct FieldDefinition {
22 pub field_type: FieldType,
23 pub unique: bool,
24 pub indexed: bool,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct Collection {
29 pub name: String,
30 pub fields: HashMap<String, FieldDefinition>,
31}
32
33#[derive(Clone, Serialize, Deserialize)]
34pub struct Document {
35 pub id: String,
36 pub data: HashMap<String, Value>,
37}
38
39impl Default for Document {
40 fn default() -> Self {
41 Self {
42 id: Uuid::new_v4().to_string(),
43 data: HashMap::new(),
44 }
45 }
46}
47
48impl Document {
49 pub fn new() -> Self {
50 Self::default()
51 }
52}
53
54impl fmt::Display for Document {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 write!(f, "{{ ")?;
57 let mut first = true;
58 for (key, value) in &self.data {
59 if !first {
60 write!(f, ", ")?;
61 }
62 write!(f, "\"{}\": {}", key, value)?;
63 first = false;
64 }
65 write!(f, " }}")
66 }
67}
68
69impl fmt::Debug for Document {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 fmt::Display::fmt(self, f)
72 }
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub enum Value {
77 Null,
78 String(String),
79 Int(i64),
80 Float(f64),
81 Bool(bool),
82 Array(Vec<Value>),
83 Object(HashMap<String, Value>),
84 Uuid(Uuid),
85}
86
87impl Hash for Value {
89 fn hash<H: Hasher>(&self, state: &mut H) {
90 match self {
91 Value::Null => 0.hash(state),
92 Value::String(s) => s.hash(state),
93 Value::Int(i) => i.hash(state),
94 Value::Float(f) => {
95 f.to_bits().hash(state)
97 }
98 Value::Bool(b) => b.hash(state),
99 Value::Array(arr) => arr.hash(state),
100 Value::Object(map) => {
101 let mut keys: Vec<_> = map.keys().collect();
103 keys.sort();
104 for key in keys {
105 key.hash(state);
106 map.get(key).unwrap().hash(state);
107 }
108 }
109 Value::Uuid(u) => u.hash(state),
110 }
111 }
112}
113
114impl PartialEq for Value {
115 fn eq(&self, other: &Self) -> bool {
116 match (self, other) {
117 (Value::Null, Value::Null) => true,
118 (Value::String(a), Value::String(b)) => a == b,
119 (Value::Int(a), Value::Int(b)) => a == b,
120 (Value::Float(a), Value::Float(b)) => a.to_bits() == b.to_bits(),
121 (Value::Bool(a), Value::Bool(b)) => a == b,
122 (Value::Array(a), Value::Array(b)) => a == b,
123 (Value::Object(a), Value::Object(b)) => a == b,
124 (Value::Uuid(a), Value::Uuid(b)) => a == b,
125 _ => false,
126 }
127 }
128}
129
130impl Eq for Value {}
131
132impl fmt::Display for Value {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 match self {
136 Value::String(s) => write!(f, "\"{}\"", s),
137 Value::Int(i) => write!(f, "{}", i),
138 Value::Float(fl) => write!(f, "{}", fl),
139 Value::Bool(b) => write!(f, "{}", b),
140 Value::Array(arr) => {
141 let items: Vec<String> = arr.iter().map(|v| v.to_string()).collect();
142 write!(f, "[{}]", items.join(", "))
143 }
144 Value::Object(obj) => {
145 let items: Vec<String> = obj
146 .iter()
147 .map(|(k, v)| format!("\"{}\": {}", k, v))
148 .collect();
149 write!(f, "{{{}}}", items.join(", "))
150 }
151 Value::Uuid(u) => write!(f, "\"{}\"", u),
152 Value::Null => write!(f, "null"),
153 }
154 }
155}
156
157fn type_rank(v: &Value) -> u8 {
159 match v {
160 Value::Null => 0,
161 Value::Bool(_) => 1,
162 Value::Int(_) => 2,
163 Value::Float(_) => 3,
164 Value::String(_) => 4,
165 Value::Uuid(_) => 5,
166 Value::Array(_) => 6,
167 Value::Object(_) => 7,
168 }
169}
170
171impl PartialOrd for Value {
172 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
173 let self_rank = type_rank(self);
174 let other_rank = type_rank(other);
175
176 if self_rank != other_rank {
177 return Some(self_rank.cmp(&other_rank));
178 }
179
180 match (self, other) {
181 (Value::String(a), Value::String(b)) => a.partial_cmp(b),
182 (Value::Int(a), Value::Int(b)) => a.partial_cmp(b),
183 (Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
184 (Value::Bool(a), Value::Bool(b)) => a.partial_cmp(b),
185 (Value::Array(a), Value::Array(b)) => a.partial_cmp(b),
186 (Value::Uuid(a), Value::Uuid(b)) => a.partial_cmp(b),
187 (Value::Object(_), Value::Object(_)) => Some(Ordering::Equal),
188 (Value::Null, Value::Null) => Some(Ordering::Equal),
189 _ => None,
190 }
191 }
192}
193
194impl Ord for Value {
195 fn cmp(&self, other: &Self) -> Ordering {
196 self.partial_cmp(other).unwrap()
197 }
198}
199
200impl From<i64> for Value {
202 fn from(v: i64) -> Self {
203 Value::Int(v)
204 }
205}
206
207impl From<i32> for Value {
208 fn from(v: i32) -> Self {
209 Value::Int(v as i64)
210 }
211}
212
213impl From<&str> for Value {
214 fn from(v: &str) -> Self {
215 Value::String(v.to_string())
216 }
217}
218
219impl From<String> for Value {
220 fn from(v: String) -> Self {
221 Value::String(v)
222 }
223}
224
225impl From<bool> for Value {
226 fn from(v: bool) -> Self {
227 Value::Bool(v)
228 }
229}
230
231impl From<f64> for Value {
232 fn from(v: f64) -> Self {
233 Value::Float(v)
234 }
235}
236
237impl From<Vec<Value>> for Value {
238 fn from(v: Vec<Value>) -> Self {
239 Value::Array(v)
240 }
241}
242
243impl From<HashMap<String, Value>> for Value {
244 fn from(v: HashMap<String, Value>) -> Self {
245 Value::Object(v)
246 }
247}
248
249impl From<Uuid> for Value {
250 fn from(v: Uuid) -> Self {
251 Value::Uuid(v)
252 }
253}
254
255#[derive(Debug, Clone)]
257pub struct AuroraConfig {
258 pub db_path: PathBuf,
260 pub create_dirs: bool, pub hot_cache_size_mb: usize,
264 pub hot_cache_cleanup_interval_secs: u64,
265
266 pub cold_cache_capacity_mb: usize,
268 pub cold_flush_interval_ms: Option<u64>,
269 pub cold_mode: ColdStoreMode,
270
271 pub auto_compact: bool,
273 pub compact_interval_mins: u64,
274}
275
276#[derive(Debug, Clone, Copy)]
277pub enum ColdStoreMode {
278 HighThroughput,
279 LowSpace,
280}
281
282impl Default for AuroraConfig {
283 fn default() -> Self {
284 Self {
285 db_path: PathBuf::from("aurora.db"),
286 create_dirs: true,
287
288 hot_cache_size_mb: 128,
289 hot_cache_cleanup_interval_secs: 30,
290
291 cold_cache_capacity_mb: 64,
292 cold_flush_interval_ms: Some(100),
293 cold_mode: ColdStoreMode::HighThroughput,
294
295 auto_compact: true,
296 compact_interval_mins: 60,
297 }
298 }
299}
300
301impl AuroraConfig {
302 pub fn with_path<P: AsRef<Path>>(path: P) -> Self {
304 let mut config = Self::default();
305 config.db_path = path.as_ref().to_path_buf();
306 config
307 }
308}