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}