aegis_document/
collection.rs1use crate::index::{DocumentIndex, IndexType};
9use crate::query::{Query, QueryResult};
10use crate::types::{Document, DocumentId};
11use crate::validation::{Schema, ValidationResult};
12use std::collections::HashMap;
13use std::sync::RwLock;
14
15pub struct Collection {
21 name: String,
22 documents: RwLock<HashMap<DocumentId, Document>>,
23 indexes: RwLock<Vec<DocumentIndex>>,
24 schema: Option<Schema>,
25}
26
27impl Collection {
28 pub fn new(name: impl Into<String>) -> Self {
30 Self {
31 name: name.into(),
32 documents: RwLock::new(HashMap::new()),
33 indexes: RwLock::new(Vec::new()),
34 schema: None,
35 }
36 }
37
38 pub fn with_schema(name: impl Into<String>, schema: Schema) -> Self {
40 Self {
41 name: name.into(),
42 documents: RwLock::new(HashMap::new()),
43 indexes: RwLock::new(Vec::new()),
44 schema: Some(schema),
45 }
46 }
47
48 pub fn name(&self) -> &str {
50 &self.name
51 }
52
53 pub fn insert(&self, doc: Document) -> Result<DocumentId, CollectionError> {
59 if let Some(ref schema) = self.schema {
60 let result = schema.validate(&doc);
61 if !result.is_valid {
62 return Err(CollectionError::ValidationFailed(result.errors));
63 }
64 }
65
66 let id = doc.id.clone();
67
68 {
69 let mut docs = self.documents.write().unwrap();
70 if docs.contains_key(&id) {
71 return Err(CollectionError::DuplicateId(id));
72 }
73 docs.insert(id.clone(), doc.clone());
74 }
75
76 self.index_document(&doc);
77
78 Ok(id)
79 }
80
81 pub fn insert_many(&self, docs: Vec<Document>) -> Result<Vec<DocumentId>, CollectionError> {
83 let mut ids = Vec::with_capacity(docs.len());
84
85 for doc in docs {
86 let id = self.insert(doc)?;
87 ids.push(id);
88 }
89
90 Ok(ids)
91 }
92
93 pub fn get(&self, id: &DocumentId) -> Option<Document> {
95 let docs = self.documents.read().unwrap();
96 docs.get(id).cloned()
97 }
98
99 pub fn update(&self, id: &DocumentId, doc: Document) -> Result<(), CollectionError> {
101 if let Some(ref schema) = self.schema {
102 let result = schema.validate(&doc);
103 if !result.is_valid {
104 return Err(CollectionError::ValidationFailed(result.errors));
105 }
106 }
107
108 {
109 let mut docs = self.documents.write().unwrap();
110 if !docs.contains_key(id) {
111 return Err(CollectionError::NotFound(id.clone()));
112 }
113
114 if let Some(old_doc) = docs.get(id) {
115 self.unindex_document(old_doc);
116 }
117
118 docs.insert(id.clone(), doc.clone());
119 }
120
121 self.index_document(&doc);
122
123 Ok(())
124 }
125
126 pub fn delete(&self, id: &DocumentId) -> Result<Document, CollectionError> {
128 let mut docs = self.documents.write().unwrap();
129
130 match docs.remove(id) {
131 Some(doc) => {
132 self.unindex_document(&doc);
133 Ok(doc)
134 }
135 None => Err(CollectionError::NotFound(id.clone())),
136 }
137 }
138
139 pub fn contains(&self, id: &DocumentId) -> bool {
141 let docs = self.documents.read().unwrap();
142 docs.contains_key(id)
143 }
144
145 pub fn count(&self) -> usize {
147 let docs = self.documents.read().unwrap();
148 docs.len()
149 }
150
151 pub fn ids(&self) -> Vec<DocumentId> {
153 let docs = self.documents.read().unwrap();
154 docs.keys().cloned().collect()
155 }
156
157 pub fn all(&self) -> Vec<Document> {
159 let docs = self.documents.read().unwrap();
160 docs.values().cloned().collect()
161 }
162
163 pub fn clear(&self) {
165 let mut docs = self.documents.write().unwrap();
166 docs.clear();
167
168 let mut indexes = self.indexes.write().unwrap();
169 for index in indexes.iter_mut() {
170 index.clear();
171 }
172 }
173
174 pub fn find(&self, query: &Query) -> QueryResult {
180 let docs = self.documents.read().unwrap();
181 let start = std::time::Instant::now();
182
183 let matching: Vec<Document> = docs
184 .values()
185 .filter(|doc| query.matches(doc))
186 .take(query.limit.unwrap_or(usize::MAX))
187 .cloned()
188 .collect();
189
190 QueryResult {
191 documents: matching,
192 total_scanned: docs.len(),
193 execution_time_ms: start.elapsed().as_millis() as u64,
194 }
195 }
196
197 pub fn find_one(&self, query: &Query) -> Option<Document> {
199 let docs = self.documents.read().unwrap();
200 docs.values().find(|doc| query.matches(doc)).cloned()
201 }
202
203 pub fn count_matching(&self, query: &Query) -> usize {
205 let docs = self.documents.read().unwrap();
206 docs.values().filter(|doc| query.matches(doc)).count()
207 }
208
209 pub fn create_index(&self, field: impl Into<String>, index_type: IndexType) {
215 let field = field.into();
216 let mut index = DocumentIndex::new(field.clone(), index_type);
217
218 let docs = self.documents.read().unwrap();
219 for doc in docs.values() {
220 index.index_document(doc);
221 }
222
223 let mut indexes = self.indexes.write().unwrap();
224 indexes.push(index);
225 }
226
227 pub fn drop_index(&self, field: &str) {
229 let mut indexes = self.indexes.write().unwrap();
230 indexes.retain(|idx| idx.field() != field);
231 }
232
233 pub fn index_names(&self) -> Vec<String> {
235 let indexes = self.indexes.read().unwrap();
236 indexes.iter().map(|idx| idx.field().to_string()).collect()
237 }
238
239 fn index_document(&self, doc: &Document) {
240 let mut indexes = self.indexes.write().unwrap();
241 for index in indexes.iter_mut() {
242 index.index_document(doc);
243 }
244 }
245
246 fn unindex_document(&self, doc: &Document) {
247 let mut indexes = self.indexes.write().unwrap();
248 for index in indexes.iter_mut() {
249 index.unindex_document(doc);
250 }
251 }
252
253 pub fn set_schema(&mut self, schema: Schema) {
259 self.schema = Some(schema);
260 }
261
262 pub fn schema(&self) -> Option<&Schema> {
264 self.schema.as_ref()
265 }
266
267 pub fn validate_all(&self) -> Vec<(DocumentId, ValidationResult)> {
269 let Some(ref schema) = self.schema else {
270 return Vec::new();
271 };
272
273 let docs = self.documents.read().unwrap();
274 docs.iter()
275 .map(|(id, doc)| (id.clone(), schema.validate(doc)))
276 .filter(|(_, result)| !result.is_valid)
277 .collect()
278 }
279}
280
281#[derive(Debug, Clone)]
287pub enum CollectionError {
288 DuplicateId(DocumentId),
289 NotFound(DocumentId),
290 ValidationFailed(Vec<String>),
291 IndexError(String),
292}
293
294impl std::fmt::Display for CollectionError {
295 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296 match self {
297 Self::DuplicateId(id) => write!(f, "Document with ID {} already exists", id),
298 Self::NotFound(id) => write!(f, "Document with ID {} not found", id),
299 Self::ValidationFailed(errors) => {
300 write!(f, "Validation failed: {}", errors.join(", "))
301 }
302 Self::IndexError(msg) => write!(f, "Index error: {}", msg),
303 }
304 }
305}
306
307impl std::error::Error for CollectionError {}
308
309#[cfg(test)]
314mod tests {
315 use super::*;
316 use crate::query::QueryBuilder;
317
318 #[test]
319 fn test_collection_creation() {
320 let collection = Collection::new("users");
321 assert_eq!(collection.name(), "users");
322 assert_eq!(collection.count(), 0);
323 }
324
325 #[test]
326 fn test_insert_and_get() {
327 let collection = Collection::new("test");
328
329 let mut doc = Document::with_id("doc1");
330 doc.set("name", "Alice");
331
332 let id = collection.insert(doc).unwrap();
333 assert_eq!(id.as_str(), "doc1");
334
335 let retrieved = collection.get(&id).unwrap();
336 assert_eq!(retrieved.get("name").and_then(|v| v.as_str()), Some("Alice"));
337 }
338
339 #[test]
340 fn test_duplicate_id() {
341 let collection = Collection::new("test");
342
343 let doc1 = Document::with_id("same-id");
344 let doc2 = Document::with_id("same-id");
345
346 collection.insert(doc1).unwrap();
347 let result = collection.insert(doc2);
348
349 assert!(matches!(result, Err(CollectionError::DuplicateId(_))));
350 }
351
352 #[test]
353 fn test_update() {
354 let collection = Collection::new("test");
355
356 let mut doc = Document::with_id("doc1");
357 doc.set("count", 1i64);
358 collection.insert(doc).unwrap();
359
360 let mut updated = Document::with_id("doc1");
361 updated.set("count", 2i64);
362 collection.update(&DocumentId::new("doc1"), updated).unwrap();
363
364 let retrieved = collection.get(&DocumentId::new("doc1")).unwrap();
365 assert_eq!(retrieved.get("count").and_then(|v| v.as_i64()), Some(2));
366 }
367
368 #[test]
369 fn test_delete() {
370 let collection = Collection::new("test");
371
372 let doc = Document::with_id("doc1");
373 collection.insert(doc).unwrap();
374
375 assert!(collection.contains(&DocumentId::new("doc1")));
376
377 collection.delete(&DocumentId::new("doc1")).unwrap();
378 assert!(!collection.contains(&DocumentId::new("doc1")));
379 }
380
381 #[test]
382 fn test_find() {
383 let collection = Collection::new("test");
384
385 for i in 0..10 {
386 let mut doc = Document::new();
387 doc.set("value", i as i64);
388 doc.set("even", i % 2 == 0);
389 collection.insert(doc).unwrap();
390 }
391
392 let query = QueryBuilder::new().eq("even", true).build();
393 let result = collection.find(&query);
394
395 assert_eq!(result.documents.len(), 5);
396 }
397}