1use super::binding::{Binding, Value, Var};
13use super::cancel::CancelToken;
14use std::collections::HashSet;
15use std::fmt::Debug;
16
17#[inline]
24fn check_shared_cancel(token: &Option<CancelToken>) -> Result<(), IterError> {
25 if let Some(token) = token {
26 if token.is_cancelled() {
27 return Err(IterError::Cancelled);
28 }
29 }
30 Ok(())
31}
32
33pub type IterResult = Result<Option<Binding>, IterError>;
35
36#[derive(Debug, Clone)]
38pub enum IterError {
39 Execution(String),
41 Timeout,
43 Cancelled,
45 ResourceExhausted(String),
47}
48
49impl std::fmt::Display for IterError {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 match self {
52 IterError::Execution(msg) => write!(f, "Execution error: {}", msg),
53 IterError::Timeout => write!(f, "Query timeout"),
54 IterError::Cancelled => write!(f, "Query cancelled"),
55 IterError::ResourceExhausted(msg) => write!(f, "Resource exhausted: {}", msg),
56 }
57 }
58}
59
60impl std::error::Error for IterError {}
61
62pub trait BindingIterator: Debug + Send {
64 fn next_binding(&mut self) -> IterResult;
66
67 fn has_next(&self) -> bool {
69 true }
71
72 fn vars(&self) -> Vec<Var>;
74
75 fn cancel(&mut self);
77
78 fn reset(&mut self) -> bool {
80 false }
82}
83
84#[derive(Debug)]
86pub struct QueryIterBase {
87 bindings: Vec<Binding>,
88 index: usize,
89 vars: Vec<Var>,
90 cancelled: bool,
91 cancel: Option<CancelToken>,
95}
96
97impl QueryIterBase {
98 pub fn new(bindings: Vec<Binding>) -> Self {
100 let vars = if let Some(first) = bindings.first() {
101 first.all_vars().into_iter().cloned().collect()
102 } else {
103 Vec::new()
104 };
105
106 Self {
107 bindings,
108 index: 0,
109 vars,
110 cancelled: false,
111 cancel: None,
112 }
113 }
114
115 pub fn empty() -> Self {
117 Self {
118 bindings: Vec::new(),
119 index: 0,
120 vars: Vec::new(),
121 cancelled: false,
122 cancel: None,
123 }
124 }
125
126 pub fn single(binding: Binding) -> Self {
128 let vars = binding.all_vars().into_iter().cloned().collect();
129 Self {
130 bindings: vec![binding],
131 index: 0,
132 vars,
133 cancelled: false,
134 cancel: None,
135 }
136 }
137
138 pub fn with_cancel(mut self, token: CancelToken) -> Self {
143 self.cancel = Some(token);
144 self
145 }
146}
147
148impl BindingIterator for QueryIterBase {
149 fn next_binding(&mut self) -> IterResult {
150 if self.cancelled {
151 return Err(IterError::Cancelled);
152 }
153 check_shared_cancel(&self.cancel)?;
154
155 if self.index < self.bindings.len() {
156 let binding = std::mem::take(&mut self.bindings[self.index]);
161 self.index += 1;
162 Ok(Some(binding))
163 } else {
164 Ok(None)
165 }
166 }
167
168 fn has_next(&self) -> bool {
169 !self.cancelled && self.index < self.bindings.len()
170 }
171
172 fn vars(&self) -> Vec<Var> {
173 self.vars.clone()
174 }
175
176 fn cancel(&mut self) {
177 self.cancelled = true;
178 }
179
180 fn reset(&mut self) -> bool {
181 self.index = 0;
182 self.cancelled = false;
183 true
184 }
185}
186
187pub struct QueryIterFilter {
189 upstream: Box<dyn BindingIterator>,
190 predicate: Box<dyn Fn(&Binding) -> bool + Send + Sync>,
191 cancelled: bool,
192 cancel: Option<CancelToken>,
197}
198
199impl std::fmt::Debug for QueryIterFilter {
200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 f.debug_struct("QueryIterFilter")
202 .field("upstream", &self.upstream)
203 .field("predicate", &"<filter fn>")
204 .field("cancelled", &self.cancelled)
205 .finish()
206 }
207}
208
209impl QueryIterFilter {
210 pub fn new<F>(upstream: Box<dyn BindingIterator>, predicate: F) -> Self
212 where
213 F: Fn(&Binding) -> bool + Send + Sync + 'static,
214 {
215 Self {
216 upstream,
217 predicate: Box::new(predicate),
218 cancelled: false,
219 cancel: None,
220 }
221 }
222
223 pub fn with_cancel(mut self, token: CancelToken) -> Self {
225 self.cancel = Some(token);
226 self
227 }
228}
229
230impl BindingIterator for QueryIterFilter {
231 fn next_binding(&mut self) -> IterResult {
232 if self.cancelled {
233 return Err(IterError::Cancelled);
234 }
235
236 loop {
237 check_shared_cancel(&self.cancel)?;
238 match self.upstream.next_binding()? {
239 Some(binding) => {
240 if (self.predicate)(&binding) {
241 return Ok(Some(binding));
242 }
243 }
245 None => return Ok(None),
246 }
247 }
248 }
249
250 fn vars(&self) -> Vec<Var> {
251 self.upstream.vars()
252 }
253
254 fn cancel(&mut self) {
255 self.cancelled = true;
256 self.upstream.cancel();
257 }
258}
259
260pub struct QueryIterJoin {
262 left: Box<dyn BindingIterator>,
263 right_factory: Box<dyn Fn() -> Box<dyn BindingIterator> + Send + Sync>,
264 current_left: Option<Binding>,
265 current_right: Option<Box<dyn BindingIterator>>,
266 vars: Vec<Var>,
267 cancelled: bool,
268 cancel: Option<CancelToken>,
273}
274
275impl std::fmt::Debug for QueryIterJoin {
276 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277 f.debug_struct("QueryIterJoin")
278 .field("left", &self.left)
279 .field("right_factory", &"<factory fn>")
280 .field("current_left", &self.current_left)
281 .field("current_right", &self.current_right)
282 .field("vars", &self.vars)
283 .field("cancelled", &self.cancelled)
284 .finish()
285 }
286}
287
288impl QueryIterJoin {
289 pub fn new<F>(left: Box<dyn BindingIterator>, right_factory: F, right_vars: Vec<Var>) -> Self
291 where
292 F: Fn() -> Box<dyn BindingIterator> + Send + Sync + 'static,
293 {
294 let mut vars = left.vars();
295 for v in right_vars {
296 if !vars.contains(&v) {
297 vars.push(v);
298 }
299 }
300
301 Self {
302 left,
303 right_factory: Box::new(right_factory),
304 current_left: None,
305 current_right: None,
306 vars,
307 cancelled: false,
308 cancel: None,
309 }
310 }
311
312 pub fn with_cancel(mut self, token: CancelToken) -> Self {
314 self.cancel = Some(token);
315 self
316 }
317}
318
319impl BindingIterator for QueryIterJoin {
320 fn next_binding(&mut self) -> IterResult {
321 if self.cancelled {
322 return Err(IterError::Cancelled);
323 }
324
325 loop {
326 check_shared_cancel(&self.cancel)?;
327 if let Some(ref mut right) = self.current_right {
329 if let Some(right_binding) = right.next_binding()? {
330 if let Some(ref left_binding) = self.current_left {
332 if let Some(merged) = left_binding.merge(&right_binding) {
333 return Ok(Some(merged));
334 }
335 continue;
337 }
338 }
339 }
340
341 match self.left.next_binding()? {
343 Some(left_binding) => {
344 self.current_left = Some(left_binding);
345 self.current_right = Some((self.right_factory)());
346 }
347 None => return Ok(None),
348 }
349 }
350 }
351
352 fn vars(&self) -> Vec<Var> {
353 self.vars.clone()
354 }
355
356 fn cancel(&mut self) {
357 self.cancelled = true;
358 self.left.cancel();
359 if let Some(ref mut right) = self.current_right {
360 right.cancel();
361 }
362 }
363}
364
365#[derive(Debug)]
367pub struct QueryIterUnion {
368 iterators: Vec<Box<dyn BindingIterator>>,
369 current_index: usize,
370 vars: Vec<Var>,
371 cancelled: bool,
372}
373
374impl QueryIterUnion {
375 pub fn new(iterators: Vec<Box<dyn BindingIterator>>) -> Self {
377 let mut vars = Vec::new();
378 for iter in &iterators {
379 for v in iter.vars() {
380 if !vars.contains(&v) {
381 vars.push(v);
382 }
383 }
384 }
385
386 Self {
387 iterators,
388 current_index: 0,
389 vars,
390 cancelled: false,
391 }
392 }
393}
394
395impl BindingIterator for QueryIterUnion {
396 fn next_binding(&mut self) -> IterResult {
397 if self.cancelled {
398 return Err(IterError::Cancelled);
399 }
400
401 while self.current_index < self.iterators.len() {
402 match self.iterators[self.current_index].next_binding()? {
403 Some(binding) => return Ok(Some(binding)),
404 None => {
405 self.current_index += 1;
406 }
407 }
408 }
409
410 Ok(None)
411 }
412
413 fn vars(&self) -> Vec<Var> {
414 self.vars.clone()
415 }
416
417 fn cancel(&mut self) {
418 self.cancelled = true;
419 for iter in &mut self.iterators {
420 iter.cancel();
421 }
422 }
423}
424
425#[derive(Debug)]
427pub struct QueryIterProject {
428 upstream: Box<dyn BindingIterator>,
429 project_vars: Vec<Var>,
430 cancelled: bool,
431}
432
433impl QueryIterProject {
434 pub fn new(upstream: Box<dyn BindingIterator>, vars: Vec<Var>) -> Self {
436 Self {
437 upstream,
438 project_vars: vars,
439 cancelled: false,
440 }
441 }
442}
443
444impl BindingIterator for QueryIterProject {
445 fn next_binding(&mut self) -> IterResult {
446 if self.cancelled {
447 return Err(IterError::Cancelled);
448 }
449
450 match self.upstream.next_binding()? {
451 Some(binding) => Ok(Some(binding.project(&self.project_vars))),
452 None => Ok(None),
453 }
454 }
455
456 fn vars(&self) -> Vec<Var> {
457 self.project_vars.clone()
458 }
459
460 fn cancel(&mut self) {
461 self.cancelled = true;
462 self.upstream.cancel();
463 }
464}
465
466#[derive(Debug)]
468pub struct QueryIterSlice {
469 upstream: Box<dyn BindingIterator>,
470 offset: u64,
471 limit: Option<u64>,
472 skipped: u64,
473 returned: u64,
474 cancelled: bool,
475}
476
477impl QueryIterSlice {
478 pub fn new(upstream: Box<dyn BindingIterator>, offset: u64, limit: Option<u64>) -> Self {
480 Self {
481 upstream,
482 offset,
483 limit,
484 skipped: 0,
485 returned: 0,
486 cancelled: false,
487 }
488 }
489
490 pub fn limit(upstream: Box<dyn BindingIterator>, limit: u64) -> Self {
492 Self::new(upstream, 0, Some(limit))
493 }
494
495 pub fn offset(upstream: Box<dyn BindingIterator>, offset: u64) -> Self {
497 Self::new(upstream, offset, None)
498 }
499}
500
501impl BindingIterator for QueryIterSlice {
502 fn next_binding(&mut self) -> IterResult {
503 if self.cancelled {
504 return Err(IterError::Cancelled);
505 }
506
507 if let Some(limit) = self.limit {
509 if self.returned >= limit {
510 return Ok(None);
511 }
512 }
513
514 while self.skipped < self.offset {
516 match self.upstream.next_binding()? {
517 Some(_) => {
518 self.skipped += 1;
519 }
520 None => return Ok(None),
521 }
522 }
523
524 match self.upstream.next_binding()? {
526 Some(binding) => {
527 self.returned += 1;
528 Ok(Some(binding))
529 }
530 None => Ok(None),
531 }
532 }
533
534 fn vars(&self) -> Vec<Var> {
535 self.upstream.vars()
536 }
537
538 fn cancel(&mut self) {
539 self.cancelled = true;
540 self.upstream.cancel();
541 }
542}
543
544#[derive(Debug)]
546pub struct QueryIterSort {
547 upstream: Box<dyn BindingIterator>,
548 comparators: Vec<SortKey>,
549 sorted: Option<Vec<Binding>>,
550 index: usize,
551 cancelled: bool,
552}
553
554#[derive(Debug, Clone)]
556pub struct SortKey {
557 pub var: Var,
559 pub ascending: bool,
561}
562
563impl SortKey {
564 pub fn asc(var: Var) -> Self {
566 Self {
567 var,
568 ascending: true,
569 }
570 }
571
572 pub fn desc(var: Var) -> Self {
574 Self {
575 var,
576 ascending: false,
577 }
578 }
579}
580
581impl QueryIterSort {
582 pub fn new(upstream: Box<dyn BindingIterator>, comparators: Vec<SortKey>) -> Self {
584 Self {
585 upstream,
586 comparators,
587 sorted: None,
588 index: 0,
589 cancelled: false,
590 }
591 }
592
593 fn materialize(&mut self) -> Result<(), IterError> {
595 if self.sorted.is_some() {
596 return Ok(());
597 }
598
599 let mut bindings = Vec::new();
600 while let Some(b) = self.upstream.next_binding()? {
601 bindings.push(b);
602 }
603
604 let comparators = self.comparators.clone();
606 bindings.sort_by(|a, b| {
607 for key in &comparators {
608 let a_val = a.get(&key.var);
609 let b_val = b.get(&key.var);
610
611 let ordering = compare_values(a_val, b_val);
612 if ordering != std::cmp::Ordering::Equal {
613 return if key.ascending {
614 ordering
615 } else {
616 ordering.reverse()
617 };
618 }
619 }
620 std::cmp::Ordering::Equal
621 });
622
623 self.sorted = Some(bindings);
624 Ok(())
625 }
626}
627
628impl BindingIterator for QueryIterSort {
629 fn next_binding(&mut self) -> IterResult {
630 if self.cancelled {
631 return Err(IterError::Cancelled);
632 }
633
634 self.materialize()?;
635
636 if let Some(ref sorted) = self.sorted {
637 if self.index < sorted.len() {
638 let binding = sorted[self.index].clone();
639 self.index += 1;
640 return Ok(Some(binding));
641 }
642 }
643
644 Ok(None)
645 }
646
647 fn vars(&self) -> Vec<Var> {
648 self.upstream.vars()
649 }
650
651 fn cancel(&mut self) {
652 self.cancelled = true;
653 self.upstream.cancel();
654 }
655}
656
657fn compare_values(a: Option<&Value>, b: Option<&Value>) -> std::cmp::Ordering {
659 match (a, b) {
660 (None, None) => std::cmp::Ordering::Equal,
661 (None, Some(_)) => std::cmp::Ordering::Less,
662 (Some(_), None) => std::cmp::Ordering::Greater,
663 (Some(a_val), Some(b_val)) => compare_value(a_val, b_val),
664 }
665}
666
667fn compare_value(a: &Value, b: &Value) -> std::cmp::Ordering {
669 match (a, b) {
670 (Value::Integer(a), Value::Integer(b)) => a.cmp(b),
671 (Value::Float(a), Value::Float(b)) => a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal),
672 (Value::String(a), Value::String(b)) => a.cmp(b),
673 (Value::Boolean(a), Value::Boolean(b)) => a.cmp(b),
674 (Value::Node(a), Value::Node(b)) => a.cmp(b),
675 (Value::Edge(a), Value::Edge(b)) => a.cmp(b),
676 (Value::Uri(a), Value::Uri(b)) => a.cmp(b),
677 (Value::Null, Value::Null) => std::cmp::Ordering::Equal,
678 _ => {
680 let type_order = |v: &Value| -> u8 {
681 match v {
682 Value::Null => 0,
683 Value::Boolean(_) => 1,
684 Value::Integer(_) => 2,
685 Value::Float(_) => 3,
686 Value::String(_) => 4,
687 Value::Node(_) => 5,
688 Value::Edge(_) => 6,
689 Value::Uri(_) => 7,
690 }
691 };
692 type_order(a).cmp(&type_order(b))
693 }
694 }
695}
696
697#[derive(Debug)]
699pub struct QueryIterDistinct {
700 upstream: Box<dyn BindingIterator>,
701 seen: HashSet<u64>,
702 cancelled: bool,
703}
704
705impl QueryIterDistinct {
706 pub fn new(upstream: Box<dyn BindingIterator>) -> Self {
708 Self {
709 upstream,
710 seen: HashSet::new(),
711 cancelled: false,
712 }
713 }
714
715 fn hash_binding(binding: &Binding) -> u64 {
717 use std::hash::{Hash, Hasher};
718 let mut hasher = std::collections::hash_map::DefaultHasher::new();
719 binding.hash(&mut hasher);
720 hasher.finish()
721 }
722}
723
724impl BindingIterator for QueryIterDistinct {
725 fn next_binding(&mut self) -> IterResult {
726 if self.cancelled {
727 return Err(IterError::Cancelled);
728 }
729
730 loop {
731 match self.upstream.next_binding()? {
732 Some(binding) => {
733 let hash = Self::hash_binding(&binding);
734 if self.seen.insert(hash) {
735 return Ok(Some(binding));
736 }
737 }
739 None => return Ok(None),
740 }
741 }
742 }
743
744 fn vars(&self) -> Vec<Var> {
745 self.upstream.vars()
746 }
747
748 fn cancel(&mut self) {
749 self.cancelled = true;
750 self.upstream.cancel();
751 }
752}
753
754pub struct QueryIter {
756 inner: Box<dyn BindingIterator>,
757}
758
759impl QueryIter {
760 pub fn new(inner: Box<dyn BindingIterator>) -> Self {
762 Self { inner }
763 }
764
765 pub fn vars(&self) -> Vec<Var> {
767 self.inner.vars()
768 }
769
770 pub fn cancel(&mut self) {
772 self.inner.cancel();
773 }
774}
775
776impl Iterator for QueryIter {
777 type Item = Result<Binding, IterError>;
778
779 fn next(&mut self) -> Option<Self::Item> {
780 match self.inner.next_binding() {
781 Ok(Some(binding)) => Some(Ok(binding)),
782 Ok(None) => None,
783 Err(e) => Some(Err(e)),
784 }
785 }
786}
787
788#[cfg(test)]
789mod tests {
790 use super::*;
791 use crate::storage::query::engine::binding::BindingBuilder;
792
793 fn make_binding(x: i64) -> Binding {
794 BindingBuilder::new()
795 .add_named("x", Value::Integer(x))
796 .build()
797 }
798
799 #[test]
800 fn test_base_iterator() {
801 let bindings = vec![make_binding(1), make_binding(2), make_binding(3)];
802 let mut iter = QueryIterBase::new(bindings);
803
804 assert!(iter.has_next());
805 assert!(iter.next_binding().unwrap().is_some());
806 assert!(iter.next_binding().unwrap().is_some());
807 assert!(iter.next_binding().unwrap().is_some());
808 assert!(iter.next_binding().unwrap().is_none());
809 }
810
811 #[test]
812 fn test_filter_iterator() {
813 let bindings = vec![make_binding(1), make_binding(2), make_binding(3)];
814 let base = Box::new(QueryIterBase::new(bindings));
815
816 let mut iter = QueryIterFilter::new(base, |b| {
817 b.get(&Var::new("x"))
818 .and_then(|v| v.as_integer())
819 .map(|i| i > 1)
820 .unwrap_or(false)
821 });
822
823 let b1 = iter.next_binding().unwrap().unwrap();
825 assert_eq!(b1.get(&Var::new("x")), Some(&Value::Integer(2)));
826
827 let b2 = iter.next_binding().unwrap().unwrap();
828 assert_eq!(b2.get(&Var::new("x")), Some(&Value::Integer(3)));
829
830 assert!(iter.next_binding().unwrap().is_none());
831 }
832
833 #[test]
834 fn test_slice_iterator() {
835 let bindings: Vec<_> = (1..=10).map(make_binding).collect();
836 let base = Box::new(QueryIterBase::new(bindings));
837
838 let mut iter = QueryIterSlice::new(base, 2, Some(3));
840
841 let b1 = iter.next_binding().unwrap().unwrap();
842 assert_eq!(b1.get(&Var::new("x")), Some(&Value::Integer(3)));
843
844 let b2 = iter.next_binding().unwrap().unwrap();
845 assert_eq!(b2.get(&Var::new("x")), Some(&Value::Integer(4)));
846
847 let b3 = iter.next_binding().unwrap().unwrap();
848 assert_eq!(b3.get(&Var::new("x")), Some(&Value::Integer(5)));
849
850 assert!(iter.next_binding().unwrap().is_none());
851 }
852
853 #[test]
854 fn test_project_iterator() {
855 let binding = BindingBuilder::new()
856 .add_named("x", Value::Integer(1))
857 .add_named("y", Value::Integer(2))
858 .add_named("z", Value::Integer(3))
859 .build();
860
861 let base = Box::new(QueryIterBase::single(binding));
862 let mut iter = QueryIterProject::new(base, vec![Var::new("x"), Var::new("z")]);
863
864 let result = iter.next_binding().unwrap().unwrap();
865 assert!(result.contains(&Var::new("x")));
866 assert!(!result.contains(&Var::new("y")));
867 assert!(result.contains(&Var::new("z")));
868 }
869
870 #[test]
871 fn test_union_iterator() {
872 let iter1 = Box::new(QueryIterBase::new(vec![make_binding(1), make_binding(2)]));
873 let iter2 = Box::new(QueryIterBase::new(vec![make_binding(3), make_binding(4)]));
874
875 let mut union = QueryIterUnion::new(vec![iter1, iter2]);
876
877 let mut results = Vec::new();
878 while let Some(b) = union.next_binding().unwrap() {
879 results.push(b.get(&Var::new("x")).unwrap().as_integer().unwrap());
880 }
881
882 assert_eq!(results, vec![1, 2, 3, 4]);
883 }
884
885 #[test]
886 fn test_sort_iterator() {
887 let bindings = vec![make_binding(3), make_binding(1), make_binding(2)];
888 let base = Box::new(QueryIterBase::new(bindings));
889
890 let mut iter = QueryIterSort::new(base, vec![SortKey::asc(Var::new("x"))]);
891
892 let mut results = Vec::new();
893 while let Some(b) = iter.next_binding().unwrap() {
894 results.push(b.get(&Var::new("x")).unwrap().as_integer().unwrap());
895 }
896
897 assert_eq!(results, vec![1, 2, 3]);
898 }
899
900 #[test]
901 fn test_distinct_iterator() {
902 let bindings = vec![
903 make_binding(1),
904 make_binding(2),
905 make_binding(1),
906 make_binding(3),
907 make_binding(2),
908 ];
909 let base = Box::new(QueryIterBase::new(bindings));
910
911 let mut iter = QueryIterDistinct::new(base);
912
913 let mut results = Vec::new();
914 while let Some(b) = iter.next_binding().unwrap() {
915 results.push(b.get(&Var::new("x")).unwrap().as_integer().unwrap());
916 }
917
918 assert_eq!(results, vec![1, 2, 3]);
919 }
920
921 #[test]
922 fn test_cancel_iterator() {
923 let bindings: Vec<_> = (1..=100).map(make_binding).collect();
924 let mut iter = QueryIterBase::new(bindings);
925
926 iter.next_binding().unwrap();
928 iter.next_binding().unwrap();
929
930 iter.cancel();
932
933 assert!(matches!(iter.next_binding(), Err(IterError::Cancelled)));
935 }
936
937 #[test]
938 fn test_query_iter_wrapper() {
939 let bindings = vec![make_binding(1), make_binding(2)];
940 let base = Box::new(QueryIterBase::new(bindings));
941
942 let iter = QueryIter::new(base);
943 let results: Vec<_> = iter.collect();
944
945 assert_eq!(results.len(), 2);
946 assert!(results.iter().all(|r| r.is_ok()));
947 }
948
949 #[derive(Debug)]
956 struct InfiniteScan {
957 n: i64,
958 }
959
960 impl BindingIterator for InfiniteScan {
961 fn next_binding(&mut self) -> IterResult {
962 self.n += 1;
963 Ok(Some(make_binding(self.n)))
964 }
965
966 fn vars(&self) -> Vec<Var> {
967 vec![Var::new("x")]
968 }
969
970 fn cancel(&mut self) {}
971 }
972
973 #[test]
974 fn shared_token_cancels_scan() {
975 let token = CancelToken::new();
976 let bindings: Vec<_> = (1..=1000).map(make_binding).collect();
977 let mut scan = QueryIterBase::new(bindings).with_cancel(token.clone());
978
979 assert!(scan.next_binding().unwrap().is_some());
980 token.cancel();
981 assert!(matches!(scan.next_binding(), Err(IterError::Cancelled)));
984 }
985
986 #[test]
987 fn shared_token_cancels_filter_within_budget() {
988 use std::time::{Duration, Instant};
989
990 let token = CancelToken::new();
991 let upstream = Box::new(InfiniteScan { n: 0 });
994 let mut filter = QueryIterFilter::new(upstream, |_| false).with_cancel(token.clone());
995
996 let canceller = token.clone();
997 std::thread::spawn(move || {
998 std::thread::sleep(Duration::from_millis(20));
999 canceller.cancel();
1000 });
1001
1002 let start = Instant::now();
1003 let result = filter.next_binding();
1004 let elapsed = start.elapsed();
1005
1006 assert!(matches!(result, Err(IterError::Cancelled)));
1007 assert!(
1010 elapsed < Duration::from_secs(1),
1011 "cancel took too long to take effect: {elapsed:?}"
1012 );
1013 }
1014
1015 #[test]
1016 fn shared_token_cancels_join_within_budget() {
1017 use std::time::{Duration, Instant};
1018
1019 let token = CancelToken::new();
1020 let left = Box::new(
1024 QueryIterFilter::new(Box::new(InfiniteScan { n: 0 }), |_| false)
1025 .with_cancel(token.clone()),
1026 );
1027 let mut join = QueryIterJoin::new(
1028 left,
1029 || Box::new(QueryIterBase::empty()),
1030 vec![Var::new("y")],
1031 )
1032 .with_cancel(token.clone());
1033
1034 let canceller = token.clone();
1035 std::thread::spawn(move || {
1036 std::thread::sleep(Duration::from_millis(20));
1037 canceller.cancel();
1038 });
1039
1040 let start = Instant::now();
1041 let result = join.next_binding();
1042 let elapsed = start.elapsed();
1043
1044 assert!(matches!(result, Err(IterError::Cancelled)));
1045 assert!(
1046 elapsed < Duration::from_secs(1),
1047 "join cancel took too long: {elapsed:?}"
1048 );
1049 }
1050
1051 #[test]
1052 fn cancellation_propagates_through_aggregate_consumer() {
1053 let token = CancelToken::new();
1059 let upstream: Box<dyn BindingIterator> = Box::new(
1060 QueryIterFilter::new(Box::new(InfiniteScan { n: 0 }), |_| false)
1061 .with_cancel(token.clone()),
1062 );
1063
1064 fn count_all(mut it: Box<dyn BindingIterator>) -> Result<u64, IterError> {
1066 let mut n = 0;
1067 while it.next_binding()?.is_some() {
1068 n += 1;
1069 }
1070 Ok(n)
1071 }
1072
1073 token.cancel();
1074 assert!(matches!(count_all(upstream), Err(IterError::Cancelled)));
1075 }
1076}