1use crate::DbValue;
2use crate::QueryId;
3use crate::graph_search::SearchControl;
4
5#[derive(Clone, Copy, Debug, PartialEq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
9#[cfg_attr(feature = "derive", derive(agdb::DbSerialize))]
10#[cfg_attr(feature = "api", derive(agdb::ApiDef))]
11pub enum QueryConditionLogic {
12 And,
14
15 Or,
17}
18
19#[derive(Clone, Copy, Debug, PartialEq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
23#[cfg_attr(feature = "derive", derive(agdb::DbSerialize))]
24#[cfg_attr(feature = "api", derive(agdb::ApiDef))]
25pub enum QueryConditionModifier {
26 None,
28
29 Beyond,
32
33 Not,
35
36 NotBeyond,
39}
40
41#[derive(Debug, Clone, PartialEq)]
43#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
45#[cfg_attr(feature = "derive", derive(agdb::DbSerialize))]
46#[cfg_attr(feature = "api", derive(agdb::ApiDef))]
47pub enum QueryConditionData {
48 Distance(CountComparison),
51
52 Edge,
54
55 EdgeCount(CountComparison),
60
61 EdgeCountFrom(CountComparison),
65
66 EdgeCountTo(CountComparison),
70
71 Ids(Vec<QueryId>),
73
74 KeyValue(KeyValueComparison),
77
78 Keys(Vec<DbValue>),
80
81 Node,
83
84 Where(Vec<QueryCondition>),
86}
87
88#[derive(Debug, Clone, PartialEq)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
92#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
93#[cfg_attr(feature = "derive", derive(agdb::DbSerialize))]
94#[cfg_attr(feature = "api", derive(agdb::ApiDef))]
95pub struct QueryCondition {
96 pub logic: QueryConditionLogic,
98
99 pub modifier: QueryConditionModifier,
101
102 #[cfg_attr(feature = "openapi", schema(no_recursion))]
105 pub data: QueryConditionData,
106}
107
108#[derive(Debug, Clone, PartialEq)]
112#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
113#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
114#[cfg_attr(feature = "derive", derive(agdb::DbSerialize))]
115#[cfg_attr(feature = "api", derive(agdb::ApiDef))]
116pub enum CountComparison {
117 Equal(u64),
119
120 GreaterThan(u64),
122
123 GreaterThanOrEqual(u64),
125
126 LessThan(u64),
128
129 LessThanOrEqual(u64),
131
132 NotEqual(u64),
134}
135
136#[derive(Debug, Clone, PartialEq)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
147#[cfg_attr(feature = "derive", derive(agdb::DbSerialize))]
148#[cfg_attr(feature = "api", derive(agdb::ApiDef))]
149pub enum Comparison {
150 Equal(DbValue),
152
153 GreaterThan(DbValue),
155
156 GreaterThanOrEqual(DbValue),
158
159 LessThan(DbValue),
161
162 LessThanOrEqual(DbValue),
164
165 NotEqual(DbValue),
167
168 Contains(DbValue),
170
171 StartsWith(DbValue),
173
174 EndsWith(DbValue),
176}
177
178#[derive(Debug, Clone, PartialEq)]
181#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
182#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
183#[cfg_attr(feature = "derive", derive(agdb::DbSerialize))]
184#[cfg_attr(feature = "api", derive(agdb::ApiDef))]
185pub struct KeyValueComparison {
186 pub key: DbValue,
188
189 pub value: Comparison,
191}
192
193impl CountComparison {
194 pub(crate) fn compare_distance(&self, right: u64) -> SearchControl {
195 match self {
196 CountComparison::Equal(left) => match right.cmp(left) {
197 std::cmp::Ordering::Less => SearchControl::Continue(false),
198 std::cmp::Ordering::Equal => SearchControl::Stop(true),
199 std::cmp::Ordering::Greater => SearchControl::Stop(false),
200 },
201 CountComparison::GreaterThan(left) => match right.cmp(left) {
202 std::cmp::Ordering::Less | std::cmp::Ordering::Equal => {
203 SearchControl::Continue(false)
204 }
205 std::cmp::Ordering::Greater => SearchControl::Continue(true),
206 },
207 CountComparison::GreaterThanOrEqual(left) => match right.cmp(left) {
208 std::cmp::Ordering::Less => SearchControl::Continue(false),
209 std::cmp::Ordering::Greater | std::cmp::Ordering::Equal => {
210 SearchControl::Continue(true)
211 }
212 },
213 CountComparison::LessThan(left) => match right.cmp(left) {
214 std::cmp::Ordering::Less => SearchControl::Continue(true),
215 std::cmp::Ordering::Greater | std::cmp::Ordering::Equal => {
216 SearchControl::Stop(false)
217 }
218 },
219 CountComparison::LessThanOrEqual(left) => match right.cmp(left) {
220 std::cmp::Ordering::Less | std::cmp::Ordering::Equal => {
221 SearchControl::Continue(true)
222 }
223 std::cmp::Ordering::Greater => SearchControl::Stop(false),
224 },
225 CountComparison::NotEqual(left) => match right.cmp(left) {
226 std::cmp::Ordering::Less | std::cmp::Ordering::Greater => {
227 SearchControl::Continue(true)
228 }
229 std::cmp::Ordering::Equal => SearchControl::Continue(false),
230 },
231 }
232 }
233
234 pub(crate) fn compare(&self, left: u64) -> bool {
235 match self {
236 CountComparison::Equal(right) => left == *right,
237 CountComparison::GreaterThan(right) => left > *right,
238 CountComparison::GreaterThanOrEqual(right) => left >= *right,
239 CountComparison::LessThan(right) => left < *right,
240 CountComparison::LessThanOrEqual(right) => left <= *right,
241 CountComparison::NotEqual(right) => left != *right,
242 }
243 }
244}
245
246impl Comparison {
247 pub(crate) fn compare(&self, left: &DbValue) -> bool {
248 match self {
249 Comparison::Equal(right) => left == right,
250 Comparison::GreaterThan(right) => left > right,
251 Comparison::GreaterThanOrEqual(right) => left >= right,
252 Comparison::LessThan(right) => left < right,
253 Comparison::LessThanOrEqual(right) => left <= right,
254 Comparison::NotEqual(right) => left != right,
255
256 Comparison::Contains(right) => match (left, right) {
257 (DbValue::String(left), DbValue::String(right)) => left.contains(right),
258 (DbValue::String(left), DbValue::VecString(right)) => {
259 right.iter().all(|x| left.contains(x))
260 }
261 (DbValue::VecI64(left), DbValue::I64(right)) => left.contains(right),
262 (DbValue::VecI64(left), DbValue::VecI64(right)) => {
263 right.iter().all(|x| left.contains(x))
264 }
265 (DbValue::VecU64(left), DbValue::U64(right)) => left.contains(right),
266 (DbValue::VecU64(left), DbValue::VecU64(right)) => {
267 right.iter().all(|x| left.contains(x))
268 }
269 (DbValue::VecF64(left), DbValue::F64(right)) => left.contains(right),
270 (DbValue::VecF64(left), DbValue::VecF64(right)) => {
271 right.iter().all(|x| left.contains(x))
272 }
273 (DbValue::VecString(left), DbValue::String(right)) => left.contains(right),
274 (DbValue::VecString(left), DbValue::VecString(right)) => {
275 right.iter().all(|x| left.contains(x))
276 }
277 _ => false,
278 },
279
280 Comparison::StartsWith(right) => match (left, right) {
281 (DbValue::String(left), DbValue::String(right)) => left.starts_with(right),
282 (DbValue::String(left), DbValue::VecString(right)) => {
283 left.starts_with(&right.concat())
284 }
285 (DbValue::VecI64(left), DbValue::I64(right)) => left.starts_with(&[*right]),
286 (DbValue::VecI64(left), DbValue::VecI64(right)) => left.starts_with(right),
287 (DbValue::VecU64(left), DbValue::U64(right)) => left.starts_with(&[*right]),
288 (DbValue::VecU64(left), DbValue::VecU64(right)) => left.starts_with(right),
289 (DbValue::VecF64(left), DbValue::F64(right)) => left.starts_with(&[*right]),
290 (DbValue::VecF64(left), DbValue::VecF64(right)) => left.starts_with(right),
291 (DbValue::VecString(left), DbValue::String(right)) => left.first() == Some(right),
292 (DbValue::VecString(left), DbValue::VecString(right)) => left.starts_with(right),
293 _ => false,
294 },
295
296 Comparison::EndsWith(right) => match (left, right) {
297 (DbValue::String(left), DbValue::String(right)) => left.ends_with(right),
298 (DbValue::String(left), DbValue::VecString(right)) => {
299 left.ends_with(&right.concat())
300 }
301 (DbValue::VecI64(left), DbValue::I64(right)) => left.ends_with(&[*right]),
302 (DbValue::VecI64(left), DbValue::VecI64(right)) => left.ends_with(right),
303 (DbValue::VecU64(left), DbValue::U64(right)) => left.ends_with(&[*right]),
304 (DbValue::VecU64(left), DbValue::VecU64(right)) => left.ends_with(right),
305 (DbValue::VecF64(left), DbValue::F64(right)) => left.ends_with(&[*right]),
306 (DbValue::VecF64(left), DbValue::VecF64(right)) => left.ends_with(right),
307 (DbValue::VecString(left), DbValue::String(right)) => left.last() == Some(right),
308 (DbValue::VecString(left), DbValue::VecString(right)) => left.ends_with(right),
309 _ => false,
310 },
311 }
312 }
313
314 pub(crate) fn value(&self) -> &DbValue {
315 match self {
316 Comparison::Equal(value)
317 | Comparison::GreaterThan(value)
318 | Comparison::GreaterThanOrEqual(value)
319 | Comparison::LessThan(value)
320 | Comparison::LessThanOrEqual(value)
321 | Comparison::NotEqual(value)
322 | Comparison::Contains(value)
323 | Comparison::StartsWith(value)
324 | Comparison::EndsWith(value) => value,
325 }
326 }
327}
328
329impl From<u64> for CountComparison {
330 fn from(value: u64) -> Self {
331 CountComparison::Equal(value)
332 }
333}
334
335impl<T: Into<DbValue>> From<T> for Comparison {
336 fn from(value: T) -> Self {
337 Comparison::Equal(value.into())
338 }
339}
340
341#[cfg(test)]
342mod tests {
343 use super::*;
344
345 #[test]
346 fn derived_from_debug() {
347 let _ = format!(
348 "{:?}",
349 QueryCondition {
350 logic: QueryConditionLogic::And,
351 modifier: QueryConditionModifier::None,
352 data: QueryConditionData::Edge,
353 }
354 );
355
356 let _ = format!("{:?}", Comparison::Equal(DbValue::I64(0)));
357
358 let _ = format!("{:?}", CountComparison::Equal(0));
359 }
360
361 #[test]
362 #[allow(clippy::redundant_clone)]
363 fn derived_from_clone() {
364 let left = QueryCondition {
365 logic: QueryConditionLogic::And,
366 modifier: QueryConditionModifier::None,
367 data: QueryConditionData::Edge,
368 };
369 let right = left.clone();
370 assert_eq!(left, right);
371
372 let left = Comparison::Equal(DbValue::I64(0));
373 let right = left.clone();
374 assert_eq!(left, right);
375
376 let left = CountComparison::Equal(0);
377 let right = left.clone();
378 assert_eq!(left, right);
379 }
380
381 #[test]
382 fn derived_from_partial_eq() {
383 assert_eq!(
384 QueryCondition {
385 logic: QueryConditionLogic::And,
386 modifier: QueryConditionModifier::None,
387 data: QueryConditionData::Edge,
388 },
389 QueryCondition {
390 logic: QueryConditionLogic::And,
391 modifier: QueryConditionModifier::None,
392 data: QueryConditionData::Edge,
393 }
394 );
395
396 assert_eq!(
397 Comparison::Equal(DbValue::I64(0)),
398 Comparison::Equal(DbValue::I64(0))
399 );
400
401 assert_eq!(CountComparison::Equal(0), CountComparison::Equal(0));
402 }
403
404 #[test]
405 fn count_comparison() {
406 use CountComparison::Equal;
407 use CountComparison::GreaterThan;
408 use CountComparison::GreaterThanOrEqual;
409 use CountComparison::LessThan;
410 use CountComparison::LessThanOrEqual;
411 use CountComparison::NotEqual;
412 use SearchControl::Continue;
413 use SearchControl::Stop;
414
415 assert_eq!(Equal(2).compare_distance(3), Stop(false));
416 assert_eq!(Equal(2).compare_distance(2), Stop(true));
417 assert_eq!(Equal(2).compare_distance(1), Continue(false));
418 assert_eq!(NotEqual(2).compare_distance(3), Continue(true));
419 assert_eq!(NotEqual(2).compare_distance(2), Continue(false));
420 assert_eq!(NotEqual(2).compare_distance(1), Continue(true));
421 assert_eq!(GreaterThan(2).compare_distance(3), Continue(true));
422 assert_eq!(GreaterThan(2).compare_distance(2), Continue(false));
423 assert_eq!(GreaterThan(2).compare_distance(1), Continue(false));
424 assert_eq!(GreaterThanOrEqual(2).compare_distance(3), Continue(true));
425 assert_eq!(GreaterThanOrEqual(2).compare_distance(2), Continue(true));
426 assert_eq!(GreaterThanOrEqual(2).compare_distance(1), Continue(false));
427 assert_eq!(LessThan(2).compare_distance(3), Stop(false));
428 assert_eq!(LessThan(2).compare_distance(2), Stop(false));
429 assert_eq!(LessThan(2).compare_distance(1), Continue(true));
430 assert_eq!(LessThanOrEqual(2).compare_distance(3), Stop(false));
431 assert_eq!(LessThanOrEqual(2).compare_distance(2), Continue(true));
432 assert_eq!(LessThanOrEqual(2).compare_distance(1), Continue(true));
433 }
434
435 #[test]
436 fn contains() {
437 let condition = Comparison::Contains("abc".into());
438 assert!(condition.compare(&"0abc123".into()));
439 assert!(!condition.compare(&"0bc123".into()));
440
441 let condition = Comparison::Contains(vec!["ab".to_string(), "23".to_string()].into());
442 assert!(condition.compare(&"0abc123".into()));
443 assert!(!condition.compare(&"0abc12".into()));
444
445 assert!(Comparison::Contains(1.into()).compare(&vec![2, 1, 3].into()));
446 assert!(!Comparison::Contains(4.into()).compare(&vec![2, 1, 3].into()));
447
448 let condition = Comparison::Contains(vec![2, 3].into());
449 assert!(condition.compare(&vec![2, 3].into()));
450 assert!(!condition.compare(&vec![1, 3].into()));
451
452 let condition = Comparison::Contains(1_u64.into());
453 assert!(condition.compare(&vec![2_u64, 1_u64, 3_u64].into()));
454 assert!(!condition.compare(&vec![2_u64, 3_u64].into()));
455
456 let condition = Comparison::Contains(vec![2_u64, 3_u64].into());
457 assert!(condition.compare(&vec![2_u64, 1_u64, 3_u64].into()));
458 assert!(!condition.compare(&vec![1_u64, 3_u64].into()));
459
460 let condition = Comparison::Contains(1.1.into());
461 assert!(condition.compare(&vec![2.1, 1.1, 3.3].into()));
462 assert!(!condition.compare(&vec![2.1, 3.3].into()));
463
464 let condition = Comparison::Contains(vec![2.2, 3.3].into());
465 assert!(condition.compare(&vec![2.2, 1.1, 3.3].into()));
466 assert!(!condition.compare(&vec![1.1, 3.3].into()));
467
468 let condition = Comparison::Contains("abc".into());
469 assert!(condition.compare(&vec!["abc".to_string(), "123".to_string()].into()));
470 assert!(!condition.compare(&vec!["0".to_string(), "123".to_string()].into()));
471
472 let condition = Comparison::Contains(vec!["abc".to_string(), "123".to_string()].into());
473 assert!(condition.compare(&vec!["abc".to_string(), "123".to_string()].into()));
474 assert!(!condition.compare(&vec!["123".to_string()].into()));
475
476 assert!(!Comparison::Contains("abc".into()).compare(&1.into()));
477 }
478
479 #[test]
480 fn value() {
481 assert_eq!(Comparison::Equal(DbValue::I64(0)).value(), &DbValue::I64(0));
482 assert_eq!(
483 Comparison::GreaterThan(DbValue::I64(0)).value(),
484 &DbValue::I64(0)
485 );
486 assert_eq!(
487 Comparison::GreaterThanOrEqual(DbValue::I64(0)).value(),
488 &DbValue::I64(0)
489 );
490 assert_eq!(
491 Comparison::LessThan(DbValue::I64(0)).value(),
492 &DbValue::I64(0)
493 );
494 assert_eq!(
495 Comparison::LessThanOrEqual(DbValue::I64(0)).value(),
496 &DbValue::I64(0)
497 );
498 assert_eq!(
499 Comparison::NotEqual(DbValue::I64(0)).value(),
500 &DbValue::I64(0)
501 );
502 assert_eq!(
503 Comparison::Contains(DbValue::I64(0)).value(),
504 &DbValue::I64(0)
505 );
506 }
507
508 #[test]
509 fn starts_with() {
510 let condition = Comparison::StartsWith("a".into());
511 assert!(condition.compare(&"abc".into()));
512 assert!(!condition.compare(&"bca".into()));
513
514 let condition = Comparison::StartsWith(vec!["ab".to_string(), "23".to_string()].into());
515 assert!(condition.compare(&"ab23".into()));
516 assert!(!condition.compare(&"ab2".into()));
517
518 assert!(Comparison::StartsWith(1.into()).compare(&vec![1, 2, 3].into()));
519 assert!(!Comparison::StartsWith(1.into()).compare(&vec![2, 1, 3].into()));
520
521 let condition = Comparison::StartsWith(vec![2, 3].into());
522 assert!(condition.compare(&vec![2, 3].into()));
523 assert!(!condition.compare(&vec![1, 2, 3].into()));
524
525 let condition = Comparison::StartsWith(1_u64.into());
526 assert!(condition.compare(&vec![1_u64, 2_u64, 3_u64].into()));
527 assert!(!condition.compare(&vec![2_u64, 1_u64].into()));
528
529 let condition = Comparison::StartsWith(vec![2_u64, 3_u64].into());
530 assert!(condition.compare(&vec![2_u64, 3_u64, 1_u64].into()));
531 assert!(!condition.compare(&vec![1_u64, 2_u64, 3_u64].into()));
532
533 let condition = Comparison::StartsWith(1.1.into());
534 assert!(condition.compare(&vec![1.1, 2.1, 3.3].into()));
535 assert!(!condition.compare(&vec![2.1, 3.3, 1.1].into()));
536
537 let condition = Comparison::StartsWith(vec![2.2, 3.3].into());
538 assert!(condition.compare(&vec![2.2, 3.3, 3.3].into()));
539 assert!(!condition.compare(&vec![1.1, 3.3, 2.2].into()));
540
541 let condition = Comparison::StartsWith("abc".into());
542 assert!(condition.compare(&vec!["abc".to_string(), "123".to_string()].into()));
543 assert!(!condition.compare(&vec!["0".to_string(), "abc".to_string()].into()));
544
545 let condition = Comparison::StartsWith(vec!["abc".to_string(), "123".to_string()].into());
546 assert!(condition.compare(&vec!["abc".to_string(), "123".to_string()].into()));
547 assert!(!condition.compare(&vec!["123".to_string(), "abc".to_string()].into()));
548
549 assert!(!Comparison::StartsWith("abc".into()).compare(&1.into()));
550 }
551
552 #[test]
553 fn ends_with() {
554 let condition = Comparison::EndsWith("a".into());
555 assert!(condition.compare(&"bca".into()));
556 assert!(!condition.compare(&"abc".into()));
557
558 let condition = Comparison::EndsWith(vec!["ab".to_string(), "23".to_string()].into());
559 assert!(condition.compare(&"ffeeggab23".into()));
560 assert!(!condition.compare(&"ab23ff".into()));
561
562 assert!(Comparison::EndsWith(1.into()).compare(&vec![1, 2, 1].into()));
563 assert!(!Comparison::EndsWith(1.into()).compare(&vec![1, 1, 3].into()));
564
565 let condition = Comparison::EndsWith(vec![2, 3].into());
566 assert!(condition.compare(&vec![4, 5, 2, 3].into()));
567 assert!(!condition.compare(&vec![1, 2, 3, 4, 5].into()));
568
569 let condition = Comparison::EndsWith(1_u64.into());
570 assert!(condition.compare(&vec![1_u64, 2_u64, 1_u64].into()));
571 assert!(!condition.compare(&vec![2_u64, 1_u64, 3_u64].into()));
572
573 let condition = Comparison::EndsWith(vec![2_u64, 3_u64].into());
574 assert!(condition.compare(&vec![1_u64, 2_u64, 3_u64].into()));
575 assert!(!condition.compare(&vec![2_u64, 3_u64, 1_u64].into()));
576
577 let condition = Comparison::EndsWith(1.1.into());
578 assert!(condition.compare(&vec![2.1, 3.3, 1.1].into()));
579 assert!(!condition.compare(&vec![2.1, 3.3, 1.1, 4.4].into()));
580
581 let condition = Comparison::EndsWith(vec![2.2, 3.3].into());
582 assert!(condition.compare(&vec![3.3, 4.4, 2.2, 3.3].into()));
583 assert!(!condition.compare(&vec![1.1, 3.3, 2.2].into()));
584
585 let condition = Comparison::EndsWith("abc".into());
586 assert!(condition.compare(&vec!["123".to_string(), "abc".to_string()].into()));
587 assert!(!condition.compare(&vec!["0".to_string(), "abcdef".to_string()].into()));
588
589 let condition = Comparison::EndsWith(vec!["abc".to_string(), "123".to_string()].into());
590 assert!(condition.compare(&vec!["abc".to_string(), "123".to_string()].into()));
591 assert!(!condition.compare(&vec!["123".to_string(), "abc".to_string()].into()));
592
593 assert!(!Comparison::EndsWith("abc".into()).compare(&1.into()));
594 }
595}