Skip to main content

graphrecords_python/graphrecord/querying/
edges.rs

1use super::{
2    PyGraphRecordAttributeCardinalityWrapper, PyGroupCardinalityWrapper,
3    attributes::PyEdgeAttributesTreeOperand, nodes::PyNodeOperand,
4};
5use crate::graphrecord::{
6    attribute::PyGraphRecordAttribute,
7    errors::PyGraphRecordError,
8    querying::{
9        attributes::PyEdgeAttributesTreeGroupOperand,
10        nodes::PyNodeGroupOperand,
11        values::{PyEdgeMultipleValuesWithIndexGroupOperand, PyEdgeMultipleValuesWithIndexOperand},
12    },
13};
14use graphrecords_core::{
15    errors::GraphRecordError,
16    graphrecord::{
17        EdgeIndex,
18        querying::{
19            DeepClone,
20            edges::{
21                self, EdgeIndexComparisonOperand, EdgeIndexOperand, EdgeIndicesComparisonOperand,
22                EdgeIndicesOperand, EdgeOperand,
23            },
24            group_by::GroupOperand,
25            wrapper::Wrapper,
26        },
27    },
28};
29use pyo3::{
30    Borrowed, Bound, FromPyObject, PyAny, PyErr, PyResult, pyclass, pymethods,
31    types::{PyAnyMethods, PyFunction},
32};
33use std::ops::Deref;
34
35#[pyclass(frozen)]
36#[derive(Clone)]
37pub enum EdgeOperandGroupDiscriminator {
38    SourceNode(),
39    TargetNode(),
40    Parallel(),
41    Attribute(PyGraphRecordAttribute),
42}
43
44impl From<EdgeOperandGroupDiscriminator> for edges::EdgeOperandGroupDiscriminator {
45    fn from(discriminator: EdgeOperandGroupDiscriminator) -> Self {
46        match discriminator {
47            EdgeOperandGroupDiscriminator::SourceNode() => Self::SourceNode,
48            EdgeOperandGroupDiscriminator::TargetNode() => Self::TargetNode,
49            EdgeOperandGroupDiscriminator::Parallel() => Self::Parallel,
50            EdgeOperandGroupDiscriminator::Attribute(attribute) => {
51                Self::Attribute(attribute.into())
52            }
53        }
54    }
55}
56
57#[pyclass(frozen)]
58#[repr(transparent)]
59pub struct PyEdgeOperand(Wrapper<EdgeOperand>);
60
61impl From<Wrapper<EdgeOperand>> for PyEdgeOperand {
62    fn from(operand: Wrapper<EdgeOperand>) -> Self {
63        Self(operand)
64    }
65}
66
67impl From<PyEdgeOperand> for Wrapper<EdgeOperand> {
68    fn from(operand: PyEdgeOperand) -> Self {
69        operand.0
70    }
71}
72
73#[pymethods]
74impl PyEdgeOperand {
75    pub fn attribute(
76        &self,
77        attribute: PyGraphRecordAttribute,
78    ) -> PyEdgeMultipleValuesWithIndexOperand {
79        self.0.attribute(attribute).into()
80    }
81
82    pub fn attributes(&self) -> PyEdgeAttributesTreeOperand {
83        self.0.attributes().into()
84    }
85
86    pub fn index(&self) -> PyEdgeIndicesOperand {
87        self.0.index().into()
88    }
89
90    pub fn in_group(&self, group: PyGroupCardinalityWrapper) {
91        self.0.in_group(group);
92    }
93
94    pub fn has_attribute(&self, attribute: PyGraphRecordAttributeCardinalityWrapper) {
95        self.0.has_attribute(attribute);
96    }
97
98    pub fn source_node(&self) -> PyNodeOperand {
99        self.0.source_node().into()
100    }
101
102    pub fn target_node(&self) -> PyNodeOperand {
103        self.0.target_node().into()
104    }
105
106    /// # Panics
107    ///
108    /// Panics if the python typing was not followed.
109    pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
110        self.0.either_or(
111            |operand| {
112                either
113                    .call1((Self::from(operand.clone()),))
114                    .expect("Call must succeed");
115            },
116            |operand| {
117                or.call1((Self::from(operand.clone()),))
118                    .expect("Call must succeed");
119            },
120        );
121    }
122
123    /// # Panics
124    ///
125    /// Panics if the python typing was not followed.
126    pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
127        self.0.exclude(|operand| {
128            query
129                .call1((Self::from(operand.clone()),))
130                .expect("Call must succeed");
131        });
132    }
133
134    pub fn group_by(&self, discriminator: EdgeOperandGroupDiscriminator) -> PyEdgeGroupOperand {
135        self.0.group_by(discriminator.into()).into()
136    }
137
138    pub fn deep_clone(&self) -> Self {
139        self.0.deep_clone().into()
140    }
141}
142
143#[pyclass(frozen)]
144#[repr(transparent)]
145pub struct PyEdgeGroupOperand(Wrapper<GroupOperand<EdgeOperand>>);
146
147impl From<Wrapper<GroupOperand<EdgeOperand>>> for PyEdgeGroupOperand {
148    fn from(operand: Wrapper<GroupOperand<EdgeOperand>>) -> Self {
149        Self(operand)
150    }
151}
152
153impl From<PyEdgeGroupOperand> for Wrapper<GroupOperand<EdgeOperand>> {
154    fn from(operand: PyEdgeGroupOperand) -> Self {
155        operand.0
156    }
157}
158
159#[pymethods]
160impl PyEdgeGroupOperand {
161    pub fn attribute(
162        &self,
163        attribute: PyGraphRecordAttribute,
164    ) -> PyEdgeMultipleValuesWithIndexGroupOperand {
165        self.0.attribute(attribute).into()
166    }
167
168    pub fn attributes(&self) -> PyEdgeAttributesTreeGroupOperand {
169        self.0.attributes().into()
170    }
171
172    pub fn index(&self) -> PyEdgeIndicesGroupOperand {
173        self.0.index().into()
174    }
175
176    pub fn in_group(&self, group: PyGroupCardinalityWrapper) {
177        self.0.in_group(group);
178    }
179
180    pub fn has_attribute(&self, attribute: PyGraphRecordAttributeCardinalityWrapper) {
181        self.0.has_attribute(attribute);
182    }
183
184    pub fn source_node(&self) -> PyNodeGroupOperand {
185        self.0.source_node().into()
186    }
187
188    pub fn target_node(&self) -> PyNodeGroupOperand {
189        self.0.target_node().into()
190    }
191
192    /// # Panics
193    ///
194    /// Panics if the python typing was not followed.
195    pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
196        self.0.either_or(
197            |operand| {
198                either
199                    .call1((PyEdgeOperand::from(operand.clone()),))
200                    .expect("Call must succeed");
201            },
202            |operand| {
203                or.call1((PyEdgeOperand::from(operand.clone()),))
204                    .expect("Call must succeed");
205            },
206        );
207    }
208
209    /// # Panics
210    ///
211    /// Panics if the python typing was not followed.
212    pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
213        self.0.exclude(|operand| {
214            query
215                .call1((PyEdgeOperand::from(operand.clone()),))
216                .expect("Call must succeed");
217        });
218    }
219
220    pub fn deep_clone(&self) -> Self {
221        self.0.deep_clone().into()
222    }
223}
224
225#[repr(transparent)]
226pub struct PyEdgeIndexComparisonOperand(EdgeIndexComparisonOperand);
227
228impl From<EdgeIndexComparisonOperand> for PyEdgeIndexComparisonOperand {
229    fn from(operand: EdgeIndexComparisonOperand) -> Self {
230        Self(operand)
231    }
232}
233
234impl From<PyEdgeIndexComparisonOperand> for EdgeIndexComparisonOperand {
235    fn from(operand: PyEdgeIndexComparisonOperand) -> Self {
236        operand.0
237    }
238}
239
240impl FromPyObject<'_, '_> for PyEdgeIndexComparisonOperand {
241    type Error = PyErr;
242
243    fn extract(ob: Borrowed<'_, '_, PyAny>) -> PyResult<Self> {
244        match ob.extract::<EdgeIndex>() {
245            Ok(index) => Ok(EdgeIndexComparisonOperand::Index(index).into()),
246            _ => match ob.extract::<PyEdgeIndexOperand>() {
247                Ok(operand) => Ok(Self(operand.0.into())),
248                _ => Err(
249                    PyGraphRecordError::from(GraphRecordError::ConversionError(format!(
250                        "Failed to convert {} into EdgeIndex or EdgeIndexOperand",
251                        ob.to_owned()
252                    )))
253                    .into(),
254                ),
255            },
256        }
257    }
258}
259
260#[repr(transparent)]
261pub struct PyEdgeIndicesComparisonOperand(EdgeIndicesComparisonOperand);
262
263impl From<EdgeIndicesComparisonOperand> for PyEdgeIndicesComparisonOperand {
264    fn from(operand: EdgeIndicesComparisonOperand) -> Self {
265        Self(operand)
266    }
267}
268
269impl From<PyEdgeIndicesComparisonOperand> for EdgeIndicesComparisonOperand {
270    fn from(operand: PyEdgeIndicesComparisonOperand) -> Self {
271        operand.0
272    }
273}
274
275impl FromPyObject<'_, '_> for PyEdgeIndicesComparisonOperand {
276    type Error = PyErr;
277
278    fn extract(ob: Borrowed<'_, '_, PyAny>) -> PyResult<Self> {
279        match ob.extract::<Vec<EdgeIndex>>() {
280            Ok(indices) => Ok(EdgeIndicesComparisonOperand::from(indices).into()),
281            _ => match ob.extract::<PyEdgeIndicesOperand>() {
282                Ok(operand) => Ok(Self(operand.0.into())),
283                _ => Err(
284                    PyGraphRecordError::from(GraphRecordError::ConversionError(format!(
285                        "Failed to convert {} into List[EdgeIndex] or EdgeIndicesOperand",
286                        ob.to_owned()
287                    )))
288                    .into(),
289                ),
290            },
291        }
292    }
293}
294
295#[pyclass(frozen)]
296#[repr(transparent)]
297#[derive(Clone)]
298pub struct PyEdgeIndicesOperand(Wrapper<EdgeIndicesOperand>);
299
300impl From<Wrapper<EdgeIndicesOperand>> for PyEdgeIndicesOperand {
301    fn from(operand: Wrapper<EdgeIndicesOperand>) -> Self {
302        Self(operand)
303    }
304}
305
306impl From<PyEdgeIndicesOperand> for Wrapper<EdgeIndicesOperand> {
307    fn from(operand: PyEdgeIndicesOperand) -> Self {
308        operand.0
309    }
310}
311
312impl Deref for PyEdgeIndicesOperand {
313    type Target = Wrapper<EdgeIndicesOperand>;
314
315    fn deref(&self) -> &Self::Target {
316        &self.0
317    }
318}
319
320#[pymethods]
321impl PyEdgeIndicesOperand {
322    pub fn max(&self) -> PyEdgeIndexOperand {
323        self.0.max().into()
324    }
325
326    pub fn min(&self) -> PyEdgeIndexOperand {
327        self.0.min().into()
328    }
329
330    pub fn count(&self) -> PyEdgeIndexOperand {
331        self.0.count().into()
332    }
333
334    pub fn sum(&self) -> PyEdgeIndexOperand {
335        self.0.sum().into()
336    }
337
338    pub fn random(&self) -> PyEdgeIndexOperand {
339        self.0.random().into()
340    }
341
342    pub fn greater_than(&self, index: PyEdgeIndexComparisonOperand) {
343        self.0.greater_than(index);
344    }
345
346    pub fn greater_than_or_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
347        self.0.greater_than_or_equal_to(index);
348    }
349
350    pub fn less_than(&self, index: PyEdgeIndexComparisonOperand) {
351        self.0.less_than(index);
352    }
353
354    pub fn less_than_or_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
355        self.0.less_than_or_equal_to(index);
356    }
357
358    pub fn equal_to(&self, index: PyEdgeIndexComparisonOperand) {
359        self.0.equal_to(index);
360    }
361
362    pub fn not_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
363        self.0.not_equal_to(index);
364    }
365
366    pub fn starts_with(&self, index: PyEdgeIndexComparisonOperand) {
367        self.0.starts_with(index);
368    }
369
370    pub fn ends_with(&self, index: PyEdgeIndexComparisonOperand) {
371        self.0.ends_with(index);
372    }
373
374    pub fn contains(&self, index: PyEdgeIndexComparisonOperand) {
375        self.0.contains(index);
376    }
377
378    pub fn is_in(&self, indices: PyEdgeIndicesComparisonOperand) {
379        self.0.is_in(indices);
380    }
381
382    pub fn is_not_in(&self, indices: PyEdgeIndicesComparisonOperand) {
383        self.0.is_not_in(indices);
384    }
385
386    pub fn add(&self, index: PyEdgeIndexComparisonOperand) {
387        self.0.add(index);
388    }
389
390    pub fn sub(&self, index: PyEdgeIndexComparisonOperand) {
391        self.0.sub(index);
392    }
393
394    pub fn mul(&self, index: PyEdgeIndexComparisonOperand) {
395        self.0.mul(index);
396    }
397
398    pub fn pow(&self, index: PyEdgeIndexComparisonOperand) {
399        self.0.pow(index);
400    }
401
402    pub fn r#mod(&self, index: PyEdgeIndexComparisonOperand) {
403        self.0.r#mod(index);
404    }
405
406    pub fn is_max(&self) {
407        self.0.is_max();
408    }
409
410    pub fn is_min(&self) {
411        self.0.is_min();
412    }
413
414    /// # Panics
415    ///
416    /// Panics if the python typing was not followed.
417    pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
418        self.0.either_or(
419            |operand| {
420                either
421                    .call1((Self::from(operand.clone()),))
422                    .expect("Call must succeed");
423            },
424            |operand| {
425                or.call1((Self::from(operand.clone()),))
426                    .expect("Call must succeed");
427            },
428        );
429    }
430
431    /// # Panics
432    ///
433    /// Panics if the python typing was not followed.
434    pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
435        self.0.exclude(|operand| {
436            query
437                .call1((Self::from(operand.clone()),))
438                .expect("Call must succeed");
439        });
440    }
441
442    pub fn deep_clone(&self) -> Self {
443        self.0.deep_clone().into()
444    }
445}
446
447#[pyclass(frozen)]
448#[repr(transparent)]
449#[derive(Clone)]
450pub struct PyEdgeIndicesGroupOperand(Wrapper<GroupOperand<EdgeIndicesOperand>>);
451
452impl From<Wrapper<GroupOperand<EdgeIndicesOperand>>> for PyEdgeIndicesGroupOperand {
453    fn from(operand: Wrapper<GroupOperand<EdgeIndicesOperand>>) -> Self {
454        Self(operand)
455    }
456}
457
458impl From<PyEdgeIndicesGroupOperand> for Wrapper<GroupOperand<EdgeIndicesOperand>> {
459    fn from(operand: PyEdgeIndicesGroupOperand) -> Self {
460        operand.0
461    }
462}
463
464impl Deref for PyEdgeIndicesGroupOperand {
465    type Target = Wrapper<GroupOperand<EdgeIndicesOperand>>;
466
467    fn deref(&self) -> &Self::Target {
468        &self.0
469    }
470}
471
472#[pymethods]
473impl PyEdgeIndicesGroupOperand {
474    pub fn max(&self) -> PyEdgeIndexGroupOperand {
475        self.0.max().into()
476    }
477
478    pub fn min(&self) -> PyEdgeIndexGroupOperand {
479        self.0.min().into()
480    }
481
482    pub fn count(&self) -> PyEdgeIndexGroupOperand {
483        self.0.count().into()
484    }
485
486    pub fn sum(&self) -> PyEdgeIndexGroupOperand {
487        self.0.sum().into()
488    }
489
490    pub fn random(&self) -> PyEdgeIndexGroupOperand {
491        self.0.random().into()
492    }
493
494    pub fn greater_than(&self, index: PyEdgeIndexComparisonOperand) {
495        self.0.greater_than(index);
496    }
497
498    pub fn greater_than_or_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
499        self.0.greater_than_or_equal_to(index);
500    }
501
502    pub fn less_than(&self, index: PyEdgeIndexComparisonOperand) {
503        self.0.less_than(index);
504    }
505
506    pub fn less_than_or_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
507        self.0.less_than_or_equal_to(index);
508    }
509
510    pub fn equal_to(&self, index: PyEdgeIndexComparisonOperand) {
511        self.0.equal_to(index);
512    }
513
514    pub fn not_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
515        self.0.not_equal_to(index);
516    }
517
518    pub fn starts_with(&self, index: PyEdgeIndexComparisonOperand) {
519        self.0.starts_with(index);
520    }
521
522    pub fn ends_with(&self, index: PyEdgeIndexComparisonOperand) {
523        self.0.ends_with(index);
524    }
525
526    pub fn contains(&self, index: PyEdgeIndexComparisonOperand) {
527        self.0.contains(index);
528    }
529
530    pub fn is_in(&self, indices: PyEdgeIndicesComparisonOperand) {
531        self.0.is_in(indices);
532    }
533
534    pub fn is_not_in(&self, indices: PyEdgeIndicesComparisonOperand) {
535        self.0.is_not_in(indices);
536    }
537
538    pub fn add(&self, index: PyEdgeIndexComparisonOperand) {
539        self.0.add(index);
540    }
541
542    pub fn sub(&self, index: PyEdgeIndexComparisonOperand) {
543        self.0.sub(index);
544    }
545
546    pub fn mul(&self, index: PyEdgeIndexComparisonOperand) {
547        self.0.mul(index);
548    }
549
550    pub fn pow(&self, index: PyEdgeIndexComparisonOperand) {
551        self.0.pow(index);
552    }
553
554    pub fn r#mod(&self, index: PyEdgeIndexComparisonOperand) {
555        self.0.r#mod(index);
556    }
557
558    pub fn is_max(&self) {
559        self.0.is_max();
560    }
561
562    pub fn is_min(&self) {
563        self.0.is_min();
564    }
565
566    /// # Panics
567    ///
568    /// Panics if the python typing was not followed.
569    pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
570        self.0.either_or(
571            |operand| {
572                either
573                    .call1((PyEdgeIndicesOperand::from(operand.clone()),))
574                    .expect("Call must succeed");
575            },
576            |operand| {
577                or.call1((PyEdgeIndicesOperand::from(operand.clone()),))
578                    .expect("Call must succeed");
579            },
580        );
581    }
582
583    /// # Panics
584    ///
585    /// Panics if the python typing was not followed.
586    pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
587        self.0.exclude(|operand| {
588            query
589                .call1((PyEdgeIndicesOperand::from(operand.clone()),))
590                .expect("Call must succeed");
591        });
592    }
593
594    pub fn ungroup(&self) -> PyEdgeIndicesOperand {
595        self.0.ungroup().into()
596    }
597
598    pub fn deep_clone(&self) -> Self {
599        self.0.deep_clone().into()
600    }
601}
602
603#[pyclass(frozen)]
604#[repr(transparent)]
605#[derive(Clone)]
606pub struct PyEdgeIndexOperand(Wrapper<EdgeIndexOperand>);
607
608impl From<Wrapper<EdgeIndexOperand>> for PyEdgeIndexOperand {
609    fn from(operand: Wrapper<EdgeIndexOperand>) -> Self {
610        Self(operand)
611    }
612}
613
614impl From<PyEdgeIndexOperand> for Wrapper<EdgeIndexOperand> {
615    fn from(operand: PyEdgeIndexOperand) -> Self {
616        operand.0
617    }
618}
619
620impl Deref for PyEdgeIndexOperand {
621    type Target = Wrapper<EdgeIndexOperand>;
622
623    fn deref(&self) -> &Self::Target {
624        &self.0
625    }
626}
627
628#[pymethods]
629impl PyEdgeIndexOperand {
630    pub fn greater_than(&self, index: PyEdgeIndexComparisonOperand) {
631        self.0.greater_than(index);
632    }
633
634    pub fn greater_than_or_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
635        self.0.greater_than_or_equal_to(index);
636    }
637
638    pub fn less_than(&self, index: PyEdgeIndexComparisonOperand) {
639        self.0.less_than(index);
640    }
641
642    pub fn less_than_or_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
643        self.0.less_than_or_equal_to(index);
644    }
645
646    pub fn equal_to(&self, index: PyEdgeIndexComparisonOperand) {
647        self.0.equal_to(index);
648    }
649
650    pub fn not_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
651        self.0.not_equal_to(index);
652    }
653
654    pub fn starts_with(&self, index: PyEdgeIndexComparisonOperand) {
655        self.0.starts_with(index);
656    }
657
658    pub fn ends_with(&self, index: PyEdgeIndexComparisonOperand) {
659        self.0.ends_with(index);
660    }
661
662    pub fn contains(&self, index: PyEdgeIndexComparisonOperand) {
663        self.0.contains(index);
664    }
665
666    pub fn is_in(&self, indices: PyEdgeIndicesComparisonOperand) {
667        self.0.is_in(indices);
668    }
669
670    pub fn is_not_in(&self, indices: PyEdgeIndicesComparisonOperand) {
671        self.0.is_not_in(indices);
672    }
673
674    pub fn add(&self, index: PyEdgeIndexComparisonOperand) {
675        self.0.add(index);
676    }
677
678    pub fn sub(&self, index: PyEdgeIndexComparisonOperand) {
679        self.0.sub(index);
680    }
681
682    pub fn mul(&self, index: PyEdgeIndexComparisonOperand) {
683        self.0.mul(index);
684    }
685
686    pub fn pow(&self, index: PyEdgeIndexComparisonOperand) {
687        self.0.pow(index);
688    }
689
690    pub fn r#mod(&self, index: PyEdgeIndexComparisonOperand) {
691        self.0.r#mod(index);
692    }
693
694    /// # Panics
695    ///
696    /// Panics if the python typing was not followed.
697    pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
698        self.0.either_or(
699            |operand| {
700                either
701                    .call1((Self::from(operand.clone()),))
702                    .expect("Call must succeed");
703            },
704            |operand| {
705                or.call1((Self::from(operand.clone()),))
706                    .expect("Call must succeed");
707            },
708        );
709    }
710
711    /// # Panics
712    ///
713    /// Panics if the python typing was not followed.
714    pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
715        self.0.exclude(|operand| {
716            query
717                .call1((Self::from(operand.clone()),))
718                .expect("Call must succeed");
719        });
720    }
721
722    pub fn deep_clone(&self) -> Self {
723        self.0.deep_clone().into()
724    }
725}
726
727#[pyclass(frozen)]
728#[repr(transparent)]
729#[derive(Clone)]
730pub struct PyEdgeIndexGroupOperand(Wrapper<GroupOperand<EdgeIndexOperand>>);
731
732impl From<Wrapper<GroupOperand<EdgeIndexOperand>>> for PyEdgeIndexGroupOperand {
733    fn from(operand: Wrapper<GroupOperand<EdgeIndexOperand>>) -> Self {
734        Self(operand)
735    }
736}
737
738impl From<PyEdgeIndexGroupOperand> for Wrapper<GroupOperand<EdgeIndexOperand>> {
739    fn from(operand: PyEdgeIndexGroupOperand) -> Self {
740        operand.0
741    }
742}
743
744impl Deref for PyEdgeIndexGroupOperand {
745    type Target = Wrapper<GroupOperand<EdgeIndexOperand>>;
746
747    fn deref(&self) -> &Self::Target {
748        &self.0
749    }
750}
751
752#[pymethods]
753impl PyEdgeIndexGroupOperand {
754    pub fn greater_than(&self, index: PyEdgeIndexComparisonOperand) {
755        self.0.greater_than(index);
756    }
757
758    pub fn greater_than_or_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
759        self.0.greater_than_or_equal_to(index);
760    }
761
762    pub fn less_than(&self, index: PyEdgeIndexComparisonOperand) {
763        self.0.less_than(index);
764    }
765
766    pub fn less_than_or_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
767        self.0.less_than_or_equal_to(index);
768    }
769
770    pub fn equal_to(&self, index: PyEdgeIndexComparisonOperand) {
771        self.0.equal_to(index);
772    }
773
774    pub fn not_equal_to(&self, index: PyEdgeIndexComparisonOperand) {
775        self.0.not_equal_to(index);
776    }
777
778    pub fn starts_with(&self, index: PyEdgeIndexComparisonOperand) {
779        self.0.starts_with(index);
780    }
781
782    pub fn ends_with(&self, index: PyEdgeIndexComparisonOperand) {
783        self.0.ends_with(index);
784    }
785
786    pub fn contains(&self, index: PyEdgeIndexComparisonOperand) {
787        self.0.contains(index);
788    }
789
790    pub fn is_in(&self, indices: PyEdgeIndicesComparisonOperand) {
791        self.0.is_in(indices);
792    }
793
794    pub fn is_not_in(&self, indices: PyEdgeIndicesComparisonOperand) {
795        self.0.is_not_in(indices);
796    }
797
798    pub fn add(&self, index: PyEdgeIndexComparisonOperand) {
799        self.0.add(index);
800    }
801
802    pub fn sub(&self, index: PyEdgeIndexComparisonOperand) {
803        self.0.sub(index);
804    }
805
806    pub fn mul(&self, index: PyEdgeIndexComparisonOperand) {
807        self.0.mul(index);
808    }
809
810    pub fn pow(&self, index: PyEdgeIndexComparisonOperand) {
811        self.0.pow(index);
812    }
813
814    pub fn r#mod(&self, index: PyEdgeIndexComparisonOperand) {
815        self.0.r#mod(index);
816    }
817
818    /// # Panics
819    ///
820    /// Panics if the python typing was not followed.
821    pub fn either_or(&self, either: &Bound<'_, PyFunction>, or: &Bound<'_, PyFunction>) {
822        self.0.either_or(
823            |operand| {
824                either
825                    .call1((PyEdgeIndexOperand::from(operand.clone()),))
826                    .expect("Call must succeed");
827            },
828            |operand| {
829                or.call1((PyEdgeIndexOperand::from(operand.clone()),))
830                    .expect("Call must succeed");
831            },
832        );
833    }
834
835    /// # Panics
836    ///
837    /// Panics if the python typing was not followed.
838    pub fn exclude(&self, query: &Bound<'_, PyFunction>) {
839        self.0.exclude(|operand| {
840            query
841                .call1((PyEdgeIndexOperand::from(operand.clone()),))
842                .expect("Call must succeed");
843        });
844    }
845
846    pub fn ungroup(&self) -> PyEdgeIndicesOperand {
847        self.0.ungroup().into()
848    }
849
850    pub fn deep_clone(&self) -> Self {
851        self.0.deep_clone().into()
852    }
853}