Skip to main content

graphrecords_python/graphrecord/querying/
nodes.rs

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