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