Skip to main content

graphrecords_python/querying/
mod.rs

1mod argument;
2mod cast_target;
3mod direction;
4mod endpoint;
5pub(crate) mod exception;
6mod failure_kind;
7mod index_conversion;
8mod terminal;
9mod value_conversion;
10mod value_target;
11
12use crate::{
13    graphrecord::attribute::PyGraphRecordAttribute, querying::exception::FailureConversion,
14};
15pub use argument::PyArgument;
16pub use cast_target::PyCastTarget;
17pub use direction::PyEdgeDirection;
18pub use endpoint::PyEdgeEndpointRole;
19pub use exception::{
20    ArgumentAbsentError, DivisionByZeroError, DuplicateExpandedChildIndexError,
21    DuplicateIndexError, EmptySplitDelimiterError, EvaluationCacheGraphRecordMismatchError,
22    ExternalError, GraphRecordError, IncomparableIndicesError, IncomparableValuesAtError,
23    IncomparableValuesError, IntegerOverflowError, InvalidCastError, InvalidClipBoundsError,
24    InvalidMedianValueError, InvalidPaddingCharacterError, InvalidPartitionBucketArityError,
25    InvalidRegexPatternError, InvalidStandardDeviationValueError, InvalidStringSliceError,
26    InvalidTransitionError, InvalidVarianceValueError, MissingAttributeError,
27    MissingGroupAggregateError, MissingTraversedAttributeError, ModuloByZeroError,
28    NegativeLengthError, NegativeSquareRootError, NoChildIndexError, NonIntegerValueError,
29    NonNumericValueError, NonPositiveLogarithmError, NonStringValueError, QueryError,
30    StringLengthOverflowError, StringPaddingOverflowError, UnresolvedBucketFailuresError,
31    UnresolvedGroupKeyFailuresError, UnsupportedValueRoleError,
32};
33pub use failure_kind::PyFailureKind;
34use graphrecords_query::dynamic::{DynInvokeArgument, DynOperand};
35use pyo3::prelude::*;
36pub use value_target::PyValueTarget;
37
38#[pyclass(frozen)]
39pub struct PyOperand(DynOperand);
40
41#[pymethods]
42impl PyOperand {
43    fn on_missing_drop(&self) -> PyArgument {
44        self.dropping_argument()
45    }
46
47    fn on_missing_replace(&self, replacement: &Bound<'_, PyAny>) -> PyResult<PyArgument> {
48        self.replacing_argument(replacement)
49    }
50
51    fn cache(&self) -> Self {
52        Self(self.operand().cache())
53    }
54
55    fn filter(&self, mask: &Bound<'_, PyAny>) -> PyResult<Self> {
56        self.invoke("filter", &[Self::mask_argument(mask)?])
57    }
58
59    fn and_(&self, other: &Bound<'_, PyAny>) -> PyResult<Self> {
60        self.invoke("and", &[Self::mask_argument(other)?])
61    }
62
63    fn or_(&self, other: &Bound<'_, PyAny>) -> PyResult<Self> {
64        self.invoke("or", &[Self::mask_argument(other)?])
65    }
66
67    fn xor(&self, other: &Bound<'_, PyAny>) -> PyResult<Self> {
68        self.invoke("xor", &[Self::mask_argument(other)?])
69    }
70
71    fn not_(&self) -> PyResult<Self> {
72        self.invoke("not", &[])
73    }
74
75    fn first(&self) -> PyResult<Self> {
76        self.invoke("first", &[])
77    }
78
79    fn last(&self) -> PyResult<Self> {
80        self.invoke("last", &[])
81    }
82
83    fn reverse_order(&self) -> PyResult<Self> {
84        self.invoke("reverse_order", &[])
85    }
86
87    fn shuffle(&self) -> PyResult<Self> {
88        self.invoke("shuffle", &[])
89    }
90
91    fn unorder(&self) -> PyResult<Self> {
92        self.invoke("unorder", &[])
93    }
94
95    fn sort(&self) -> PyResult<Self> {
96        self.invoke("sort", &[])
97    }
98
99    fn sort_by(&self, key: &Bound<'_, PyAny>) -> PyResult<Self> {
100        self.invoke("sort_by", &[Self::scalar_argument(key)?])
101    }
102
103    fn drop_duplicates(&self) -> PyResult<Self> {
104        self.invoke("drop_duplicates", &[])
105    }
106
107    fn is_duplicated(&self) -> PyResult<Self> {
108        self.invoke("is_duplicated", &[])
109    }
110
111    fn unique(&self) -> PyResult<Self> {
112        self.invoke("unique", &[])
113    }
114
115    fn take(&self, elements: usize) -> PyResult<Self> {
116        self.invoke("take", &[DynInvokeArgument::Position(elements)])
117    }
118
119    fn is_bool(&self) -> PyResult<Self> {
120        self.invoke("is_bool", &[])
121    }
122
123    fn is_datetime(&self) -> PyResult<Self> {
124        self.invoke("is_datetime", &[])
125    }
126
127    fn is_duration(&self) -> PyResult<Self> {
128        self.invoke("is_duration", &[])
129    }
130
131    fn is_float(&self) -> PyResult<Self> {
132        self.invoke("is_float", &[])
133    }
134
135    fn is_null(&self) -> PyResult<Self> {
136        self.invoke("is_null", &[])
137    }
138
139    fn is_int(&self) -> PyResult<Self> {
140        self.invoke("is_int", &[])
141    }
142
143    fn is_string(&self) -> PyResult<Self> {
144        self.invoke("is_string", &[])
145    }
146
147    fn abs(&self) -> PyResult<Self> {
148        self.invoke("abs", &[])
149    }
150
151    fn neg(&self) -> PyResult<Self> {
152        self.invoke("neg", &[])
153    }
154
155    fn sign(&self) -> PyResult<Self> {
156        self.invoke("sign", &[])
157    }
158
159    fn ceil(&self) -> PyResult<Self> {
160        self.invoke("ceil", &[])
161    }
162
163    fn cbrt(&self) -> PyResult<Self> {
164        self.invoke("cbrt", &[])
165    }
166
167    fn exp(&self) -> PyResult<Self> {
168        self.invoke("exp", &[])
169    }
170
171    fn floor(&self) -> PyResult<Self> {
172        self.invoke("floor", &[])
173    }
174
175    fn log(&self) -> PyResult<Self> {
176        self.invoke("log", &[])
177    }
178
179    fn round(&self) -> PyResult<Self> {
180        self.invoke("round", &[])
181    }
182
183    fn sqrt(&self) -> PyResult<Self> {
184        self.invoke("sqrt", &[])
185    }
186
187    fn trim(&self) -> PyResult<Self> {
188        self.invoke("trim", &[])
189    }
190
191    fn trim_start(&self) -> PyResult<Self> {
192        self.invoke("trim_start", &[])
193    }
194
195    fn trim_end(&self) -> PyResult<Self> {
196        self.invoke("trim_end", &[])
197    }
198
199    fn lowercase(&self) -> PyResult<Self> {
200        self.invoke("lowercase", &[])
201    }
202
203    fn uppercase(&self) -> PyResult<Self> {
204        self.invoke("uppercase", &[])
205    }
206
207    fn reverse(&self) -> PyResult<Self> {
208        self.invoke("reverse", &[])
209    }
210
211    fn length(&self) -> PyResult<Self> {
212        self.invoke("length", &[])
213    }
214
215    fn slice(&self, start: usize, end: usize) -> PyResult<Self> {
216        self.invoke(
217            "slice",
218            &[
219                DynInvokeArgument::Position(start),
220                DynInvokeArgument::Position(end),
221            ],
222        )
223    }
224
225    fn starts_with(&self, prefix: &Bound<'_, PyAny>) -> PyResult<Self> {
226        self.invoke("starts_with", &[Self::scalar_argument(prefix)?])
227    }
228
229    fn ends_with(&self, suffix: &Bound<'_, PyAny>) -> PyResult<Self> {
230        self.invoke("ends_with", &[Self::scalar_argument(suffix)?])
231    }
232
233    fn contains(&self, part: &Bound<'_, PyAny>) -> PyResult<Self> {
234        self.invoke("contains", &[Self::scalar_argument(part)?])
235    }
236
237    fn matches(&self, pattern: &Bound<'_, PyAny>) -> PyResult<Self> {
238        self.invoke("matches", &[Self::scalar_argument(pattern)?])
239    }
240
241    fn strip_prefix(&self, prefix: &Bound<'_, PyAny>) -> PyResult<Self> {
242        self.invoke("strip_prefix", &[Self::scalar_argument(prefix)?])
243    }
244
245    fn strip_suffix(&self, suffix: &Bound<'_, PyAny>) -> PyResult<Self> {
246        self.invoke("strip_suffix", &[Self::scalar_argument(suffix)?])
247    }
248
249    fn replace(&self, old: &Bound<'_, PyAny>, new: &Bound<'_, PyAny>) -> PyResult<Self> {
250        self.invoke(
251            "replace",
252            &[Self::scalar_argument(old)?, Self::scalar_argument(new)?],
253        )
254    }
255
256    fn replace_all(&self, old: &Bound<'_, PyAny>, new: &Bound<'_, PyAny>) -> PyResult<Self> {
257        self.invoke(
258            "replace_all",
259            &[Self::scalar_argument(old)?, Self::scalar_argument(new)?],
260        )
261    }
262
263    fn pad_start(&self, width: &Bound<'_, PyAny>, character: &Bound<'_, PyAny>) -> PyResult<Self> {
264        self.invoke(
265            "pad_start",
266            &[
267                Self::scalar_argument(width)?,
268                Self::scalar_argument(character)?,
269            ],
270        )
271    }
272
273    fn pad_end(&self, width: &Bound<'_, PyAny>, character: &Bound<'_, PyAny>) -> PyResult<Self> {
274        self.invoke(
275            "pad_end",
276            &[
277                Self::scalar_argument(width)?,
278                Self::scalar_argument(character)?,
279            ],
280        )
281    }
282
283    fn split(&self, delimiter: &Bound<'_, PyAny>) -> PyResult<Self> {
284        self.invoke("split", &[Self::scalar_argument(delimiter)?])
285    }
286
287    fn attribute(&self, attribute: PyGraphRecordAttribute) -> PyResult<Self> {
288        self.invoke(
289            "attribute",
290            &[DynInvokeArgument::Attribute(attribute.into())],
291        )
292    }
293
294    fn attributes(&self) -> PyResult<Self> {
295        self.invoke("attributes", &[])
296    }
297
298    fn resolve(&self) -> PyResult<Self> {
299        self.invoke("resolve", &[])
300    }
301
302    fn select(&self) -> PyResult<Self> {
303        self.invoke("select", &[])
304    }
305
306    fn parent_index(&self) -> PyResult<Self> {
307        self.invoke("parent_index", &[])
308    }
309
310    fn child_index(&self) -> PyResult<Self> {
311        self.invoke("child_index", &[])
312    }
313
314    fn has_attribute(&self, attribute: PyGraphRecordAttribute) -> PyResult<Self> {
315        self.invoke(
316            "has_attribute",
317            &[DynInvokeArgument::Attribute(attribute.into())],
318        )
319    }
320
321    fn in_group(&self, group: PyGraphRecordAttribute) -> PyResult<Self> {
322        self.invoke("in_group", &[DynInvokeArgument::Group(group.into())])
323    }
324
325    fn add(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
326        self.invoke("add", &[self.value_argument(value)?])
327    }
328
329    fn subtract(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
330        self.invoke("subtract", &[self.value_argument(value)?])
331    }
332
333    fn multiply(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
334        self.invoke("multiply", &[self.value_argument(value)?])
335    }
336
337    fn power(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
338        self.invoke("power", &[self.value_argument(value)?])
339    }
340
341    fn modulo(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
342        self.invoke("modulo", &[self.value_argument(value)?])
343    }
344
345    fn divide(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
346        self.invoke("divide", &[self.value_argument(value)?])
347    }
348
349    fn clip(&self, lower: &Bound<'_, PyAny>, upper: &Bound<'_, PyAny>) -> PyResult<Self> {
350        self.invoke(
351            "clip",
352            &[self.value_argument(lower)?, self.value_argument(upper)?],
353        )
354    }
355
356    fn cast(&self, target: PyCastTarget) -> PyResult<Self> {
357        self.invoke("cast", &[DynInvokeArgument::CastTarget(target.into())])
358    }
359
360    fn equal_to(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
361        self.invoke("equal_to", &[self.value_argument(value)?])
362    }
363
364    fn not_equal_to(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
365        self.invoke("not_equal_to", &[self.value_argument(value)?])
366    }
367
368    fn greater_than(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
369        self.invoke("greater_than", &[self.value_argument(value)?])
370    }
371
372    fn greater_than_or_equal_to(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
373        self.invoke("greater_than_or_equal_to", &[self.value_argument(value)?])
374    }
375
376    fn less_than(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
377        self.invoke("less_than", &[self.value_argument(value)?])
378    }
379
380    fn less_than_or_equal_to(&self, value: &Bound<'_, PyAny>) -> PyResult<Self> {
381        self.invoke("less_than_or_equal_to", &[self.value_argument(value)?])
382    }
383
384    fn is_in(&self, values: &Bound<'_, PyAny>) -> PyResult<Self> {
385        self.invoke("is_in", &[self.set_argument(values)?])
386    }
387
388    fn index(&self) -> PyResult<Self> {
389        self.invoke("index", &[])
390    }
391
392    fn discard_index(&self) -> PyResult<Self> {
393        self.invoke("discard_index", &[])
394    }
395
396    fn discard_value(&self) -> PyResult<Self> {
397        self.invoke("discard_value", &[])
398    }
399
400    fn enumerate(&self) -> PyResult<Self> {
401        self.invoke("enumerate", &[])
402    }
403
404    fn errors(&self) -> PyResult<Self> {
405        self.invoke("errors", &[])
406    }
407
408    fn on_error_raise(&self) -> PyResult<Self> {
409        self.invoke("on_error_raise", &[])
410    }
411
412    fn on_error_drop(&self) -> PyResult<Self> {
413        self.invoke("on_error_drop", &[])
414    }
415
416    fn on_error_replace(&self, replacement: &Bound<'_, PyAny>) -> PyResult<Self> {
417        self.invoke("on_error_replace", &[self.value_argument(replacement)?])
418    }
419
420    fn raise_when(&self, condition: &Bound<'_, PyAny>) -> PyResult<Self> {
421        self.invoke("raise_when", &[Self::mask_argument(condition)?])
422    }
423
424    fn kind(&self) -> PyResult<Self> {
425        self.invoke("kind", &[])
426    }
427
428    fn name(&self) -> PyResult<Self> {
429        self.invoke("name", &[])
430    }
431
432    fn count(&self) -> PyResult<Self> {
433        self.invoke("count", &[])
434    }
435
436    fn sum(&self) -> PyResult<Self> {
437        self.invoke("sum", &[])
438    }
439
440    fn mean(&self) -> PyResult<Self> {
441        self.invoke("mean", &[])
442    }
443
444    fn std(&self) -> PyResult<Self> {
445        self.invoke("std", &[])
446    }
447
448    fn var(&self) -> PyResult<Self> {
449        self.invoke("var", &[])
450    }
451
452    fn all(&self) -> PyResult<Self> {
453        self.invoke("all", &[])
454    }
455
456    fn any(&self) -> PyResult<Self> {
457        self.invoke("any", &[])
458    }
459
460    fn max(&self) -> PyResult<Self> {
461        self.invoke("max", &[])
462    }
463
464    fn min(&self) -> PyResult<Self> {
465        self.invoke("min", &[])
466    }
467
468    fn median(&self) -> PyResult<Self> {
469        self.invoke("median", &[])
470    }
471
472    fn mode(&self) -> PyResult<Self> {
473        self.invoke("mode", &[])
474    }
475
476    fn product(&self) -> PyResult<Self> {
477        self.invoke("product", &[])
478    }
479
480    fn n_unique(&self) -> PyResult<Self> {
481        self.invoke("n_unique", &[])
482    }
483
484    fn random(&self) -> PyResult<Self> {
485        self.invoke("random", &[])
486    }
487
488    fn edges(&self, direction: PyEdgeDirection) -> PyResult<Self> {
489        self.invoke("edges", &[DynInvokeArgument::Direction(direction.into())])
490    }
491
492    fn neighbors(&self, direction: PyEdgeDirection) -> PyResult<Self> {
493        self.invoke(
494            "neighbors",
495            &[DynInvokeArgument::Direction(direction.into())],
496        )
497    }
498
499    fn via_edges(&self, direction: PyEdgeDirection) -> PyResult<Self> {
500        self.invoke(
501            "via_edges",
502            &[DynInvokeArgument::Direction(direction.into())],
503        )
504    }
505
506    fn via_neighbors(&self, direction: PyEdgeDirection) -> PyResult<Self> {
507        self.invoke(
508            "via_neighbors",
509            &[DynInvokeArgument::Direction(direction.into())],
510        )
511    }
512
513    fn nodes(&self) -> PyResult<Self> {
514        self.invoke("nodes", &[])
515    }
516
517    fn via_nodes(&self) -> PyResult<Self> {
518        self.invoke("via_nodes", &[])
519    }
520
521    fn source_node(&self) -> PyResult<Self> {
522        self.via_source_node()?.select()
523    }
524
525    fn target_node(&self) -> PyResult<Self> {
526        self.via_target_node()?.select()
527    }
528
529    fn via_source_node(&self) -> PyResult<Self> {
530        self.invoke("via_source_node", &[])
531    }
532
533    fn via_target_node(&self) -> PyResult<Self> {
534        self.invoke("via_target_node", &[])
535    }
536
537    #[getter]
538    fn group_depth(&self) -> usize {
539        self.operand().descriptor().group_depth()
540    }
541
542    fn group_by(&self, key: &Bound<'_, PyAny>) -> PyResult<Self> {
543        self.invoke("group_by", &[Self::scalar_argument(key)?])
544    }
545
546    fn having(&self, predicate: &Bound<'_, PyAny>) -> PyResult<Self> {
547        self.invoke("having", &[Self::mask_argument(predicate)?])
548    }
549
550    fn keys(&self) -> PyResult<Self> {
551        self.invoke("keys", &[])
552    }
553
554    fn ungroup(&self) -> PyResult<Self> {
555        self.invoke("ungroup", &[])
556    }
557
558    fn ungroup_keyed(&self) -> PyResult<Self> {
559        self.invoke("ungroup_keyed", &[])
560    }
561
562    fn broadcast(&self) -> PyResult<Self> {
563        self.invoke("broadcast", &[])
564    }
565
566    fn broadcast_via(&self, population: &Bound<'_, PyAny>) -> PyResult<Self> {
567        self.invoke("broadcast_via", &[Self::operand_argument(population)?])
568    }
569
570    fn bucket_errors(&self) -> PyResult<Self> {
571        self.invoke("bucket_errors", &[])
572    }
573
574    fn key_errors(&self) -> PyResult<Self> {
575        self.invoke("key_errors", &[])
576    }
577
578    fn on_bucket_error_drop(&self) -> PyResult<Self> {
579        self.invoke("on_bucket_error_drop", &[])
580    }
581
582    fn on_bucket_error_raise(&self) -> PyResult<Self> {
583        self.invoke("on_bucket_error_raise", &[])
584    }
585
586    fn on_key_error_drop(&self) -> PyResult<Self> {
587        self.invoke("on_key_error_drop", &[])
588    }
589
590    fn on_key_error_raise(&self) -> PyResult<Self> {
591        self.invoke("on_key_error_raise", &[])
592    }
593
594    fn transition(&self, target: PyValueTarget) -> PyResult<Self> {
595        self.invoke(
596            "transition",
597            &[DynInvokeArgument::ValueTarget(target.into())],
598        )
599    }
600
601    fn expand_to(&self, values: &Bound<'_, PyAny>) -> PyResult<Self> {
602        self.invoke("expand_to", &[Self::scalar_argument(values)?])
603    }
604}
605
606impl PyOperand {
607    const fn operand(&self) -> &DynOperand {
608        &self.0
609    }
610
611    fn invoke(&self, method: &str, arguments: &[DynInvokeArgument]) -> PyResult<Self> {
612        self.operand()
613            .invoke(method, arguments)
614            .map(Self)
615            .map_err(|failure| failure.to_python_error())
616    }
617}