1use crate::constraints::WasmFunction;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
5#[serde(tag = "name")]
6pub enum Collector {
7 #[serde(rename = "count")]
8 Count {
9 #[serde(skip_serializing_if = "Option::is_none")]
10 distinct: Option<bool>,
11 #[serde(skip_serializing_if = "Option::is_none")]
12 map: Option<WasmFunction>,
13 },
14 #[serde(rename = "sum")]
15 Sum { map: WasmFunction },
16 #[serde(rename = "average")]
17 Average { map: WasmFunction },
18 #[serde(rename = "min")]
19 Min {
20 map: WasmFunction,
21 comparator: WasmFunction,
22 },
23 #[serde(rename = "max")]
24 Max {
25 map: WasmFunction,
26 comparator: WasmFunction,
27 },
28 #[serde(rename = "toList")]
29 ToList {
30 #[serde(skip_serializing_if = "Option::is_none")]
31 map: Option<WasmFunction>,
32 },
33 #[serde(rename = "toSet")]
34 ToSet {
35 #[serde(skip_serializing_if = "Option::is_none")]
36 map: Option<WasmFunction>,
37 },
38 #[serde(rename = "compose")]
39 Compose {
40 collectors: Vec<Collector>,
41 combiner: WasmFunction,
42 },
43 #[serde(rename = "conditionally")]
44 Conditionally {
45 predicate: WasmFunction,
46 collector: Box<Collector>,
47 },
48 #[serde(rename = "collectAndThen")]
49 CollectAndThen {
50 collector: Box<Collector>,
51 mapper: WasmFunction,
52 },
53 #[serde(rename = "loadBalance")]
54 LoadBalance {
55 map: WasmFunction,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 load: Option<WasmFunction>,
58 },
59 #[serde(rename = "toSortedSet")]
60 ToSortedSet {
61 #[serde(skip_serializing_if = "Option::is_none")]
62 map: Option<WasmFunction>,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 comparator: Option<WasmFunction>,
65 },
66 #[serde(rename = "toMap")]
67 ToMap {
68 key_mapper: WasmFunction,
69 value_mapper: WasmFunction,
70 #[serde(skip_serializing_if = "Option::is_none")]
71 merge_function: Option<WasmFunction>,
72 },
73 #[serde(rename = "toSortedMap")]
74 ToSortedMap {
75 key_mapper: WasmFunction,
76 value_mapper: WasmFunction,
77 #[serde(skip_serializing_if = "Option::is_none")]
78 merge_function: Option<WasmFunction>,
79 },
80}
81
82impl Collector {
83 pub fn count() -> Self {
84 Collector::Count {
85 distinct: None,
86 map: None,
87 }
88 }
89
90 pub fn count_distinct() -> Self {
91 Collector::Count {
92 distinct: Some(true),
93 map: None,
94 }
95 }
96
97 pub fn count_with_map(map: WasmFunction) -> Self {
98 Collector::Count {
99 distinct: None,
100 map: Some(map),
101 }
102 }
103
104 pub fn sum(map: WasmFunction) -> Self {
105 Collector::Sum { map }
106 }
107
108 pub fn average(map: WasmFunction) -> Self {
109 Collector::Average { map }
110 }
111
112 pub fn min(map: WasmFunction, comparator: WasmFunction) -> Self {
113 Collector::Min { map, comparator }
114 }
115
116 pub fn max(map: WasmFunction, comparator: WasmFunction) -> Self {
117 Collector::Max { map, comparator }
118 }
119
120 pub fn to_list() -> Self {
121 Collector::ToList { map: None }
122 }
123
124 pub fn to_list_with_map(map: WasmFunction) -> Self {
125 Collector::ToList { map: Some(map) }
126 }
127
128 pub fn to_set() -> Self {
129 Collector::ToSet { map: None }
130 }
131
132 pub fn to_set_with_map(map: WasmFunction) -> Self {
133 Collector::ToSet { map: Some(map) }
134 }
135
136 pub fn compose(collectors: Vec<Collector>, combiner: WasmFunction) -> Self {
137 Collector::Compose {
138 collectors,
139 combiner,
140 }
141 }
142
143 pub fn conditionally(predicate: WasmFunction, collector: Collector) -> Self {
144 Collector::Conditionally {
145 predicate,
146 collector: Box::new(collector),
147 }
148 }
149
150 pub fn collect_and_then(collector: Collector, mapper: WasmFunction) -> Self {
151 Collector::CollectAndThen {
152 collector: Box::new(collector),
153 mapper,
154 }
155 }
156
157 pub fn load_balance(map: WasmFunction) -> Self {
158 Collector::LoadBalance { map, load: None }
159 }
160
161 pub fn load_balance_with_load(map: WasmFunction, load: WasmFunction) -> Self {
162 Collector::LoadBalance {
163 map,
164 load: Some(load),
165 }
166 }
167
168 pub fn to_sorted_set() -> Self {
170 Collector::ToSortedSet {
171 map: None,
172 comparator: None,
173 }
174 }
175
176 pub fn to_sorted_set_with_map(map: WasmFunction) -> Self {
178 Collector::ToSortedSet {
179 map: Some(map),
180 comparator: None,
181 }
182 }
183
184 pub fn to_sorted_set_with_comparator(comparator: WasmFunction) -> Self {
186 Collector::ToSortedSet {
187 map: None,
188 comparator: Some(comparator),
189 }
190 }
191
192 pub fn to_sorted_set_with_map_and_comparator(
194 map: WasmFunction,
195 comparator: WasmFunction,
196 ) -> Self {
197 Collector::ToSortedSet {
198 map: Some(map),
199 comparator: Some(comparator),
200 }
201 }
202
203 pub fn to_map(key_mapper: WasmFunction, value_mapper: WasmFunction) -> Self {
205 Collector::ToMap {
206 key_mapper,
207 value_mapper,
208 merge_function: None,
209 }
210 }
211
212 pub fn to_map_with_merge(
214 key_mapper: WasmFunction,
215 value_mapper: WasmFunction,
216 merge_function: WasmFunction,
217 ) -> Self {
218 Collector::ToMap {
219 key_mapper,
220 value_mapper,
221 merge_function: Some(merge_function),
222 }
223 }
224
225 pub fn to_sorted_map(key_mapper: WasmFunction, value_mapper: WasmFunction) -> Self {
227 Collector::ToSortedMap {
228 key_mapper,
229 value_mapper,
230 merge_function: None,
231 }
232 }
233
234 pub fn to_sorted_map_with_merge(
236 key_mapper: WasmFunction,
237 value_mapper: WasmFunction,
238 merge_function: WasmFunction,
239 ) -> Self {
240 Collector::ToSortedMap {
241 key_mapper,
242 value_mapper,
243 merge_function: Some(merge_function),
244 }
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251
252 #[test]
253 fn test_count() {
254 let collector = Collector::count();
255 match collector {
256 Collector::Count { distinct, map } => {
257 assert!(distinct.is_none());
258 assert!(map.is_none());
259 }
260 _ => panic!("Expected Count collector"),
261 }
262 }
263
264 #[test]
265 fn test_count_distinct() {
266 let collector = Collector::count_distinct();
267 match collector {
268 Collector::Count { distinct, .. } => {
269 assert_eq!(distinct, Some(true));
270 }
271 _ => panic!("Expected Count collector"),
272 }
273 }
274
275 #[test]
276 fn test_count_with_map() {
277 let collector = Collector::count_with_map(WasmFunction::new("get_id"));
278 match collector {
279 Collector::Count { map, .. } => {
280 assert!(map.is_some());
281 assert_eq!(map.unwrap().name(), "get_id");
282 }
283 _ => panic!("Expected Count collector"),
284 }
285 }
286
287 #[test]
288 fn test_sum() {
289 let collector = Collector::sum(WasmFunction::new("get_value"));
290 match collector {
291 Collector::Sum { map } => {
292 assert_eq!(map.name(), "get_value");
293 }
294 _ => panic!("Expected Sum collector"),
295 }
296 }
297
298 #[test]
299 fn test_average() {
300 let collector = Collector::average(WasmFunction::new("get_score"));
301 match collector {
302 Collector::Average { map } => {
303 assert_eq!(map.name(), "get_score");
304 }
305 _ => panic!("Expected Average collector"),
306 }
307 }
308
309 #[test]
310 fn test_min() {
311 let collector = Collector::min(
312 WasmFunction::new("get_time"),
313 WasmFunction::new("compare_time"),
314 );
315 match collector {
316 Collector::Min { map, comparator } => {
317 assert_eq!(map.name(), "get_time");
318 assert_eq!(comparator.name(), "compare_time");
319 }
320 _ => panic!("Expected Min collector"),
321 }
322 }
323
324 #[test]
325 fn test_max() {
326 let collector = Collector::max(
327 WasmFunction::new("get_priority"),
328 WasmFunction::new("compare_priority"),
329 );
330 match collector {
331 Collector::Max { map, comparator } => {
332 assert_eq!(map.name(), "get_priority");
333 assert_eq!(comparator.name(), "compare_priority");
334 }
335 _ => panic!("Expected Max collector"),
336 }
337 }
338
339 #[test]
340 fn test_to_list() {
341 let collector = Collector::to_list();
342 match collector {
343 Collector::ToList { map } => {
344 assert!(map.is_none());
345 }
346 _ => panic!("Expected ToList collector"),
347 }
348 }
349
350 #[test]
351 fn test_to_list_with_map() {
352 let collector = Collector::to_list_with_map(WasmFunction::new("get_name"));
353 match collector {
354 Collector::ToList { map } => {
355 assert!(map.is_some());
356 }
357 _ => panic!("Expected ToList collector"),
358 }
359 }
360
361 #[test]
362 fn test_to_set() {
363 let collector = Collector::to_set();
364 match collector {
365 Collector::ToSet { map } => {
366 assert!(map.is_none());
367 }
368 _ => panic!("Expected ToSet collector"),
369 }
370 }
371
372 #[test]
373 fn test_compose() {
374 let collector = Collector::compose(
375 vec![
376 Collector::count(),
377 Collector::sum(WasmFunction::new("get_value")),
378 ],
379 WasmFunction::new("combine"),
380 );
381 match collector {
382 Collector::Compose {
383 collectors,
384 combiner,
385 } => {
386 assert_eq!(collectors.len(), 2);
387 assert_eq!(combiner.name(), "combine");
388 }
389 _ => panic!("Expected Compose collector"),
390 }
391 }
392
393 #[test]
394 fn test_conditionally() {
395 let collector = Collector::conditionally(WasmFunction::new("is_valid"), Collector::count());
396 match collector {
397 Collector::Conditionally {
398 predicate,
399 collector,
400 } => {
401 assert_eq!(predicate.name(), "is_valid");
402 matches!(*collector, Collector::Count { .. });
403 }
404 _ => panic!("Expected Conditionally collector"),
405 }
406 }
407
408 #[test]
409 fn test_collect_and_then() {
410 let collector =
411 Collector::collect_and_then(Collector::count(), WasmFunction::new("to_string"));
412 match collector {
413 Collector::CollectAndThen { collector, mapper } => {
414 matches!(*collector, Collector::Count { .. });
415 assert_eq!(mapper.name(), "to_string");
416 }
417 _ => panic!("Expected CollectAndThen collector"),
418 }
419 }
420
421 #[test]
422 fn test_load_balance() {
423 let collector = Collector::load_balance(WasmFunction::new("get_employee"));
424 match collector {
425 Collector::LoadBalance { map, load } => {
426 assert_eq!(map.name(), "get_employee");
427 assert!(load.is_none());
428 }
429 _ => panic!("Expected LoadBalance collector"),
430 }
431 }
432
433 #[test]
434 fn test_load_balance_with_load() {
435 let collector = Collector::load_balance_with_load(
436 WasmFunction::new("get_employee"),
437 WasmFunction::new("get_load"),
438 );
439 match collector {
440 Collector::LoadBalance { map, load } => {
441 assert_eq!(map.name(), "get_employee");
442 assert!(load.is_some());
443 }
444 _ => panic!("Expected LoadBalance collector"),
445 }
446 }
447
448 #[test]
449 fn test_count_json_serialization() {
450 let collector = Collector::count();
451 let json = serde_json::to_string(&collector).unwrap();
452 assert!(json.contains("\"name\":\"count\""));
453
454 let parsed: Collector = serde_json::from_str(&json).unwrap();
455 assert_eq!(parsed, collector);
456 }
457
458 #[test]
459 fn test_sum_json_serialization() {
460 let collector = Collector::sum(WasmFunction::new("get_value"));
461 let json = serde_json::to_string(&collector).unwrap();
462 assert!(json.contains("\"name\":\"sum\""));
463 assert!(json.contains("\"map\":\"get_value\""));
464
465 let parsed: Collector = serde_json::from_str(&json).unwrap();
466 assert_eq!(parsed, collector);
467 }
468
469 #[test]
470 fn test_compose_json_serialization() {
471 let collector = Collector::compose(vec![Collector::count()], WasmFunction::new("wrap"));
472 let json = serde_json::to_string(&collector).unwrap();
473 assert!(json.contains("\"name\":\"compose\""));
474 assert!(json.contains("\"collectors\""));
475 assert!(json.contains("\"combiner\":\"wrap\""));
476
477 let parsed: Collector = serde_json::from_str(&json).unwrap();
478 assert_eq!(parsed, collector);
479 }
480
481 #[test]
482 fn test_conditionally_json_serialization() {
483 let collector = Collector::conditionally(WasmFunction::new("pred"), Collector::count());
484 let json = serde_json::to_string(&collector).unwrap();
485 assert!(json.contains("\"name\":\"conditionally\""));
486 assert!(json.contains("\"predicate\":\"pred\""));
487 assert!(json.contains("\"collector\""));
488
489 let parsed: Collector = serde_json::from_str(&json).unwrap();
490 assert_eq!(parsed, collector);
491 }
492
493 #[test]
494 fn test_collect_and_then_json_serialization() {
495 let collector =
496 Collector::collect_and_then(Collector::count(), WasmFunction::new("transform"));
497 let json = serde_json::to_string(&collector).unwrap();
498 assert!(json.contains("\"name\":\"collectAndThen\""));
499 assert!(json.contains("\"mapper\":\"transform\""));
500
501 let parsed: Collector = serde_json::from_str(&json).unwrap();
502 assert_eq!(parsed, collector);
503 }
504
505 #[test]
506 fn test_load_balance_json_serialization() {
507 let collector = Collector::load_balance(WasmFunction::new("get_item"));
508 let json = serde_json::to_string(&collector).unwrap();
509 assert!(json.contains("\"name\":\"loadBalance\""));
510
511 let parsed: Collector = serde_json::from_str(&json).unwrap();
512 assert_eq!(parsed, collector);
513 }
514
515 #[test]
516 fn test_nested_collectors_json() {
517 let collector = Collector::compose(
518 vec![
519 Collector::conditionally(
520 WasmFunction::new("is_valid"),
521 Collector::sum(WasmFunction::new("get_value")),
522 ),
523 Collector::collect_and_then(Collector::count(), WasmFunction::new("double")),
524 ],
525 WasmFunction::new("combine_results"),
526 );
527 let json = serde_json::to_string(&collector).unwrap();
528 let parsed: Collector = serde_json::from_str(&json).unwrap();
529 assert_eq!(parsed, collector);
530 }
531
532 #[test]
533 fn test_collector_clone() {
534 let collector = Collector::sum(WasmFunction::new("get_value"));
535 let cloned = collector.clone();
536 assert_eq!(collector, cloned);
537 }
538
539 #[test]
540 fn test_collector_debug() {
541 let collector = Collector::count();
542 let debug = format!("{:?}", collector);
543 assert!(debug.contains("Count"));
544 }
545
546 #[test]
548 fn test_to_sorted_set() {
549 let collector = Collector::to_sorted_set();
550 match collector {
551 Collector::ToSortedSet { map, comparator } => {
552 assert!(map.is_none());
553 assert!(comparator.is_none());
554 }
555 _ => panic!("Expected ToSortedSet collector"),
556 }
557 }
558
559 #[test]
560 fn test_to_sorted_set_with_map() {
561 let collector = Collector::to_sorted_set_with_map(WasmFunction::new("get_name"));
562 match collector {
563 Collector::ToSortedSet { map, comparator } => {
564 assert!(map.is_some());
565 assert_eq!(map.unwrap().name(), "get_name");
566 assert!(comparator.is_none());
567 }
568 _ => panic!("Expected ToSortedSet collector"),
569 }
570 }
571
572 #[test]
573 fn test_to_sorted_set_with_comparator() {
574 let collector = Collector::to_sorted_set_with_comparator(WasmFunction::new("compare"));
575 match collector {
576 Collector::ToSortedSet { map, comparator } => {
577 assert!(map.is_none());
578 assert!(comparator.is_some());
579 assert_eq!(comparator.unwrap().name(), "compare");
580 }
581 _ => panic!("Expected ToSortedSet collector"),
582 }
583 }
584
585 #[test]
586 fn test_to_sorted_set_with_map_and_comparator() {
587 let collector = Collector::to_sorted_set_with_map_and_comparator(
588 WasmFunction::new("get_key"),
589 WasmFunction::new("compare_keys"),
590 );
591 match collector {
592 Collector::ToSortedSet { map, comparator } => {
593 assert!(map.is_some());
594 assert!(comparator.is_some());
595 assert_eq!(map.unwrap().name(), "get_key");
596 assert_eq!(comparator.unwrap().name(), "compare_keys");
597 }
598 _ => panic!("Expected ToSortedSet collector"),
599 }
600 }
601
602 #[test]
603 fn test_to_sorted_set_json_serialization() {
604 let collector = Collector::to_sorted_set();
605 let json = serde_json::to_string(&collector).unwrap();
606 assert!(json.contains("\"name\":\"toSortedSet\""));
607
608 let parsed: Collector = serde_json::from_str(&json).unwrap();
609 assert_eq!(parsed, collector);
610 }
611
612 #[test]
613 fn test_to_sorted_set_with_comparator_json() {
614 let collector = Collector::to_sorted_set_with_comparator(WasmFunction::new("cmp"));
615 let json = serde_json::to_string(&collector).unwrap();
616 assert!(json.contains("\"comparator\":\"cmp\""));
617
618 let parsed: Collector = serde_json::from_str(&json).unwrap();
619 assert_eq!(parsed, collector);
620 }
621
622 #[test]
624 fn test_to_map() {
625 let collector =
626 Collector::to_map(WasmFunction::new("get_key"), WasmFunction::new("get_value"));
627 match collector {
628 Collector::ToMap {
629 key_mapper,
630 value_mapper,
631 merge_function,
632 } => {
633 assert_eq!(key_mapper.name(), "get_key");
634 assert_eq!(value_mapper.name(), "get_value");
635 assert!(merge_function.is_none());
636 }
637 _ => panic!("Expected ToMap collector"),
638 }
639 }
640
641 #[test]
642 fn test_to_map_with_merge() {
643 let collector = Collector::to_map_with_merge(
644 WasmFunction::new("get_key"),
645 WasmFunction::new("get_value"),
646 WasmFunction::new("merge_values"),
647 );
648 match collector {
649 Collector::ToMap {
650 key_mapper,
651 value_mapper,
652 merge_function,
653 } => {
654 assert_eq!(key_mapper.name(), "get_key");
655 assert_eq!(value_mapper.name(), "get_value");
656 assert!(merge_function.is_some());
657 assert_eq!(merge_function.unwrap().name(), "merge_values");
658 }
659 _ => panic!("Expected ToMap collector"),
660 }
661 }
662
663 #[test]
664 fn test_to_map_json_serialization() {
665 let collector = Collector::to_map(WasmFunction::new("get_k"), WasmFunction::new("get_v"));
666 let json = serde_json::to_string(&collector).unwrap();
667 assert!(json.contains("\"name\":\"toMap\""));
668 assert!(json.contains("\"key_mapper\":\"get_k\""));
669 assert!(json.contains("\"value_mapper\":\"get_v\""));
670
671 let parsed: Collector = serde_json::from_str(&json).unwrap();
672 assert_eq!(parsed, collector);
673 }
674
675 #[test]
676 fn test_to_map_with_merge_json_serialization() {
677 let collector = Collector::to_map_with_merge(
678 WasmFunction::new("k"),
679 WasmFunction::new("v"),
680 WasmFunction::new("merge"),
681 );
682 let json = serde_json::to_string(&collector).unwrap();
683 assert!(json.contains("\"merge_function\":\"merge\""));
684
685 let parsed: Collector = serde_json::from_str(&json).unwrap();
686 assert_eq!(parsed, collector);
687 }
688
689 #[test]
691 fn test_to_sorted_map() {
692 let collector =
693 Collector::to_sorted_map(WasmFunction::new("get_key"), WasmFunction::new("get_value"));
694 match collector {
695 Collector::ToSortedMap {
696 key_mapper,
697 value_mapper,
698 merge_function,
699 } => {
700 assert_eq!(key_mapper.name(), "get_key");
701 assert_eq!(value_mapper.name(), "get_value");
702 assert!(merge_function.is_none());
703 }
704 _ => panic!("Expected ToSortedMap collector"),
705 }
706 }
707
708 #[test]
709 fn test_to_sorted_map_with_merge() {
710 let collector = Collector::to_sorted_map_with_merge(
711 WasmFunction::new("get_key"),
712 WasmFunction::new("get_value"),
713 WasmFunction::new("merge"),
714 );
715 match collector {
716 Collector::ToSortedMap {
717 key_mapper,
718 value_mapper,
719 merge_function,
720 } => {
721 assert_eq!(key_mapper.name(), "get_key");
722 assert_eq!(value_mapper.name(), "get_value");
723 assert!(merge_function.is_some());
724 assert_eq!(merge_function.unwrap().name(), "merge");
725 }
726 _ => panic!("Expected ToSortedMap collector"),
727 }
728 }
729
730 #[test]
731 fn test_to_sorted_map_json_serialization() {
732 let collector = Collector::to_sorted_map(WasmFunction::new("k"), WasmFunction::new("v"));
733 let json = serde_json::to_string(&collector).unwrap();
734 assert!(json.contains("\"name\":\"toSortedMap\""));
735
736 let parsed: Collector = serde_json::from_str(&json).unwrap();
737 assert_eq!(parsed, collector);
738 }
739}