cygnet-orm 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cygnet/arrays.py ADDED
@@ -0,0 +1,111 @@
1
+ # arrays.py — Curated helpers for PostgreSQL array operators and functions.
2
+ #
3
+ # Mix of operator helpers (built on cygnet.op) and function helpers
4
+ # (built on cygnet.fn). ANY/ALL deserve special mention: they're not
5
+ # standalone predicates — they appear on the right side of a comparison,
6
+ # as in `value = ANY(arr_col)`. The any() / all() helpers below return
7
+ # FunctionCall expressions; pair them with `==` / `!=` / etc. or wrap
8
+ # with cygnet.op for non-standard comparisons.
9
+ #
10
+ # Index notes: @>, <@, and && are accelerated by GIN indexes on the
11
+ # array column. `=` and ordering operators use btree on the array as a
12
+ # whole (rarely useful). array_length / cardinality / unnest are not
13
+ # index-friendly — filter on a containment predicate first when possible.
14
+ #
15
+ # NULL handling: in arrays, NULL elements are not equal to anything, so
16
+ # `NULL = ANY(arr)` yields NULL (not true), even if arr contains NULL.
17
+ # Use `arr.contains(col, [None])` semantics with care — PG treats NULLs
18
+ # in arrays as distinct from absence.
19
+ #
20
+ # `ANY` also accepts a subquery (e.g. `= ANY(SELECT id FROM t)`); the
21
+ # any() helper here is array-flavoured but happens to render identically
22
+ # for either operand since both forms emit `ANY(<expr>)`.
23
+ #
24
+ # Usage:
25
+ # import cygnet.arrays as arr
26
+ # .WHERE(arr.contains(T.tags, ["python", "sql"]))
27
+ # .WHERE(T.id == arr.any(other_table.allowed_ids))
28
+ # .WHERE(arr.length(T.items) > 0)
29
+
30
+ from __future__ import annotations
31
+
32
+ from typing import Any
33
+
34
+ from .expression import FunctionCall, fn, op
35
+ from .predicate import Predicate
36
+
37
+
38
+ def contains(a: Any, b: Any) -> Predicate:
39
+ """`a @> b` — does array `a` contain every element of array `b`?"""
40
+ return op(a, "@>", b)
41
+
42
+
43
+ def contained_by(a: Any, b: Any) -> Predicate:
44
+ """`a <@ b` — is array `a` contained by array `b`?"""
45
+ return op(a, "<@", b)
46
+
47
+
48
+ def overlaps(a: Any, b: Any) -> Predicate:
49
+ """`a && b` — do the arrays share any element?"""
50
+ return op(a, "&&", b)
51
+
52
+
53
+ def concat(a: Any, b: Any) -> Predicate:
54
+ """`a || b` — array concatenation."""
55
+ return op(a, "||", b)
56
+
57
+
58
+ def any(col: Any) -> FunctionCall: # noqa: A001 — shadows builtin intentionally
59
+ """`ANY(col)` — for use on the right side of a comparison.
60
+
61
+ Example: `WHERE T.id = arr.any(other_col)` renders as
62
+ `T.id = ANY(other_col)`. Returns a FunctionCall, not a Predicate;
63
+ pair with `==`, `!=`, or another comparison to produce a WHERE-able
64
+ expression.
65
+ """
66
+ return fn("ANY")(col)
67
+
68
+
69
+ def all(col: Any) -> FunctionCall: # noqa: A001 — shadows builtin intentionally
70
+ """`ALL(col)` — like any(), but every element must satisfy the comparison.
71
+
72
+ Example: `WHERE T.score > arr.all(thresholds)` renders as
73
+ `T.score > ALL(thresholds)`.
74
+ """
75
+ return fn("ALL")(col)
76
+
77
+
78
+ def length(col: Any, dim: int = 1) -> FunctionCall:
79
+ """`array_length(col, dim)` — length along the given dimension (1-based).
80
+
81
+ Default dim=1 covers the common case of a 1-D array. Returns NULL
82
+ if the array is empty or the dimension doesn't exist — that's PG's
83
+ semantics, not Cygnet's.
84
+ """
85
+ return fn("array_length")(col, dim)
86
+
87
+
88
+ def cardinality(col: Any) -> FunctionCall:
89
+ """`cardinality(col)` — total element count regardless of dimensions.
90
+
91
+ Unlike length(), returns 0 (not NULL) for empty arrays.
92
+ """
93
+ return fn("cardinality")(col)
94
+
95
+
96
+ def unnest(col: Any) -> FunctionCall:
97
+ """`unnest(col)` — expand an array into rows.
98
+
99
+ Mostly useful in FROM (lateral) or SELECT contexts; less common in
100
+ WHERE. Returns a FunctionCall that renders as `unnest(col)`.
101
+ """
102
+ return fn("unnest")(col)
103
+
104
+
105
+ def array_agg(col: Any) -> FunctionCall:
106
+ """`array_agg(col)` — collect into an array (aggregate).
107
+
108
+ Re-exported here from cygnet.functions for discoverability alongside
109
+ the other array helpers.
110
+ """
111
+ return fn("array_agg")(col)