1use crate::types::{Document, Value};
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct Query {
18 pub filters: Vec<Filter>,
19 pub sort: Option<Sort>,
20 pub skip: Option<usize>,
21 pub limit: Option<usize>,
22 pub projection: Option<Vec<String>>,
23}
24
25impl Query {
26 pub fn new() -> Self {
27 Self {
28 filters: Vec::new(),
29 sort: None,
30 skip: None,
31 limit: None,
32 projection: None,
33 }
34 }
35
36 pub fn matches(&self, doc: &Document) -> bool {
38 self.filters.iter().all(|f| f.matches(doc))
39 }
40
41 pub fn with_filter(mut self, filter: Filter) -> Self {
43 self.filters.push(filter);
44 self
45 }
46
47 pub fn with_sort(mut self, field: impl Into<String>, ascending: bool) -> Self {
49 self.sort = Some(Sort {
50 field: field.into(),
51 ascending,
52 });
53 self
54 }
55
56 pub fn with_skip(mut self, skip: usize) -> Self {
58 self.skip = Some(skip);
59 self
60 }
61
62 pub fn with_limit(mut self, limit: usize) -> Self {
64 self.limit = Some(limit);
65 self
66 }
67
68 pub fn with_projection(mut self, fields: Vec<String>) -> Self {
70 self.projection = Some(fields);
71 self
72 }
73}
74
75impl Default for Query {
76 fn default() -> Self {
77 Self::new()
78 }
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
87pub enum Filter {
88 Eq { field: String, value: Value },
89 Ne { field: String, value: Value },
90 Gt { field: String, value: Value },
91 Gte { field: String, value: Value },
92 Lt { field: String, value: Value },
93 Lte { field: String, value: Value },
94 In { field: String, values: Vec<Value> },
95 Nin { field: String, values: Vec<Value> },
96 Exists { field: String, exists: bool },
97 Regex { field: String, pattern: String },
98 Contains { field: String, value: String },
99 StartsWith { field: String, value: String },
100 EndsWith { field: String, value: String },
101 And(Vec<Filter>),
102 Or(Vec<Filter>),
103 Not(Box<Filter>),
104}
105
106impl Filter {
107 pub fn matches(&self, doc: &Document) -> bool {
109 match self {
110 Self::Eq { field, value } => {
111 doc.get(field).map(|v| v == value).unwrap_or(false)
112 }
113 Self::Ne { field, value } => {
114 doc.get(field).map(|v| v != value).unwrap_or(true)
115 }
116 Self::Gt { field, value } => {
117 doc.get(field)
118 .map(|v| compare_values(v, value) == Some(std::cmp::Ordering::Greater))
119 .unwrap_or(false)
120 }
121 Self::Gte { field, value } => {
122 doc.get(field)
123 .map(|v| {
124 matches!(
125 compare_values(v, value),
126 Some(std::cmp::Ordering::Greater | std::cmp::Ordering::Equal)
127 )
128 })
129 .unwrap_or(false)
130 }
131 Self::Lt { field, value } => {
132 doc.get(field)
133 .map(|v| compare_values(v, value) == Some(std::cmp::Ordering::Less))
134 .unwrap_or(false)
135 }
136 Self::Lte { field, value } => {
137 doc.get(field)
138 .map(|v| {
139 matches!(
140 compare_values(v, value),
141 Some(std::cmp::Ordering::Less | std::cmp::Ordering::Equal)
142 )
143 })
144 .unwrap_or(false)
145 }
146 Self::In { field, values } => {
147 doc.get(field)
148 .map(|v| values.contains(v))
149 .unwrap_or(false)
150 }
151 Self::Nin { field, values } => {
152 doc.get(field)
153 .map(|v| !values.contains(v))
154 .unwrap_or(true)
155 }
156 Self::Exists { field, exists } => doc.contains(field) == *exists,
157 Self::Regex { field, pattern } => {
158 if let Some(Value::String(s)) = doc.get(field) {
159 regex::Regex::new(pattern)
160 .map(|re| re.is_match(s))
161 .unwrap_or(false)
162 } else {
163 false
164 }
165 }
166 Self::Contains { field, value } => {
167 if let Some(Value::String(s)) = doc.get(field) {
168 s.contains(value)
169 } else {
170 false
171 }
172 }
173 Self::StartsWith { field, value } => {
174 if let Some(Value::String(s)) = doc.get(field) {
175 s.starts_with(value)
176 } else {
177 false
178 }
179 }
180 Self::EndsWith { field, value } => {
181 if let Some(Value::String(s)) = doc.get(field) {
182 s.ends_with(value)
183 } else {
184 false
185 }
186 }
187 Self::And(filters) => filters.iter().all(|f| f.matches(doc)),
188 Self::Or(filters) => filters.iter().any(|f| f.matches(doc)),
189 Self::Not(filter) => !filter.matches(doc),
190 }
191 }
192}
193
194fn compare_values(a: &Value, b: &Value) -> Option<std::cmp::Ordering> {
195 match (a, b) {
196 (Value::Int(a), Value::Int(b)) => Some(a.cmp(b)),
197 (Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
198 (Value::Int(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
199 (Value::Float(a), Value::Int(b)) => a.partial_cmp(&(*b as f64)),
200 (Value::String(a), Value::String(b)) => Some(a.cmp(b)),
201 (Value::Bool(a), Value::Bool(b)) => Some(a.cmp(b)),
202 _ => None,
203 }
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct Sort {
213 pub field: String,
214 pub ascending: bool,
215}
216
217pub struct QueryBuilder {
223 query: Query,
224}
225
226impl QueryBuilder {
227 pub fn new() -> Self {
228 Self {
229 query: Query::new(),
230 }
231 }
232
233 pub fn eq(mut self, field: impl Into<String>, value: impl Into<Value>) -> Self {
234 self.query.filters.push(Filter::Eq {
235 field: field.into(),
236 value: value.into(),
237 });
238 self
239 }
240
241 pub fn ne(mut self, field: impl Into<String>, value: impl Into<Value>) -> Self {
242 self.query.filters.push(Filter::Ne {
243 field: field.into(),
244 value: value.into(),
245 });
246 self
247 }
248
249 pub fn gt(mut self, field: impl Into<String>, value: impl Into<Value>) -> Self {
250 self.query.filters.push(Filter::Gt {
251 field: field.into(),
252 value: value.into(),
253 });
254 self
255 }
256
257 pub fn gte(mut self, field: impl Into<String>, value: impl Into<Value>) -> Self {
258 self.query.filters.push(Filter::Gte {
259 field: field.into(),
260 value: value.into(),
261 });
262 self
263 }
264
265 pub fn lt(mut self, field: impl Into<String>, value: impl Into<Value>) -> Self {
266 self.query.filters.push(Filter::Lt {
267 field: field.into(),
268 value: value.into(),
269 });
270 self
271 }
272
273 pub fn lte(mut self, field: impl Into<String>, value: impl Into<Value>) -> Self {
274 self.query.filters.push(Filter::Lte {
275 field: field.into(),
276 value: value.into(),
277 });
278 self
279 }
280
281 pub fn in_values(mut self, field: impl Into<String>, values: Vec<Value>) -> Self {
282 self.query.filters.push(Filter::In {
283 field: field.into(),
284 values,
285 });
286 self
287 }
288
289 pub fn exists(mut self, field: impl Into<String>, exists: bool) -> Self {
290 self.query.filters.push(Filter::Exists {
291 field: field.into(),
292 exists,
293 });
294 self
295 }
296
297 pub fn contains(mut self, field: impl Into<String>, value: impl Into<String>) -> Self {
298 self.query.filters.push(Filter::Contains {
299 field: field.into(),
300 value: value.into(),
301 });
302 self
303 }
304
305 pub fn starts_with(mut self, field: impl Into<String>, value: impl Into<String>) -> Self {
306 self.query.filters.push(Filter::StartsWith {
307 field: field.into(),
308 value: value.into(),
309 });
310 self
311 }
312
313 pub fn ends_with(mut self, field: impl Into<String>, value: impl Into<String>) -> Self {
314 self.query.filters.push(Filter::EndsWith {
315 field: field.into(),
316 value: value.into(),
317 });
318 self
319 }
320
321 pub fn regex(mut self, field: impl Into<String>, pattern: impl Into<String>) -> Self {
322 self.query.filters.push(Filter::Regex {
323 field: field.into(),
324 pattern: pattern.into(),
325 });
326 self
327 }
328
329 pub fn and(mut self, filters: Vec<Filter>) -> Self {
330 self.query.filters.push(Filter::And(filters));
331 self
332 }
333
334 pub fn or(mut self, filters: Vec<Filter>) -> Self {
335 self.query.filters.push(Filter::Or(filters));
336 self
337 }
338
339 pub fn sort(mut self, field: impl Into<String>, ascending: bool) -> Self {
340 self.query.sort = Some(Sort {
341 field: field.into(),
342 ascending,
343 });
344 self
345 }
346
347 pub fn skip(mut self, skip: usize) -> Self {
348 self.query.skip = Some(skip);
349 self
350 }
351
352 pub fn limit(mut self, limit: usize) -> Self {
353 self.query.limit = Some(limit);
354 self
355 }
356
357 pub fn project(mut self, fields: Vec<String>) -> Self {
358 self.query.projection = Some(fields);
359 self
360 }
361
362 pub fn build(self) -> Query {
363 self.query
364 }
365}
366
367impl Default for QueryBuilder {
368 fn default() -> Self {
369 Self::new()
370 }
371}
372
373#[derive(Debug, Clone)]
379pub struct QueryResult {
380 pub documents: Vec<Document>,
381 pub total_scanned: usize,
382 pub execution_time_ms: u64,
383}
384
385impl QueryResult {
386 pub fn empty() -> Self {
387 Self {
388 documents: Vec::new(),
389 total_scanned: 0,
390 execution_time_ms: 0,
391 }
392 }
393
394 pub fn count(&self) -> usize {
395 self.documents.len()
396 }
397
398 pub fn is_empty(&self) -> bool {
399 self.documents.is_empty()
400 }
401
402 pub fn first(&self) -> Option<&Document> {
403 self.documents.first()
404 }
405}
406
407#[cfg(test)]
412mod tests {
413 use super::*;
414
415 fn create_test_doc() -> Document {
416 let mut doc = Document::with_id("test");
417 doc.set("name", "Alice");
418 doc.set("age", 30i64);
419 doc.set("active", true);
420 doc.set("email", "alice@example.com");
421 doc
422 }
423
424 #[test]
425 fn test_eq_filter() {
426 let doc = create_test_doc();
427
428 let filter = Filter::Eq {
429 field: "name".to_string(),
430 value: Value::String("Alice".to_string()),
431 };
432 assert!(filter.matches(&doc));
433
434 let filter = Filter::Eq {
435 field: "name".to_string(),
436 value: Value::String("Bob".to_string()),
437 };
438 assert!(!filter.matches(&doc));
439 }
440
441 #[test]
442 fn test_comparison_filters() {
443 let doc = create_test_doc();
444
445 let filter = Filter::Gt {
446 field: "age".to_string(),
447 value: Value::Int(25),
448 };
449 assert!(filter.matches(&doc));
450
451 let filter = Filter::Lt {
452 field: "age".to_string(),
453 value: Value::Int(25),
454 };
455 assert!(!filter.matches(&doc));
456
457 let filter = Filter::Gte {
458 field: "age".to_string(),
459 value: Value::Int(30),
460 };
461 assert!(filter.matches(&doc));
462 }
463
464 #[test]
465 fn test_string_filters() {
466 let doc = create_test_doc();
467
468 let filter = Filter::Contains {
469 field: "email".to_string(),
470 value: "example".to_string(),
471 };
472 assert!(filter.matches(&doc));
473
474 let filter = Filter::StartsWith {
475 field: "email".to_string(),
476 value: "alice".to_string(),
477 };
478 assert!(filter.matches(&doc));
479
480 let filter = Filter::EndsWith {
481 field: "email".to_string(),
482 value: ".com".to_string(),
483 };
484 assert!(filter.matches(&doc));
485 }
486
487 #[test]
488 fn test_logical_filters() {
489 let doc = create_test_doc();
490
491 let filter = Filter::And(vec![
492 Filter::Eq {
493 field: "name".to_string(),
494 value: Value::String("Alice".to_string()),
495 },
496 Filter::Gt {
497 field: "age".to_string(),
498 value: Value::Int(20),
499 },
500 ]);
501 assert!(filter.matches(&doc));
502
503 let filter = Filter::Or(vec![
504 Filter::Eq {
505 field: "name".to_string(),
506 value: Value::String("Bob".to_string()),
507 },
508 Filter::Eq {
509 field: "active".to_string(),
510 value: Value::Bool(true),
511 },
512 ]);
513 assert!(filter.matches(&doc));
514 }
515
516 #[test]
517 fn test_query_builder() {
518 let doc = create_test_doc();
519
520 let query = QueryBuilder::new()
521 .eq("name", "Alice")
522 .gt("age", 25i64)
523 .build();
524
525 assert!(query.matches(&doc));
526
527 let query = QueryBuilder::new()
528 .eq("name", "Bob")
529 .build();
530
531 assert!(!query.matches(&doc));
532 }
533
534 #[test]
535 fn test_exists_filter() {
536 let doc = create_test_doc();
537
538 let filter = Filter::Exists {
539 field: "name".to_string(),
540 exists: true,
541 };
542 assert!(filter.matches(&doc));
543
544 let filter = Filter::Exists {
545 field: "missing".to_string(),
546 exists: false,
547 };
548 assert!(filter.matches(&doc));
549 }
550}