1use std::ops::Deref;
2
3use crate::graphrecord::{
4 attribute::PyGraphRecordAttribute,
5 errors::PyGraphRecordError,
6 querying::values::{
7 PyEdgeMultipleValuesWithIndexGroupOperand, PyEdgeMultipleValuesWithIndexOperand,
8 PyNodeMultipleValuesWithIndexGroupOperand, PyNodeMultipleValuesWithIndexOperand,
9 },
10};
11use graphrecords_core::{
12 errors::GraphRecordError,
13 graphrecord::{
14 GraphRecordAttribute,
15 querying::{
16 DeepClone,
17 attributes::{
18 AttributesTreeOperand, MultipleAttributesComparisonOperand,
19 MultipleAttributesWithIndexOperand, MultipleAttributesWithoutIndexOperand,
20 SingleAttributeComparisonOperand, SingleAttributeWithIndexOperand,
21 SingleAttributeWithoutIndexOperand,
22 },
23 edges::EdgeOperand,
24 group_by::GroupOperand,
25 nodes::NodeOperand,
26 wrapper::Wrapper,
27 },
28 },
29};
30use pyo3::{
31 Borrowed, Bound, FromPyObject, PyAny, PyErr, PyResult, pyclass, pymethods,
32 types::{PyAnyMethods, PyFunction},
33};
34
35#[repr(transparent)]
36pub struct PySingleAttributeComparisonOperand(SingleAttributeComparisonOperand);
37
38impl From<SingleAttributeComparisonOperand> for PySingleAttributeComparisonOperand {
39 fn from(operand: SingleAttributeComparisonOperand) -> Self {
40 Self(operand)
41 }
42}
43
44impl From<PySingleAttributeComparisonOperand> for SingleAttributeComparisonOperand {
45 fn from(operand: PySingleAttributeComparisonOperand) -> Self {
46 operand.0
47 }
48}
49
50impl Deref for PySingleAttributeComparisonOperand {
51 type Target = SingleAttributeComparisonOperand;
52
53 fn deref(&self) -> &Self::Target {
54 &self.0
55 }
56}
57
58impl FromPyObject<'_, '_> for PySingleAttributeComparisonOperand {
59 type Error = PyErr;
60
61 fn extract(ob: Borrowed<'_, '_, PyAny>) -> PyResult<Self> {
62 match ob.extract::<PyGraphRecordAttribute>() {
63 Ok(attribute) => {
64 Ok(SingleAttributeComparisonOperand::Attribute(attribute.into()).into())
65 }
66 _ => match ob.extract::<PyNodeSingleAttributeWithIndexOperand>() {
67 Ok(operand) => Ok(Self(operand.0.into())),
68 _ => match ob.extract::<PyNodeSingleAttributeWithoutIndexOperand>() {
69 Ok(operand) => Ok(Self(operand.0.into())),
70 _ => match ob.extract::<PyEdgeSingleAttributeWithIndexOperand>() {
71 Ok(operand) => Ok(Self(operand.0.into())),
72 _ => match ob.extract::<PyEdgeSingleAttributeWithoutIndexOperand>() {
73 Ok(operand) => Ok(Self(operand.0.into())),
74 _ => Err(PyGraphRecordError::from(GraphRecordError::ConversionError(
75 format!(
76 "Failed to convert {} into GraphRecordValue or SingleValueOperand",
77 ob.to_owned()
78 ),
79 ))
80 .into()),
81 },
82 },
83 },
84 },
85 }
86 }
87}
88
89#[repr(transparent)]
90pub struct PyMultipleAttributesComparisonOperand(MultipleAttributesComparisonOperand);
91
92impl From<MultipleAttributesComparisonOperand> for PyMultipleAttributesComparisonOperand {
93 fn from(operand: MultipleAttributesComparisonOperand) -> Self {
94 Self(operand)
95 }
96}
97
98impl From<PyMultipleAttributesComparisonOperand> for MultipleAttributesComparisonOperand {
99 fn from(operand: PyMultipleAttributesComparisonOperand) -> Self {
100 operand.0
101 }
102}
103
104impl Deref for PyMultipleAttributesComparisonOperand {
105 type Target = MultipleAttributesComparisonOperand;
106
107 fn deref(&self) -> &Self::Target {
108 &self.0
109 }
110}
111
112impl FromPyObject<'_, '_> for PyMultipleAttributesComparisonOperand {
113 type Error = PyErr;
114
115 fn extract(ob: Borrowed<'_, '_, PyAny>) -> PyResult<Self> {
116 match ob.extract::<Vec<PyGraphRecordAttribute>>() {
117 Ok(values) => Ok(MultipleAttributesComparisonOperand::Attributes(
118 values.into_iter().map(GraphRecordAttribute::from).collect(),
119 )
120 .into()),
121 _ => {
122 match ob.extract::<PyNodeMultipleAttributesWithIndexOperand>() {
123 Ok(operand) => Ok(Self(operand.0.into())),
124 _ => {
125 match ob.extract::<PyNodeMultipleAttributesWithoutIndexOperand>() {
126 Ok(operand) => Ok(Self(operand.0.into())),
127 _ => match ob.extract::<PyEdgeMultipleAttributesWithIndexOperand>() {
128 Ok(operand) => Ok(Self(operand.0.into())),
129 _ => {
130 match ob.extract::<PyEdgeMultipleAttributesWithoutIndexOperand>() { Ok(operand) => {
131 Ok(Self(operand.0.into()))
132 } _ => {
133 Err(
134 PyGraphRecordError::from(GraphRecordError::ConversionError(format!(
135 "Failed to convert {} into List[GraphRecordAttribute] or MultipleAttributesOperand",
136 ob.to_owned()
137 )))
138 .into(),
139 )
140 }}
141 }
142 },
143 }
144 }
145 }
146 }
147 }
148 }
149}
150
151macro_rules! implement_attributes_tree_operand {
152 ($name:ident, $generic:ty, $multiple_attributes_operand:ty) => {
153 #[pyclass(frozen)]
154 #[repr(transparent)]
155 #[derive(Clone)]
156 pub struct $name(Wrapper<AttributesTreeOperand<$generic>>);
157
158 impl From<Wrapper<AttributesTreeOperand<$generic>>> for $name {
159 fn from(operand: Wrapper<AttributesTreeOperand<$generic>>) -> Self {
160 Self(operand)
161 }
162 }
163
164 impl From<$name> for Wrapper<AttributesTreeOperand<$generic>> {
165 fn from(operand: $name) -> Self {
166 operand.0
167 }
168 }
169
170 impl Deref for $name {
171 type Target = Wrapper<AttributesTreeOperand<$generic>>;
172
173 fn deref(&self) -> &Self::Target {
174 &self.0
175 }
176 }
177
178 #[pymethods]
179 impl $name {
180 pub fn max(&self) -> $multiple_attributes_operand {
181 self.0.max().into()
182 }
183
184 pub fn min(&self) -> $multiple_attributes_operand {
185 self.0.min().into()
186 }
187
188 pub fn count(&self) -> $multiple_attributes_operand {
189 self.0.count().into()
190 }
191
192 pub fn sum(&self) -> $multiple_attributes_operand {
193 self.0.sum().into()
194 }
195
196 pub fn random(&self) -> $multiple_attributes_operand {
197 self.0.random().into()
198 }
199
200 pub fn greater_than(&self, attribute: PySingleAttributeComparisonOperand) {
201 self.0.greater_than(attribute);
202 }
203
204 pub fn greater_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
205 self.0.greater_than_or_equal_to(attribute);
206 }
207
208 pub fn less_than(&self, attribute: PySingleAttributeComparisonOperand) {
209 self.0.less_than(attribute);
210 }
211
212 pub fn less_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
213 self.0.less_than_or_equal_to(attribute);
214 }
215
216 pub fn equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
217 self.0.equal_to(attribute);
218 }
219
220 pub fn not_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
221 self.0.not_equal_to(attribute);
222 }
223
224 pub fn starts_with(&self, attribute: PySingleAttributeComparisonOperand) {
225 self.0.starts_with(attribute);
226 }
227
228 pub fn ends_with(&self, attribute: PySingleAttributeComparisonOperand) {
229 self.0.ends_with(attribute);
230 }
231
232 pub fn contains(&self, attribute: PySingleAttributeComparisonOperand) {
233 self.0.contains(attribute);
234 }
235
236 pub fn is_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
237 self.0.is_in(attributes);
238 }
239
240 pub fn is_not_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
241 self.0.is_not_in(attributes);
242 }
243
244 pub fn add(&self, attribute: PySingleAttributeComparisonOperand) {
245 self.0.add(attribute);
246 }
247
248 pub fn sub(&self, attribute: PySingleAttributeComparisonOperand) {
249 self.0.sub(attribute);
250 }
251
252 pub fn mul(&self, attribute: PySingleAttributeComparisonOperand) {
253 self.0.mul(attribute);
254 }
255
256 pub fn pow(&self, attribute: PySingleAttributeComparisonOperand) {
257 self.0.pow(attribute);
258 }
259
260 pub fn r#mod(&self, attribute: PySingleAttributeComparisonOperand) {
261 self.0.r#mod(attribute);
262 }
263
264 pub fn abs(&self) {
265 self.0.abs();
266 }
267
268 pub fn trim(&self) {
269 self.0.trim();
270 }
271
272 pub fn trim_start(&self) {
273 self.0.trim_start();
274 }
275
276 pub fn trim_end(&self) {
277 self.0.trim_end();
278 }
279
280 pub fn lowercase(&self) {
281 self.0.lowercase();
282 }
283
284 pub fn uppercase(&self) {
285 self.0.uppercase();
286 }
287
288 pub fn slice(&self, start: usize, end: usize) {
289 self.0.slice(start, end);
290 }
291
292 pub fn is_string(&self) {
293 self.0.is_string();
294 }
295
296 pub fn is_int(&self) {
297 self.0.is_int();
298 }
299
300 pub fn is_max(&self) {
301 self.0.is_max();
302 }
303
304 pub fn is_min(&self) {
305 self.0.is_min();
306 }
307
308 pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
309 self.0.either_or(
310 |operand| {
311 either
312 .call1(($name::from(operand.clone()),))
313 .expect("Call must succeed");
314 },
315 |operand| {
316 or.call1(($name::from(operand.clone()),))
317 .expect("Call must succeed");
318 },
319 );
320 }
321
322 pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
323 self.0.exclude(|operand| {
324 query
325 .call1(($name::from(operand.clone()),))
326 .expect("Call must succeed");
327 });
328 }
329
330 pub fn deep_clone(&self) -> $name {
331 self.0.deep_clone().into()
332 }
333 }
334 };
335}
336
337implement_attributes_tree_operand!(
338 PyNodeAttributesTreeOperand,
339 NodeOperand,
340 PyNodeMultipleAttributesWithIndexOperand
341);
342implement_attributes_tree_operand!(
343 PyEdgeAttributesTreeOperand,
344 EdgeOperand,
345 PyEdgeMultipleAttributesWithIndexOperand
346);
347
348macro_rules! implement_attributes_tree_group_operand {
349 ($name:ident, $ungrouped_name:ident, $generic:ty, $multiple_attributes_operand:ty) => {
350 #[pyclass(frozen)]
351 #[repr(transparent)]
352 #[derive(Clone)]
353 pub struct $name(Wrapper<GroupOperand<AttributesTreeOperand<$generic>>>);
354
355 impl From<Wrapper<GroupOperand<AttributesTreeOperand<$generic>>>> for $name {
356 fn from(operand: Wrapper<GroupOperand<AttributesTreeOperand<$generic>>>) -> Self {
357 Self(operand)
358 }
359 }
360
361 impl From<$name> for Wrapper<GroupOperand<AttributesTreeOperand<$generic>>> {
362 fn from(operand: $name) -> Self {
363 operand.0
364 }
365 }
366
367 impl Deref for $name {
368 type Target = Wrapper<GroupOperand<AttributesTreeOperand<$generic>>>;
369
370 fn deref(&self) -> &Self::Target {
371 &self.0
372 }
373 }
374
375 #[pymethods]
376 impl $name {
377 pub fn max(&self) -> $multiple_attributes_operand {
378 self.0.max().into()
379 }
380
381 pub fn min(&self) -> $multiple_attributes_operand {
382 self.0.min().into()
383 }
384
385 pub fn count(&self) -> $multiple_attributes_operand {
386 self.0.count().into()
387 }
388
389 pub fn sum(&self) -> $multiple_attributes_operand {
390 self.0.sum().into()
391 }
392
393 pub fn random(&self) -> $multiple_attributes_operand {
394 self.0.random().into()
395 }
396
397 pub fn greater_than(&self, attribute: PySingleAttributeComparisonOperand) {
398 self.0.greater_than(attribute);
399 }
400
401 pub fn greater_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
402 self.0.greater_than_or_equal_to(attribute);
403 }
404
405 pub fn less_than(&self, attribute: PySingleAttributeComparisonOperand) {
406 self.0.less_than(attribute);
407 }
408
409 pub fn less_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
410 self.0.less_than_or_equal_to(attribute);
411 }
412
413 pub fn equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
414 self.0.equal_to(attribute);
415 }
416
417 pub fn not_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
418 self.0.not_equal_to(attribute);
419 }
420
421 pub fn starts_with(&self, attribute: PySingleAttributeComparisonOperand) {
422 self.0.starts_with(attribute);
423 }
424
425 pub fn ends_with(&self, attribute: PySingleAttributeComparisonOperand) {
426 self.0.ends_with(attribute);
427 }
428
429 pub fn contains(&self, attribute: PySingleAttributeComparisonOperand) {
430 self.0.contains(attribute);
431 }
432
433 pub fn is_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
434 self.0.is_in(attributes);
435 }
436
437 pub fn is_not_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
438 self.0.is_not_in(attributes);
439 }
440
441 pub fn add(&self, attribute: PySingleAttributeComparisonOperand) {
442 self.0.add(attribute);
443 }
444
445 pub fn sub(&self, attribute: PySingleAttributeComparisonOperand) {
446 self.0.sub(attribute);
447 }
448
449 pub fn mul(&self, attribute: PySingleAttributeComparisonOperand) {
450 self.0.mul(attribute);
451 }
452
453 pub fn pow(&self, attribute: PySingleAttributeComparisonOperand) {
454 self.0.pow(attribute);
455 }
456
457 pub fn r#mod(&self, attribute: PySingleAttributeComparisonOperand) {
458 self.0.r#mod(attribute);
459 }
460
461 pub fn abs(&self) {
462 self.0.abs();
463 }
464
465 pub fn trim(&self) {
466 self.0.trim();
467 }
468
469 pub fn trim_start(&self) {
470 self.0.trim_start();
471 }
472
473 pub fn trim_end(&self) {
474 self.0.trim_end();
475 }
476
477 pub fn lowercase(&self) {
478 self.0.lowercase();
479 }
480
481 pub fn uppercase(&self) {
482 self.0.uppercase();
483 }
484
485 pub fn slice(&self, start: usize, end: usize) {
486 self.0.slice(start, end);
487 }
488
489 pub fn is_string(&self) {
490 self.0.is_string();
491 }
492
493 pub fn is_int(&self) {
494 self.0.is_int();
495 }
496
497 pub fn is_max(&self) {
498 self.0.is_max();
499 }
500
501 pub fn is_min(&self) {
502 self.0.is_min();
503 }
504
505 pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
506 self.0.either_or(
507 |operand| {
508 either
509 .call1(($ungrouped_name::from(operand.clone()),))
510 .expect("Call must succeed");
511 },
512 |operand| {
513 or.call1(($ungrouped_name::from(operand.clone()),))
514 .expect("Call must succeed");
515 },
516 );
517 }
518
519 pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
520 self.0.exclude(|operand| {
521 query
522 .call1(($ungrouped_name::from(operand.clone()),))
523 .expect("Call must succeed");
524 });
525 }
526
527 pub fn ungroup(&self) -> $ungrouped_name {
528 self.0.ungroup().into()
529 }
530
531 pub fn deep_clone(&self) -> $name {
532 self.0.deep_clone().into()
533 }
534 }
535 };
536}
537
538implement_attributes_tree_group_operand!(
539 PyNodeAttributesTreeGroupOperand,
540 PyNodeAttributesTreeOperand,
541 NodeOperand,
542 PyNodeMultipleAttributesWithIndexGroupOperand
543);
544implement_attributes_tree_group_operand!(
545 PyEdgeAttributesTreeGroupOperand,
546 PyEdgeAttributesTreeOperand,
547 EdgeOperand,
548 PyEdgeMultipleAttributesWithIndexGroupOperand
549);
550
551macro_rules! implement_multiple_attributes_operand {
552 ($name:ident, $kind:ident, $generic:ty, $py_single_attribute_with_index_operand:ty, $py_single_attribute_without_index_operand:ty) => {
553 #[pyclass(frozen)]
554 #[repr(transparent)]
555 #[derive(Clone)]
556 pub struct $name(Wrapper<$kind<$generic>>);
557
558 impl From<Wrapper<$kind<$generic>>> for $name {
559 fn from(operand: Wrapper<$kind<$generic>>) -> Self {
560 Self(operand)
561 }
562 }
563
564 impl From<$name> for Wrapper<$kind<$generic>> {
565 fn from(operand: $name) -> Self {
566 operand.0
567 }
568 }
569
570 impl Deref for $name {
571 type Target = Wrapper<$kind<$generic>>;
572
573 fn deref(&self) -> &Self::Target {
574 &self.0
575 }
576 }
577
578 #[pymethods]
579 impl $name {
580 pub fn max(&self) -> $py_single_attribute_with_index_operand {
581 self.0.max().into()
582 }
583
584 pub fn min(&self) -> $py_single_attribute_with_index_operand {
585 self.0.min().into()
586 }
587
588 pub fn count(&self) -> $py_single_attribute_without_index_operand {
589 self.0.count().into()
590 }
591
592 pub fn sum(&self) -> $py_single_attribute_without_index_operand {
593 self.0.sum().into()
594 }
595
596 pub fn random(&self) -> $py_single_attribute_with_index_operand {
597 self.0.random().into()
598 }
599
600 pub fn greater_than(&self, attribute: PySingleAttributeComparisonOperand) {
601 self.0.greater_than(attribute);
602 }
603
604 pub fn greater_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
605 self.0.greater_than_or_equal_to(attribute);
606 }
607
608 pub fn less_than(&self, attribute: PySingleAttributeComparisonOperand) {
609 self.0.less_than(attribute);
610 }
611
612 pub fn less_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
613 self.0.less_than_or_equal_to(attribute);
614 }
615
616 pub fn equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
617 self.0.equal_to(attribute);
618 }
619
620 pub fn not_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
621 self.0.not_equal_to(attribute);
622 }
623
624 pub fn starts_with(&self, attribute: PySingleAttributeComparisonOperand) {
625 self.0.starts_with(attribute);
626 }
627
628 pub fn ends_with(&self, attribute: PySingleAttributeComparisonOperand) {
629 self.0.ends_with(attribute);
630 }
631
632 pub fn contains(&self, attribute: PySingleAttributeComparisonOperand) {
633 self.0.contains(attribute);
634 }
635
636 pub fn is_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
637 self.0.is_in(attributes);
638 }
639
640 pub fn is_not_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
641 self.0.is_not_in(attributes);
642 }
643
644 pub fn add(&self, attribute: PySingleAttributeComparisonOperand) {
645 self.0.add(attribute);
646 }
647
648 pub fn sub(&self, attribute: PySingleAttributeComparisonOperand) {
649 self.0.sub(attribute);
650 }
651
652 pub fn mul(&self, attribute: PySingleAttributeComparisonOperand) {
653 self.0.mul(attribute);
654 }
655
656 pub fn pow(&self, attribute: PySingleAttributeComparisonOperand) {
657 self.0.pow(attribute);
658 }
659
660 pub fn r#mod(&self, attribute: PySingleAttributeComparisonOperand) {
661 self.0.r#mod(attribute);
662 }
663
664 pub fn abs(&self) {
665 self.0.abs();
666 }
667
668 pub fn trim(&self) {
669 self.0.trim();
670 }
671
672 pub fn trim_start(&self) {
673 self.0.trim_start();
674 }
675
676 pub fn trim_end(&self) {
677 self.0.trim_end();
678 }
679
680 pub fn lowercase(&self) {
681 self.0.lowercase();
682 }
683
684 pub fn uppercase(&self) {
685 self.0.uppercase();
686 }
687
688 pub fn slice(&self, start: usize, end: usize) {
689 self.0.slice(start, end);
690 }
691
692 pub fn is_string(&self) {
693 self.0.is_string();
694 }
695
696 pub fn is_int(&self) {
697 self.0.is_int();
698 }
699
700 pub fn is_max(&self) {
701 self.0.is_max();
702 }
703
704 pub fn is_min(&self) {
705 self.0.is_min();
706 }
707
708 pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
709 self.0.either_or(
710 |operand| {
711 either
712 .call1(($name::from(operand.clone()),))
713 .expect("Call must succeed");
714 },
715 |operand| {
716 or.call1(($name::from(operand.clone()),))
717 .expect("Call must succeed");
718 },
719 );
720 }
721
722 pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
723 self.0.exclude(|operand| {
724 query
725 .call1(($name::from(operand.clone()),))
726 .expect("Call must succeed");
727 });
728 }
729
730 pub fn deep_clone(&self) -> $name {
731 self.0.deep_clone().into()
732 }
733 }
734 };
735 ($name:ident, $kind:ident, $generic:ty, $py_single_attribute_with_index_operand:ty, $py_single_attribute_without_index_operand:ty, $py_multiple_values_operand:ty) => {
736 #[pyclass(frozen)]
737 #[repr(transparent)]
738 #[derive(Clone)]
739 pub struct $name(Wrapper<$kind<$generic>>);
740
741 impl From<Wrapper<$kind<$generic>>> for $name {
742 fn from(operand: Wrapper<$kind<$generic>>) -> Self {
743 Self(operand)
744 }
745 }
746
747 impl From<$name> for Wrapper<$kind<$generic>> {
748 fn from(operand: $name) -> Self {
749 operand.0
750 }
751 }
752
753 impl Deref for $name {
754 type Target = Wrapper<$kind<$generic>>;
755
756 fn deref(&self) -> &Self::Target {
757 &self.0
758 }
759 }
760
761 #[pymethods]
762 impl $name {
763 pub fn max(&self) -> $py_single_attribute_with_index_operand {
764 self.0.max().into()
765 }
766
767 pub fn min(&self) -> $py_single_attribute_with_index_operand {
768 self.0.min().into()
769 }
770
771 pub fn count(&self) -> $py_single_attribute_without_index_operand {
772 self.0.count().into()
773 }
774
775 pub fn sum(&self) -> $py_single_attribute_without_index_operand {
776 self.0.sum().into()
777 }
778
779 pub fn random(&self) -> $py_single_attribute_with_index_operand {
780 self.0.random().into()
781 }
782
783 pub fn greater_than(&self, attribute: PySingleAttributeComparisonOperand) {
784 self.0.greater_than(attribute);
785 }
786
787 pub fn greater_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
788 self.0.greater_than_or_equal_to(attribute);
789 }
790
791 pub fn less_than(&self, attribute: PySingleAttributeComparisonOperand) {
792 self.0.less_than(attribute);
793 }
794
795 pub fn less_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
796 self.0.less_than_or_equal_to(attribute);
797 }
798
799 pub fn equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
800 self.0.equal_to(attribute);
801 }
802
803 pub fn not_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
804 self.0.not_equal_to(attribute);
805 }
806
807 pub fn starts_with(&self, attribute: PySingleAttributeComparisonOperand) {
808 self.0.starts_with(attribute);
809 }
810
811 pub fn ends_with(&self, attribute: PySingleAttributeComparisonOperand) {
812 self.0.ends_with(attribute);
813 }
814
815 pub fn contains(&self, attribute: PySingleAttributeComparisonOperand) {
816 self.0.contains(attribute);
817 }
818
819 pub fn is_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
820 self.0.is_in(attributes);
821 }
822
823 pub fn is_not_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
824 self.0.is_not_in(attributes);
825 }
826
827 pub fn add(&self, attribute: PySingleAttributeComparisonOperand) {
828 self.0.add(attribute);
829 }
830
831 pub fn sub(&self, attribute: PySingleAttributeComparisonOperand) {
832 self.0.sub(attribute);
833 }
834
835 pub fn mul(&self, attribute: PySingleAttributeComparisonOperand) {
836 self.0.mul(attribute);
837 }
838
839 pub fn pow(&self, attribute: PySingleAttributeComparisonOperand) {
840 self.0.pow(attribute);
841 }
842
843 pub fn r#mod(&self, attribute: PySingleAttributeComparisonOperand) {
844 self.0.r#mod(attribute);
845 }
846
847 pub fn abs(&self) {
848 self.0.abs();
849 }
850
851 pub fn trim(&self) {
852 self.0.trim();
853 }
854
855 pub fn trim_start(&self) {
856 self.0.trim_start();
857 }
858
859 pub fn trim_end(&self) {
860 self.0.trim_end();
861 }
862
863 pub fn lowercase(&self) {
864 self.0.lowercase();
865 }
866
867 pub fn uppercase(&self) {
868 self.0.uppercase();
869 }
870
871 pub fn to_values(&self) -> $py_multiple_values_operand {
872 self.0.to_values().into()
873 }
874
875 pub fn slice(&self, start: usize, end: usize) {
876 self.0.slice(start, end);
877 }
878
879 pub fn is_string(&self) {
880 self.0.is_string();
881 }
882
883 pub fn is_int(&self) {
884 self.0.is_int();
885 }
886
887 pub fn is_max(&self) {
888 self.0.is_max();
889 }
890
891 pub fn is_min(&self) {
892 self.0.is_min();
893 }
894
895 pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
896 self.0.either_or(
897 |operand| {
898 either
899 .call1(($name::from(operand.clone()),))
900 .expect("Call must succeed");
901 },
902 |operand| {
903 or.call1(($name::from(operand.clone()),))
904 .expect("Call must succeed");
905 },
906 );
907 }
908
909 pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
910 self.0.exclude(|operand| {
911 query
912 .call1(($name::from(operand.clone()),))
913 .expect("Call must succeed");
914 });
915 }
916
917 pub fn deep_clone(&self) -> $name {
918 self.0.deep_clone().into()
919 }
920 }
921 };
922}
923
924implement_multiple_attributes_operand!(
925 PyNodeMultipleAttributesWithIndexOperand,
926 MultipleAttributesWithIndexOperand,
927 NodeOperand,
928 PyNodeSingleAttributeWithIndexOperand,
929 PyNodeSingleAttributeWithoutIndexOperand,
930 PyNodeMultipleValuesWithIndexOperand
931);
932implement_multiple_attributes_operand!(
933 PyNodeMultipleAttributesWithoutIndexOperand,
934 MultipleAttributesWithoutIndexOperand,
935 NodeOperand,
936 PyNodeSingleAttributeWithoutIndexOperand,
937 PyNodeSingleAttributeWithoutIndexOperand
938);
939implement_multiple_attributes_operand!(
940 PyEdgeMultipleAttributesWithIndexOperand,
941 MultipleAttributesWithIndexOperand,
942 EdgeOperand,
943 PyEdgeSingleAttributeWithIndexOperand,
944 PyEdgeSingleAttributeWithoutIndexOperand,
945 PyEdgeMultipleValuesWithIndexOperand
946);
947implement_multiple_attributes_operand!(
948 PyEdgeMultipleAttributesWithoutIndexOperand,
949 MultipleAttributesWithoutIndexOperand,
950 EdgeOperand,
951 PyEdgeSingleAttributeWithoutIndexOperand,
952 PyEdgeSingleAttributeWithoutIndexOperand
953);
954
955macro_rules! implement_multiple_attributes_grouped_operand {
956 ($name:ident, $ungrouped_name:ident, $kind:ident, $generic:ty, $py_single_attribute_with_index_operand:ty, $py_single_attribute_without_index_operand:ty, $py_multiple_values_operand:ty) => {
957 #[pyclass(frozen)]
958 #[repr(transparent)]
959 #[derive(Clone)]
960 pub struct $name(Wrapper<GroupOperand<$kind<$generic>>>);
961
962 impl From<Wrapper<GroupOperand<$kind<$generic>>>> for $name {
963 fn from(operand: Wrapper<GroupOperand<$kind<$generic>>>) -> Self {
964 Self(operand)
965 }
966 }
967
968 impl From<$name> for Wrapper<GroupOperand<$kind<$generic>>> {
969 fn from(operand: $name) -> Self {
970 operand.0
971 }
972 }
973
974 impl Deref for $name {
975 type Target = Wrapper<GroupOperand<$kind<$generic>>>;
976
977 fn deref(&self) -> &Self::Target {
978 &self.0
979 }
980 }
981
982 #[pymethods]
983 impl $name {
984 pub fn max(&self) -> $py_single_attribute_with_index_operand {
985 self.0.max().into()
986 }
987
988 pub fn min(&self) -> $py_single_attribute_with_index_operand {
989 self.0.min().into()
990 }
991
992 pub fn count(&self) -> $py_single_attribute_without_index_operand {
993 self.0.count().into()
994 }
995
996 pub fn sum(&self) -> $py_single_attribute_without_index_operand {
997 self.0.sum().into()
998 }
999
1000 pub fn random(&self) -> $py_single_attribute_with_index_operand {
1001 self.0.random().into()
1002 }
1003
1004 pub fn greater_than(&self, attribute: PySingleAttributeComparisonOperand) {
1005 self.0.greater_than(attribute);
1006 }
1007
1008 pub fn greater_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1009 self.0.greater_than_or_equal_to(attribute);
1010 }
1011
1012 pub fn less_than(&self, attribute: PySingleAttributeComparisonOperand) {
1013 self.0.less_than(attribute);
1014 }
1015
1016 pub fn less_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1017 self.0.less_than_or_equal_to(attribute);
1018 }
1019
1020 pub fn equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1021 self.0.equal_to(attribute);
1022 }
1023
1024 pub fn not_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1025 self.0.not_equal_to(attribute);
1026 }
1027
1028 pub fn starts_with(&self, attribute: PySingleAttributeComparisonOperand) {
1029 self.0.starts_with(attribute);
1030 }
1031
1032 pub fn ends_with(&self, attribute: PySingleAttributeComparisonOperand) {
1033 self.0.ends_with(attribute);
1034 }
1035
1036 pub fn contains(&self, attribute: PySingleAttributeComparisonOperand) {
1037 self.0.contains(attribute);
1038 }
1039
1040 pub fn is_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
1041 self.0.is_in(attributes);
1042 }
1043
1044 pub fn is_not_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
1045 self.0.is_not_in(attributes);
1046 }
1047
1048 pub fn add(&self, attribute: PySingleAttributeComparisonOperand) {
1049 self.0.add(attribute);
1050 }
1051
1052 pub fn sub(&self, attribute: PySingleAttributeComparisonOperand) {
1053 self.0.sub(attribute);
1054 }
1055
1056 pub fn mul(&self, attribute: PySingleAttributeComparisonOperand) {
1057 self.0.mul(attribute);
1058 }
1059
1060 pub fn pow(&self, attribute: PySingleAttributeComparisonOperand) {
1061 self.0.pow(attribute);
1062 }
1063
1064 pub fn r#mod(&self, attribute: PySingleAttributeComparisonOperand) {
1065 self.0.r#mod(attribute);
1066 }
1067
1068 pub fn abs(&self) {
1069 self.0.abs();
1070 }
1071
1072 pub fn trim(&self) {
1073 self.0.trim();
1074 }
1075
1076 pub fn trim_start(&self) {
1077 self.0.trim_start();
1078 }
1079
1080 pub fn trim_end(&self) {
1081 self.0.trim_end();
1082 }
1083
1084 pub fn lowercase(&self) {
1085 self.0.lowercase();
1086 }
1087
1088 pub fn uppercase(&self) {
1089 self.0.uppercase();
1090 }
1091
1092 pub fn to_values(&self) -> $py_multiple_values_operand {
1093 self.0.to_values().into()
1094 }
1095
1096 pub fn slice(&self, start: usize, end: usize) {
1097 self.0.slice(start, end);
1098 }
1099
1100 pub fn is_string(&self) {
1101 self.0.is_string();
1102 }
1103
1104 pub fn is_int(&self) {
1105 self.0.is_int();
1106 }
1107
1108 pub fn is_max(&self) {
1109 self.0.is_max();
1110 }
1111
1112 pub fn is_min(&self) {
1113 self.0.is_min();
1114 }
1115
1116 pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
1117 self.0.either_or(
1118 |operand| {
1119 either
1120 .call1(($ungrouped_name::from(operand.clone()),))
1121 .expect("Call must succeed");
1122 },
1123 |operand| {
1124 or.call1(($ungrouped_name::from(operand.clone()),))
1125 .expect("Call must succeed");
1126 },
1127 );
1128 }
1129
1130 pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
1131 self.0.exclude(|operand| {
1132 query
1133 .call1(($ungrouped_name::from(operand.clone()),))
1134 .expect("Call must succeed");
1135 });
1136 }
1137
1138 pub fn ungroup(&self) -> $ungrouped_name {
1139 self.0.ungroup().into()
1140 }
1141
1142 pub fn deep_clone(&self) -> $name {
1143 self.0.deep_clone().into()
1144 }
1145 }
1146 };
1147}
1148
1149implement_multiple_attributes_grouped_operand!(
1150 PyNodeMultipleAttributesWithIndexGroupOperand,
1151 PyNodeMultipleAttributesWithIndexOperand,
1152 MultipleAttributesWithIndexOperand,
1153 NodeOperand,
1154 PyNodeSingleAttributeWithIndexGroupOperand,
1155 PyNodeSingleAttributeWithoutIndexGroupOperand,
1156 PyNodeMultipleValuesWithIndexGroupOperand
1157);
1158implement_multiple_attributes_grouped_operand!(
1159 PyEdgeMultipleAttributesWithIndexGroupOperand,
1160 PyEdgeMultipleAttributesWithIndexOperand,
1161 MultipleAttributesWithIndexOperand,
1162 EdgeOperand,
1163 PyEdgeSingleAttributeWithIndexGroupOperand,
1164 PyEdgeSingleAttributeWithoutIndexGroupOperand,
1165 PyEdgeMultipleValuesWithIndexGroupOperand
1166);
1167
1168macro_rules! implement_single_attribute_operand {
1169 ($name:ident, $kind:ident, $generic:ty) => {
1170 #[pyclass(frozen)]
1171 #[repr(transparent)]
1172 #[derive(Clone)]
1173 pub struct $name(Wrapper<$kind<$generic>>);
1174
1175 impl From<Wrapper<$kind<$generic>>> for $name {
1176 fn from(operand: Wrapper<$kind<$generic>>) -> Self {
1177 Self(operand)
1178 }
1179 }
1180
1181 impl From<$name> for Wrapper<$kind<$generic>> {
1182 fn from(operand: $name) -> Self {
1183 operand.0
1184 }
1185 }
1186
1187 impl Deref for $name {
1188 type Target = Wrapper<$kind<$generic>>;
1189
1190 fn deref(&self) -> &Self::Target {
1191 &self.0
1192 }
1193 }
1194
1195 #[pymethods]
1196 impl $name {
1197 pub fn greater_than(&self, attribute: PySingleAttributeComparisonOperand) {
1198 self.0.greater_than(attribute);
1199 }
1200
1201 pub fn greater_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1202 self.0.greater_than_or_equal_to(attribute);
1203 }
1204
1205 pub fn less_than(&self, attribute: PySingleAttributeComparisonOperand) {
1206 self.0.less_than(attribute);
1207 }
1208
1209 pub fn less_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1210 self.0.less_than_or_equal_to(attribute);
1211 }
1212
1213 pub fn equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1214 self.0.equal_to(attribute);
1215 }
1216
1217 pub fn not_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1218 self.0.not_equal_to(attribute);
1219 }
1220
1221 pub fn starts_with(&self, attribute: PySingleAttributeComparisonOperand) {
1222 self.0.starts_with(attribute);
1223 }
1224
1225 pub fn ends_with(&self, attribute: PySingleAttributeComparisonOperand) {
1226 self.0.ends_with(attribute);
1227 }
1228
1229 pub fn contains(&self, attribute: PySingleAttributeComparisonOperand) {
1230 self.0.contains(attribute);
1231 }
1232
1233 pub fn is_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
1234 self.0.is_in(attributes);
1235 }
1236
1237 pub fn is_not_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
1238 self.0.is_not_in(attributes);
1239 }
1240
1241 pub fn add(&self, attribute: PySingleAttributeComparisonOperand) {
1242 self.0.add(attribute);
1243 }
1244
1245 pub fn sub(&self, attribute: PySingleAttributeComparisonOperand) {
1246 self.0.sub(attribute);
1247 }
1248
1249 pub fn mul(&self, attribute: PySingleAttributeComparisonOperand) {
1250 self.0.mul(attribute);
1251 }
1252
1253 pub fn pow(&self, attribute: PySingleAttributeComparisonOperand) {
1254 self.0.pow(attribute);
1255 }
1256
1257 pub fn r#mod(&self, attribute: PySingleAttributeComparisonOperand) {
1258 self.0.r#mod(attribute);
1259 }
1260
1261 pub fn abs(&self) {
1262 self.0.abs();
1263 }
1264
1265 pub fn trim(&self) {
1266 self.0.trim();
1267 }
1268
1269 pub fn trim_start(&self) {
1270 self.0.trim_start();
1271 }
1272
1273 pub fn trim_end(&self) {
1274 self.0.trim_end();
1275 }
1276
1277 pub fn lowercase(&self) {
1278 self.0.lowercase();
1279 }
1280
1281 pub fn uppercase(&self) {
1282 self.0.uppercase();
1283 }
1284
1285 pub fn slice(&self, start: usize, end: usize) {
1286 self.0.slice(start, end);
1287 }
1288
1289 pub fn is_string(&self) {
1290 self.0.is_string();
1291 }
1292
1293 pub fn is_int(&self) {
1294 self.0.is_int();
1295 }
1296
1297 pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
1298 self.0.either_or(
1299 |operand| {
1300 either
1301 .call1(($name::from(operand.clone()),))
1302 .expect("Call must succeed");
1303 },
1304 |operand| {
1305 or.call1(($name::from(operand.clone()),))
1306 .expect("Call must succeed");
1307 },
1308 );
1309 }
1310
1311 pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
1312 self.0.exclude(|operand| {
1313 query
1314 .call1(($name::from(operand.clone()),))
1315 .expect("Call must succeed");
1316 });
1317 }
1318
1319 pub fn deep_clone(&self) -> $name {
1320 self.0.deep_clone().into()
1321 }
1322 }
1323 };
1324}
1325
1326implement_single_attribute_operand!(
1327 PyNodeSingleAttributeWithIndexOperand,
1328 SingleAttributeWithIndexOperand,
1329 NodeOperand
1330);
1331implement_single_attribute_operand!(
1332 PyNodeSingleAttributeWithoutIndexOperand,
1333 SingleAttributeWithoutIndexOperand,
1334 NodeOperand
1335);
1336implement_single_attribute_operand!(
1337 PyEdgeSingleAttributeWithIndexOperand,
1338 SingleAttributeWithIndexOperand,
1339 EdgeOperand
1340);
1341implement_single_attribute_operand!(
1342 PyEdgeSingleAttributeWithoutIndexOperand,
1343 SingleAttributeWithoutIndexOperand,
1344 EdgeOperand
1345);
1346
1347macro_rules! implement_single_attribute_grouped_operand {
1348 ($name:ident, $ungrouped_name:ident, $ungrouped_operand_name:ident, $kind:ident, $generic:ty) => {
1349 #[pyclass(frozen)]
1350 #[repr(transparent)]
1351 #[derive(Clone)]
1352 pub struct $name(Wrapper<GroupOperand<$kind<$generic>>>);
1353
1354 impl From<Wrapper<GroupOperand<$kind<$generic>>>> for $name {
1355 fn from(operand: Wrapper<GroupOperand<$kind<$generic>>>) -> Self {
1356 Self(operand)
1357 }
1358 }
1359
1360 impl From<$name> for Wrapper<GroupOperand<$kind<$generic>>> {
1361 fn from(operand: $name) -> Self {
1362 operand.0
1363 }
1364 }
1365
1366 impl Deref for $name {
1367 type Target = Wrapper<GroupOperand<$kind<$generic>>>;
1368
1369 fn deref(&self) -> &Self::Target {
1370 &self.0
1371 }
1372 }
1373
1374 #[pymethods]
1375 impl $name {
1376 pub fn greater_than(&self, attribute: PySingleAttributeComparisonOperand) {
1377 self.0.greater_than(attribute);
1378 }
1379
1380 pub fn greater_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1381 self.0.greater_than_or_equal_to(attribute);
1382 }
1383
1384 pub fn less_than(&self, attribute: PySingleAttributeComparisonOperand) {
1385 self.0.less_than(attribute);
1386 }
1387
1388 pub fn less_than_or_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1389 self.0.less_than_or_equal_to(attribute);
1390 }
1391
1392 pub fn equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1393 self.0.equal_to(attribute);
1394 }
1395
1396 pub fn not_equal_to(&self, attribute: PySingleAttributeComparisonOperand) {
1397 self.0.not_equal_to(attribute);
1398 }
1399
1400 pub fn starts_with(&self, attribute: PySingleAttributeComparisonOperand) {
1401 self.0.starts_with(attribute);
1402 }
1403
1404 pub fn ends_with(&self, attribute: PySingleAttributeComparisonOperand) {
1405 self.0.ends_with(attribute);
1406 }
1407
1408 pub fn contains(&self, attribute: PySingleAttributeComparisonOperand) {
1409 self.0.contains(attribute);
1410 }
1411
1412 pub fn is_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
1413 self.0.is_in(attributes);
1414 }
1415
1416 pub fn is_not_in(&self, attributes: PyMultipleAttributesComparisonOperand) {
1417 self.0.is_not_in(attributes);
1418 }
1419
1420 pub fn add(&self, attribute: PySingleAttributeComparisonOperand) {
1421 self.0.add(attribute);
1422 }
1423
1424 pub fn sub(&self, attribute: PySingleAttributeComparisonOperand) {
1425 self.0.sub(attribute);
1426 }
1427
1428 pub fn mul(&self, attribute: PySingleAttributeComparisonOperand) {
1429 self.0.mul(attribute);
1430 }
1431
1432 pub fn pow(&self, attribute: PySingleAttributeComparisonOperand) {
1433 self.0.pow(attribute);
1434 }
1435
1436 pub fn r#mod(&self, attribute: PySingleAttributeComparisonOperand) {
1437 self.0.r#mod(attribute);
1438 }
1439
1440 pub fn abs(&self) {
1441 self.0.abs();
1442 }
1443
1444 pub fn trim(&self) {
1445 self.0.trim();
1446 }
1447
1448 pub fn trim_start(&self) {
1449 self.0.trim_start();
1450 }
1451
1452 pub fn trim_end(&self) {
1453 self.0.trim_end();
1454 }
1455
1456 pub fn lowercase(&self) {
1457 self.0.lowercase();
1458 }
1459
1460 pub fn uppercase(&self) {
1461 self.0.uppercase();
1462 }
1463
1464 pub fn slice(&self, start: usize, end: usize) {
1465 self.0.slice(start, end);
1466 }
1467
1468 pub fn is_string(&self) {
1469 self.0.is_string();
1470 }
1471
1472 pub fn is_int(&self) {
1473 self.0.is_int();
1474 }
1475
1476 pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
1477 self.0.either_or(
1478 |operand| {
1479 either
1480 .call1(($ungrouped_name::from(operand.clone()),))
1481 .expect("Call must succeed");
1482 },
1483 |operand| {
1484 or.call1(($ungrouped_name::from(operand.clone()),))
1485 .expect("Call must succeed");
1486 },
1487 );
1488 }
1489
1490 pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
1491 self.0.exclude(|operand| {
1492 query
1493 .call1(($ungrouped_name::from(operand.clone()),))
1494 .expect("Call must succeed");
1495 });
1496 }
1497
1498 pub fn ungroup(&self) -> $ungrouped_operand_name {
1499 self.0.ungroup().into()
1500 }
1501
1502 pub fn deep_clone(&self) -> $name {
1503 self.0.deep_clone().into()
1504 }
1505 }
1506 };
1507}
1508
1509implement_single_attribute_grouped_operand!(
1510 PyNodeSingleAttributeWithIndexGroupOperand,
1511 PyNodeSingleAttributeWithIndexOperand,
1512 PyNodeMultipleAttributesWithIndexOperand,
1513 SingleAttributeWithIndexOperand,
1514 NodeOperand
1515);
1516implement_single_attribute_grouped_operand!(
1517 PyNodeSingleAttributeWithoutIndexGroupOperand,
1518 PyNodeSingleAttributeWithoutIndexOperand,
1519 PyNodeMultipleAttributesWithoutIndexOperand,
1520 SingleAttributeWithoutIndexOperand,
1521 NodeOperand
1522);
1523implement_single_attribute_grouped_operand!(
1524 PyEdgeSingleAttributeWithIndexGroupOperand,
1525 PyEdgeSingleAttributeWithIndexOperand,
1526 PyEdgeMultipleAttributesWithIndexOperand,
1527 SingleAttributeWithIndexOperand,
1528 EdgeOperand
1529);
1530implement_single_attribute_grouped_operand!(
1531 PyEdgeSingleAttributeWithoutIndexGroupOperand,
1532 PyEdgeSingleAttributeWithoutIndexOperand,
1533 PyEdgeMultipleAttributesWithoutIndexOperand,
1534 SingleAttributeWithoutIndexOperand,
1535 EdgeOperand
1536);