SQLAlchemy 2.1.0b2__cp313-cp313t-win_arm64.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.
Files changed (270) hide show
  1. sqlalchemy/__init__.py +298 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +171 -0
  4. sqlalchemy/connectors/asyncio.py +476 -0
  5. sqlalchemy/connectors/pyodbc.py +250 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +30 -0
  8. sqlalchemy/dialects/mssql/__init__.py +89 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4166 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +220 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +698 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +226 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +214 -0
  21. sqlalchemy/dialects/mysql/base.py +3877 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +106 -0
  23. sqlalchemy/dialects/mysql/dml.py +279 -0
  24. sqlalchemy/dialects/mysql/enumerated.py +277 -0
  25. sqlalchemy/dialects/mysql/expression.py +146 -0
  26. sqlalchemy/dialects/mysql/json.py +92 -0
  27. sqlalchemy/dialects/mysql/mariadb.py +67 -0
  28. sqlalchemy/dialects/mysql/mariadbconnector.py +330 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +296 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +312 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +157 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +156 -0
  34. sqlalchemy/dialects/mysql/reflection.py +724 -0
  35. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  36. sqlalchemy/dialects/mysql/types.py +845 -0
  37. sqlalchemy/dialects/oracle/__init__.py +85 -0
  38. sqlalchemy/dialects/oracle/base.py +3977 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1601 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +158 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +909 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +368 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +171 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +229 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1323 -0
  50. sqlalchemy/dialects/postgresql/base.py +5789 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +593 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +423 -0
  55. sqlalchemy/dialects/postgresql/json.py +408 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +521 -0
  57. sqlalchemy/dialects/postgresql/operators.py +130 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +670 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +344 -0
  60. sqlalchemy/dialects/postgresql/provision.py +184 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +799 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +321 -0
  68. sqlalchemy/dialects/sqlite/base.py +3063 -0
  69. sqlalchemy/dialects/sqlite/dml.py +279 -0
  70. sqlalchemy/dialects/sqlite/json.py +100 -0
  71. sqlalchemy/dialects/sqlite/provision.py +229 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +161 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +754 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp313t-win_arm64.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp313t-win_arm64.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +633 -0
  80. sqlalchemy/engine/_row_cy.cp313t-win_arm64.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp313t-win_arm64.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3354 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2421 -0
  88. sqlalchemy/engine/default.py +2402 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3495 -0
  91. sqlalchemy/engine/mock.py +134 -0
  92. sqlalchemy/engine/processors.py +82 -0
  93. sqlalchemy/engine/reflection.py +2100 -0
  94. sqlalchemy/engine/result.py +1966 -0
  95. sqlalchemy/engine/row.py +397 -0
  96. sqlalchemy/engine/strategies.py +16 -0
  97. sqlalchemy/engine/url.py +922 -0
  98. sqlalchemy/engine/util.py +156 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +674 -0
  102. sqlalchemy/event/base.py +472 -0
  103. sqlalchemy/event/legacy.py +258 -0
  104. sqlalchemy/event/registry.py +390 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +922 -0
  107. sqlalchemy/ext/__init__.py +11 -0
  108. sqlalchemy/ext/associationproxy.py +2072 -0
  109. sqlalchemy/ext/asyncio/__init__.py +29 -0
  110. sqlalchemy/ext/asyncio/base.py +281 -0
  111. sqlalchemy/ext/asyncio/engine.py +1487 -0
  112. sqlalchemy/ext/asyncio/exc.py +21 -0
  113. sqlalchemy/ext/asyncio/result.py +994 -0
  114. sqlalchemy/ext/asyncio/scoping.py +1679 -0
  115. sqlalchemy/ext/asyncio/session.py +2007 -0
  116. sqlalchemy/ext/automap.py +1701 -0
  117. sqlalchemy/ext/baked.py +559 -0
  118. sqlalchemy/ext/compiler.py +600 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +560 -0
  121. sqlalchemy/ext/horizontal_shard.py +481 -0
  122. sqlalchemy/ext/hybrid.py +1877 -0
  123. sqlalchemy/ext/indexable.py +364 -0
  124. sqlalchemy/ext/instrumentation.py +450 -0
  125. sqlalchemy/ext/mutable.py +1081 -0
  126. sqlalchemy/ext/orderinglist.py +439 -0
  127. sqlalchemy/ext/serializer.py +185 -0
  128. sqlalchemy/future/__init__.py +16 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +174 -0
  131. sqlalchemy/log.py +283 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2694 -0
  134. sqlalchemy/orm/_typing.py +179 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +976 -0
  137. sqlalchemy/orm/bulk_persistence.py +2152 -0
  138. sqlalchemy/orm/clsregistry.py +582 -0
  139. sqlalchemy/orm/collections.py +1568 -0
  140. sqlalchemy/orm/context.py +3471 -0
  141. sqlalchemy/orm/decl_api.py +2280 -0
  142. sqlalchemy/orm/decl_base.py +2309 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1183 -0
  145. sqlalchemy/orm/dynamic.py +307 -0
  146. sqlalchemy/orm/evaluator.py +379 -0
  147. sqlalchemy/orm/events.py +3386 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +746 -0
  151. sqlalchemy/orm/interfaces.py +1589 -0
  152. sqlalchemy/orm/loading.py +1684 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4411 -0
  155. sqlalchemy/orm/path_registry.py +829 -0
  156. sqlalchemy/orm/persistence.py +1789 -0
  157. sqlalchemy/orm/properties.py +973 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3570 -0
  160. sqlalchemy/orm/scoping.py +2232 -0
  161. sqlalchemy/orm/session.py +5403 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3492 -0
  165. sqlalchemy/orm/strategy_options.py +2562 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +798 -0
  168. sqlalchemy/orm/util.py +2438 -0
  169. sqlalchemy/orm/writeonly.py +694 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1522 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +582 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +74 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +397 -0
  178. sqlalchemy/sql/_dml_constructors.py +132 -0
  179. sqlalchemy/sql/_elements_constructors.py +2164 -0
  180. sqlalchemy/sql/_orm_types.py +20 -0
  181. sqlalchemy/sql/_selectable_constructors.py +840 -0
  182. sqlalchemy/sql/_typing.py +487 -0
  183. sqlalchemy/sql/_util_cy.cp313t-win_arm64.pyd +0 -0
  184. sqlalchemy/sql/_util_cy.py +127 -0
  185. sqlalchemy/sql/annotation.py +590 -0
  186. sqlalchemy/sql/base.py +2699 -0
  187. sqlalchemy/sql/cache_key.py +1066 -0
  188. sqlalchemy/sql/coercions.py +1373 -0
  189. sqlalchemy/sql/compiler.py +8327 -0
  190. sqlalchemy/sql/crud.py +1815 -0
  191. sqlalchemy/sql/ddl.py +1928 -0
  192. sqlalchemy/sql/default_comparator.py +654 -0
  193. sqlalchemy/sql/dml.py +1977 -0
  194. sqlalchemy/sql/elements.py +6033 -0
  195. sqlalchemy/sql/events.py +458 -0
  196. sqlalchemy/sql/expression.py +172 -0
  197. sqlalchemy/sql/functions.py +2305 -0
  198. sqlalchemy/sql/lambdas.py +1443 -0
  199. sqlalchemy/sql/naming.py +209 -0
  200. sqlalchemy/sql/operators.py +2897 -0
  201. sqlalchemy/sql/roles.py +332 -0
  202. sqlalchemy/sql/schema.py +6703 -0
  203. sqlalchemy/sql/selectable.py +7553 -0
  204. sqlalchemy/sql/sqltypes.py +4093 -0
  205. sqlalchemy/sql/traversals.py +1042 -0
  206. sqlalchemy/sql/type_api.py +2446 -0
  207. sqlalchemy/sql/util.py +1495 -0
  208. sqlalchemy/sql/visitors.py +1157 -0
  209. sqlalchemy/testing/__init__.py +96 -0
  210. sqlalchemy/testing/assertions.py +1007 -0
  211. sqlalchemy/testing/assertsql.py +519 -0
  212. sqlalchemy/testing/asyncio.py +128 -0
  213. sqlalchemy/testing/config.py +440 -0
  214. sqlalchemy/testing/engines.py +483 -0
  215. sqlalchemy/testing/entities.py +117 -0
  216. sqlalchemy/testing/exclusions.py +476 -0
  217. sqlalchemy/testing/fixtures/__init__.py +30 -0
  218. sqlalchemy/testing/fixtures/base.py +384 -0
  219. sqlalchemy/testing/fixtures/mypy.py +247 -0
  220. sqlalchemy/testing/fixtures/orm.py +227 -0
  221. sqlalchemy/testing/fixtures/sql.py +538 -0
  222. sqlalchemy/testing/pickleable.py +155 -0
  223. sqlalchemy/testing/plugin/__init__.py +6 -0
  224. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  225. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  226. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  227. sqlalchemy/testing/profiling.py +329 -0
  228. sqlalchemy/testing/provision.py +613 -0
  229. sqlalchemy/testing/requirements.py +1978 -0
  230. sqlalchemy/testing/schema.py +198 -0
  231. sqlalchemy/testing/suite/__init__.py +19 -0
  232. sqlalchemy/testing/suite/test_cte.py +237 -0
  233. sqlalchemy/testing/suite/test_ddl.py +420 -0
  234. sqlalchemy/testing/suite/test_dialect.py +776 -0
  235. sqlalchemy/testing/suite/test_insert.py +630 -0
  236. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  237. sqlalchemy/testing/suite/test_results.py +660 -0
  238. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  239. sqlalchemy/testing/suite/test_select.py +2112 -0
  240. sqlalchemy/testing/suite/test_sequence.py +317 -0
  241. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  242. sqlalchemy/testing/suite/test_types.py +2271 -0
  243. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  244. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  245. sqlalchemy/testing/util.py +535 -0
  246. sqlalchemy/testing/warnings.py +52 -0
  247. sqlalchemy/types.py +76 -0
  248. sqlalchemy/util/__init__.py +158 -0
  249. sqlalchemy/util/_collections.py +688 -0
  250. sqlalchemy/util/_collections_cy.cp313t-win_arm64.pyd +0 -0
  251. sqlalchemy/util/_collections_cy.pxd +8 -0
  252. sqlalchemy/util/_collections_cy.py +516 -0
  253. sqlalchemy/util/_has_cython.py +46 -0
  254. sqlalchemy/util/_immutabledict_cy.cp313t-win_arm64.pyd +0 -0
  255. sqlalchemy/util/_immutabledict_cy.py +240 -0
  256. sqlalchemy/util/compat.py +299 -0
  257. sqlalchemy/util/concurrency.py +322 -0
  258. sqlalchemy/util/cython.py +79 -0
  259. sqlalchemy/util/deprecations.py +401 -0
  260. sqlalchemy/util/langhelpers.py +2320 -0
  261. sqlalchemy/util/preloaded.py +152 -0
  262. sqlalchemy/util/queue.py +304 -0
  263. sqlalchemy/util/tool_support.py +201 -0
  264. sqlalchemy/util/topological.py +120 -0
  265. sqlalchemy/util/typing.py +711 -0
  266. sqlalchemy-2.1.0b2.dist-info/METADATA +269 -0
  267. sqlalchemy-2.1.0b2.dist-info/RECORD +270 -0
  268. sqlalchemy-2.1.0b2.dist-info/WHEEL +5 -0
  269. sqlalchemy-2.1.0b2.dist-info/licenses/LICENSE +19 -0
  270. sqlalchemy-2.1.0b2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2897 @@
1
+ # sql/operators.py
2
+ # Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+
8
+ # This module is part of SQLAlchemy and is released under
9
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
10
+
11
+ """Defines operators used in SQL expressions."""
12
+
13
+ from __future__ import annotations
14
+
15
+ from enum import auto
16
+ from enum import Flag
17
+ from enum import IntEnum
18
+ from operator import add as _uncast_add
19
+ from operator import and_ as _uncast_and_
20
+ from operator import contains as _uncast_contains
21
+ from operator import eq as _uncast_eq
22
+ from operator import floordiv as _uncast_floordiv
23
+ from operator import ge as _uncast_ge
24
+ from operator import getitem as _uncast_getitem
25
+ from operator import gt as _uncast_gt
26
+ from operator import inv as _uncast_inv
27
+ from operator import le as _uncast_le
28
+ from operator import lshift as _uncast_lshift
29
+ from operator import lt as _uncast_lt
30
+ from operator import matmul as _uncast_matmul
31
+ from operator import mod as _uncast_mod
32
+ from operator import mul as _uncast_mul
33
+ from operator import ne as _uncast_ne
34
+ from operator import neg as _uncast_neg
35
+ from operator import or_ as _uncast_or_
36
+ from operator import pow as _uncast_pow
37
+ from operator import rshift as _uncast_rshift
38
+ from operator import sub as _uncast_sub
39
+ from operator import truediv as _uncast_truediv
40
+ import typing
41
+ from typing import Any
42
+ from typing import Callable
43
+ from typing import cast
44
+ from typing import Dict
45
+ from typing import Generic
46
+ from typing import Hashable
47
+ from typing import Literal
48
+ from typing import Optional
49
+ from typing import overload
50
+ from typing import Protocol
51
+ from typing import Set
52
+ from typing import Tuple
53
+ from typing import Type
54
+ from typing import TYPE_CHECKING
55
+ from typing import TypeVar
56
+ from typing import Union
57
+
58
+ from .. import exc
59
+ from .. import util
60
+
61
+ if typing.TYPE_CHECKING:
62
+ from ._typing import ColumnExpressionArgument
63
+ from .cache_key import CacheConst
64
+ from .elements import ColumnElement
65
+ from .type_api import TypeEngine
66
+
67
+ _T = TypeVar("_T", bound=Any)
68
+ _FN = TypeVar("_FN", bound=Callable[..., Any])
69
+
70
+
71
+ class OperatorClass(Flag):
72
+ """Describes a class of SQLAlchemy built-in operators that should be
73
+ available on a particular type.
74
+
75
+ The :class:`.OperatorClass` should be present on the
76
+ :attr:`.TypeEngine.operator_classes` attribute of any particular type.
77
+
78
+ The enums here can be ORed together to provide sets of operators merged
79
+ together.
80
+
81
+ .. versionadded:: 2.1
82
+
83
+ """
84
+
85
+ UNSPECIFIED = auto()
86
+ BASE = auto()
87
+ BOOLEAN_ALGEBRA = auto()
88
+ COMPARISON = auto()
89
+ INDEXABLE = auto() # noqa: F811
90
+ CONTAINS = auto()
91
+ CONCATENABLE = auto()
92
+ STRING_MATCH = auto()
93
+ MATH = auto()
94
+ BITWISE = auto()
95
+ DATE_ARITHEMETIC = auto()
96
+ JSON_GETITEM = auto()
97
+
98
+ STRING = (
99
+ BASE | COMPARISON | STRING_MATCH | CONTAINS | CONCATENABLE | INDEXABLE
100
+ )
101
+ INTEGER = BASE | COMPARISON | MATH | BITWISE
102
+ NUMERIC = BASE | COMPARISON | MATH | BITWISE
103
+ BOOLEAN = BASE | COMPARISON | BOOLEAN_ALGEBRA | COMPARISON
104
+ BINARY = BASE | COMPARISON | CONTAINS | CONCATENABLE | INDEXABLE
105
+ DATETIME = BASE | COMPARISON | DATE_ARITHEMETIC
106
+ JSON = BASE | COMPARISON | INDEXABLE | JSON_GETITEM
107
+ ARRAY = BASE | COMPARISON | CONTAINS | CONCATENABLE | INDEXABLE
108
+ TUPLE = BASE | COMPARISON | CONTAINS | CONCATENABLE | INDEXABLE
109
+
110
+ ANY = (
111
+ STRING
112
+ | INTEGER
113
+ | NUMERIC
114
+ | BOOLEAN
115
+ | DATETIME
116
+ | BINARY
117
+ | JSON
118
+ | ARRAY
119
+ | TUPLE
120
+ )
121
+
122
+
123
+ class OperatorType(Hashable, Protocol):
124
+ """describe an op() function."""
125
+
126
+ __slots__ = ()
127
+
128
+ __name__: str
129
+
130
+ @overload
131
+ def __call__(
132
+ self,
133
+ left: ColumnExpressionArgument[Any],
134
+ right: Optional[Any] = None,
135
+ *other: Any,
136
+ **kwargs: Any,
137
+ ) -> ColumnElement[Any]: ...
138
+
139
+ @overload
140
+ def __call__(
141
+ self,
142
+ left: Operators,
143
+ right: Optional[Any] = None,
144
+ *other: Any,
145
+ **kwargs: Any,
146
+ ) -> Operators: ...
147
+
148
+ def __call__(
149
+ self,
150
+ left: Any,
151
+ right: Optional[Any] = None,
152
+ *other: Any,
153
+ **kwargs: Any,
154
+ ) -> Operators: ...
155
+
156
+
157
+ add = cast(OperatorType, _uncast_add)
158
+ and_ = cast(OperatorType, _uncast_and_)
159
+ contains = cast(OperatorType, _uncast_contains)
160
+ eq = cast(OperatorType, _uncast_eq)
161
+ floordiv = cast(OperatorType, _uncast_floordiv)
162
+ ge = cast(OperatorType, _uncast_ge)
163
+ getitem = cast(OperatorType, _uncast_getitem)
164
+ gt = cast(OperatorType, _uncast_gt)
165
+ inv = cast(OperatorType, _uncast_inv)
166
+ le = cast(OperatorType, _uncast_le)
167
+ lshift = cast(OperatorType, _uncast_lshift)
168
+ lt = cast(OperatorType, _uncast_lt)
169
+ matmul = cast(OperatorType, _uncast_matmul)
170
+ mod = cast(OperatorType, _uncast_mod)
171
+ mul = cast(OperatorType, _uncast_mul)
172
+ ne = cast(OperatorType, _uncast_ne)
173
+ neg = cast(OperatorType, _uncast_neg)
174
+ or_ = cast(OperatorType, _uncast_or_)
175
+ pow_ = cast(OperatorType, _uncast_pow)
176
+ rshift = cast(OperatorType, _uncast_rshift)
177
+ sub = cast(OperatorType, _uncast_sub)
178
+ truediv = cast(OperatorType, _uncast_truediv)
179
+
180
+
181
+ class Operators:
182
+ """Base of comparison and logical operators.
183
+
184
+ Implements base methods
185
+ :meth:`~sqlalchemy.sql.operators.Operators.operate` and
186
+ :meth:`~sqlalchemy.sql.operators.Operators.reverse_operate`, as well as
187
+ :meth:`~sqlalchemy.sql.operators.Operators.__and__`,
188
+ :meth:`~sqlalchemy.sql.operators.Operators.__or__`,
189
+ :meth:`~sqlalchemy.sql.operators.Operators.__invert__`.
190
+
191
+ Usually is used via its most common subclass
192
+ :class:`.ColumnOperators`.
193
+
194
+ """
195
+
196
+ __slots__ = ()
197
+
198
+ def __and__(self, other: Any) -> Operators:
199
+ """Implement the ``&`` operator.
200
+
201
+ When used with SQL expressions, results in an
202
+ AND operation, equivalent to
203
+ :func:`_expression.and_`, that is::
204
+
205
+ a & b
206
+
207
+ is equivalent to::
208
+
209
+ from sqlalchemy import and_
210
+
211
+ and_(a, b)
212
+
213
+ Care should be taken when using ``&`` regarding
214
+ operator precedence; the ``&`` operator has the highest precedence.
215
+ The operands should be enclosed in parenthesis if they contain
216
+ further sub expressions::
217
+
218
+ (a == 2) & (b == 4)
219
+
220
+ """
221
+ return self.operate(and_, other)
222
+
223
+ def __or__(self, other: Any) -> Operators:
224
+ """Implement the ``|`` operator.
225
+
226
+ When used with SQL expressions, results in an
227
+ OR operation, equivalent to
228
+ :func:`_expression.or_`, that is::
229
+
230
+ a | b
231
+
232
+ is equivalent to::
233
+
234
+ from sqlalchemy import or_
235
+
236
+ or_(a, b)
237
+
238
+ Care should be taken when using ``|`` regarding
239
+ operator precedence; the ``|`` operator has the highest precedence.
240
+ The operands should be enclosed in parenthesis if they contain
241
+ further sub expressions::
242
+
243
+ (a == 2) | (b == 4)
244
+
245
+ """
246
+ return self.operate(or_, other)
247
+
248
+ def __invert__(self) -> Operators:
249
+ """Implement the ``~`` operator.
250
+
251
+ When used with SQL expressions, results in a
252
+ NOT operation, equivalent to
253
+ :func:`_expression.not_`, that is::
254
+
255
+ ~a
256
+
257
+ is equivalent to::
258
+
259
+ from sqlalchemy import not_
260
+
261
+ not_(a)
262
+
263
+ """
264
+ return self.operate(inv)
265
+
266
+ def _null_operate(self, other: Any) -> Operators:
267
+ """A 'null' operation available on all types, used for testing."""
268
+
269
+ return self.operate(null_op, other)
270
+
271
+ def op(
272
+ self,
273
+ opstring: str,
274
+ precedence: int = 0,
275
+ is_comparison: bool = False,
276
+ return_type: Optional[
277
+ Union[Type[TypeEngine[Any]], TypeEngine[Any]]
278
+ ] = None,
279
+ python_impl: Optional[Callable[..., Any]] = None,
280
+ operator_class: OperatorClass = OperatorClass.BASE,
281
+ visit_name: Optional[str] = None,
282
+ ) -> Callable[[Any], Operators]:
283
+ """Produce a generic operator function.
284
+
285
+ e.g.::
286
+
287
+ somecolumn.op("*")(5)
288
+
289
+ produces::
290
+
291
+ somecolumn * 5
292
+
293
+ This function can also be used to make bitwise operators explicit. For
294
+ example::
295
+
296
+ somecolumn.op("&")(0xFF)
297
+
298
+ is a bitwise AND of the value in ``somecolumn``.
299
+
300
+ :param opstring: a string which will be output as the infix operator
301
+ between this element and the expression passed to the
302
+ generated function.
303
+
304
+ :param precedence: precedence which the database is expected to apply
305
+ to the operator in SQL expressions. This integer value acts as a hint
306
+ for the SQL compiler to know when explicit parenthesis should be
307
+ rendered around a particular operation. A lower number will cause the
308
+ expression to be parenthesized when applied against another operator
309
+ with higher precedence. The default value of ``0`` is lower than all
310
+ operators except for the comma (``,``) and ``AS`` operators. A value
311
+ of 100 will be higher or equal to all operators, and -100 will be
312
+ lower than or equal to all operators.
313
+
314
+ .. seealso::
315
+
316
+ :ref:`faq_sql_expression_op_parenthesis` - detailed description
317
+ of how the SQLAlchemy SQL compiler renders parenthesis
318
+
319
+ :param is_comparison: legacy; if True, the operator will be considered
320
+ as a "comparison" operator, that is which evaluates to a boolean
321
+ true/false value, like ``==``, ``>``, etc. This flag is provided
322
+ so that ORM relationships can establish that the operator is a
323
+ comparison operator when used in a custom join condition.
324
+
325
+ Using the ``is_comparison`` parameter is superseded by using the
326
+ :meth:`.Operators.bool_op` method instead; this more succinct
327
+ operator sets this parameter automatically, but also provides
328
+ correct :pep:`484` typing support as the returned object will
329
+ express a "boolean" datatype, i.e. ``BinaryExpression[bool]``.
330
+
331
+ :param return_type: a :class:`.TypeEngine` class or object that will
332
+ force the return type of an expression produced by this operator
333
+ to be of that type. By default, operators that specify
334
+ :paramref:`.Operators.op.is_comparison` will resolve to
335
+ :class:`.Boolean`, and those that do not will be of the same
336
+ type as the left-hand operand.
337
+
338
+ :param python_impl: an optional Python function that can evaluate
339
+ two Python values in the same way as this operator works when
340
+ run on the database server. Useful for in-Python SQL expression
341
+ evaluation functions, such as for ORM hybrid attributes, and the
342
+ ORM "evaluator" used to match objects in a session after a multi-row
343
+ update or delete.
344
+
345
+ e.g.::
346
+
347
+ >>> expr = column("x").op("+", python_impl=lambda a, b: a + b)("y")
348
+
349
+ The operator for the above expression will also work for non-SQL
350
+ left and right objects::
351
+
352
+ >>> expr.operator(5, 10)
353
+ 15
354
+
355
+ .. versionadded:: 2.0
356
+
357
+ :param operator_class: optional :class:`.OperatorClass` which will be
358
+ applied to the :class:`.custom_op` created, which provides hints
359
+ as to which datatypes are appropriate for this operator. Defaults
360
+ to :attr:`.OperatorClass.BASE` which is appropriate for all
361
+ datatypes.
362
+
363
+ .. versionadded:: 2.1
364
+
365
+ .. seealso::
366
+
367
+ :meth:`.Operators.bool_op`
368
+
369
+ :ref:`types_operators`
370
+
371
+ :ref:`relationship_custom_operator`
372
+
373
+ :param visit_name: string name indicating a series of methods that
374
+ maybe be implemented by a :class:`.Dialect`, specifically using its
375
+ :class:`.SQLCompiler` implementation. The naming scheme is
376
+ ``visit_<visit_name>_op_[binary|unary]``; e.g. using the visit name
377
+ ``hstore`` means that a binary expression using the operator will
378
+ attempt to locate a method ``visit_hstore_op_binary()`` on the
379
+ target dialect's compiler class, which can then provide a compilation
380
+ string for the full binary expression.
381
+
382
+ .. versionadded:: 2.1
383
+
384
+ """
385
+ operator = custom_op(
386
+ opstring,
387
+ precedence=precedence,
388
+ is_comparison=is_comparison,
389
+ return_type=return_type,
390
+ python_impl=python_impl,
391
+ operator_class=operator_class,
392
+ visit_name=visit_name,
393
+ )
394
+
395
+ def against(other: Any) -> Operators:
396
+ return operator(self, other)
397
+
398
+ return against
399
+
400
+ def bool_op(
401
+ self,
402
+ opstring: str,
403
+ precedence: int = 0,
404
+ python_impl: Optional[Callable[..., Any]] = None,
405
+ ) -> Callable[[Any], Operators]:
406
+ """Return a custom boolean operator.
407
+
408
+ This method is shorthand for calling
409
+ :meth:`.Operators.op` and passing the
410
+ :paramref:`.Operators.op.is_comparison`
411
+ flag with True. A key advantage to using :meth:`.Operators.bool_op`
412
+ is that when using column constructs, the "boolean" nature of the
413
+ returned expression will be present for :pep:`484` purposes.
414
+
415
+ .. seealso::
416
+
417
+ :meth:`.Operators.op`
418
+
419
+ """
420
+ return self.op(
421
+ opstring,
422
+ precedence=precedence,
423
+ is_comparison=True,
424
+ python_impl=python_impl,
425
+ )
426
+
427
+ def operate(
428
+ self, op: OperatorType, *other: Any, **kwargs: Any
429
+ ) -> Operators:
430
+ r"""Operate on an argument.
431
+
432
+ This is the lowest level of operation, raises
433
+ :class:`NotImplementedError` by default.
434
+
435
+ Overriding this on a subclass can allow common
436
+ behavior to be applied to all operations.
437
+ For example, overriding :class:`.ColumnOperators`
438
+ to apply ``func.lower()`` to the left and right
439
+ side::
440
+
441
+ class MyComparator(ColumnOperators):
442
+ def operate(self, op, other, **kwargs):
443
+ return op(func.lower(self), func.lower(other), **kwargs)
444
+
445
+ :param op: Operator callable.
446
+ :param \*other: the 'other' side of the operation. Will
447
+ be a single scalar for most operations.
448
+ :param \**kwargs: modifiers. These may be passed by special
449
+ operators such as :meth:`ColumnOperators.contains`.
450
+
451
+
452
+ """
453
+ raise NotImplementedError(str(op))
454
+
455
+ __sa_operate__ = operate
456
+
457
+ def reverse_operate(
458
+ self, op: OperatorType, other: Any, **kwargs: Any
459
+ ) -> Operators:
460
+ """Reverse operate on an argument.
461
+
462
+ Usage is the same as :meth:`operate`.
463
+
464
+ """
465
+ raise NotImplementedError(str(op))
466
+
467
+
468
+ class custom_op(OperatorType, Generic[_T]):
469
+ """Represent a 'custom' operator.
470
+
471
+ :class:`.custom_op` is normally instantiated when the
472
+ :meth:`.Operators.op` or :meth:`.Operators.bool_op` methods
473
+ are used to create a custom operator callable. The class can also be
474
+ used directly when programmatically constructing expressions. E.g.
475
+ to represent the "factorial" operation::
476
+
477
+ from sqlalchemy.sql import UnaryExpression
478
+ from sqlalchemy.sql import operators
479
+ from sqlalchemy import Numeric
480
+
481
+ unary = UnaryExpression(
482
+ table.c.somecolumn, modifier=operators.custom_op("!"), type_=Numeric
483
+ )
484
+
485
+ .. seealso::
486
+
487
+ :meth:`.Operators.op`
488
+
489
+ :meth:`.Operators.bool_op`
490
+
491
+ """ # noqa: E501
492
+
493
+ __name__ = "custom_op"
494
+
495
+ __slots__ = (
496
+ "opstring",
497
+ "precedence",
498
+ "is_comparison",
499
+ "natural_self_precedent",
500
+ "eager_grouping",
501
+ "return_type",
502
+ "python_impl",
503
+ "operator_class",
504
+ "visit_name",
505
+ )
506
+
507
+ def __init__(
508
+ self,
509
+ opstring: str,
510
+ *,
511
+ precedence: int = 0,
512
+ is_comparison: bool = False,
513
+ return_type: Optional[
514
+ Union[Type[TypeEngine[_T]], TypeEngine[_T]]
515
+ ] = None,
516
+ natural_self_precedent: bool = False,
517
+ eager_grouping: bool = False,
518
+ python_impl: Optional[Callable[..., Any]] = None,
519
+ operator_class: OperatorClass = OperatorClass.BASE,
520
+ visit_name: Optional[str] = None,
521
+ ):
522
+ """Create a new :class:`.custom_op`.
523
+
524
+ See :meth:`.Operators.op` for parameter information.
525
+
526
+ """
527
+ self.opstring = opstring
528
+ self.precedence = precedence
529
+ self.is_comparison = is_comparison
530
+ self.natural_self_precedent = natural_self_precedent
531
+ self.eager_grouping = eager_grouping
532
+ self.return_type = (
533
+ return_type._to_instance(return_type) if return_type else None
534
+ )
535
+ self.python_impl = python_impl
536
+ self.operator_class = operator_class
537
+ self.visit_name = visit_name
538
+
539
+ def __eq__(self, other: Any) -> bool:
540
+ return (
541
+ isinstance(other, custom_op)
542
+ and other._hash_key() == self._hash_key()
543
+ )
544
+
545
+ def __hash__(self) -> int:
546
+ return hash(self._hash_key())
547
+
548
+ def _hash_key(self) -> Union[CacheConst, Tuple[Any, ...]]:
549
+ return (
550
+ self.__class__,
551
+ self.opstring,
552
+ self.precedence,
553
+ self.is_comparison,
554
+ self.natural_self_precedent,
555
+ self.eager_grouping,
556
+ self.return_type._static_cache_key if self.return_type else None,
557
+ self.operator_class,
558
+ )
559
+
560
+ @overload
561
+ def __call__(
562
+ self,
563
+ left: ColumnExpressionArgument[Any],
564
+ right: Optional[Any] = None,
565
+ *other: Any,
566
+ **kwargs: Any,
567
+ ) -> ColumnElement[Any]: ...
568
+
569
+ @overload
570
+ def __call__(
571
+ self,
572
+ left: Operators,
573
+ right: Optional[Any] = None,
574
+ *other: Any,
575
+ **kwargs: Any,
576
+ ) -> Operators: ...
577
+
578
+ def __call__(
579
+ self,
580
+ left: Any,
581
+ right: Optional[Any] = None,
582
+ *other: Any,
583
+ **kwargs: Any,
584
+ ) -> Operators:
585
+ if hasattr(left, "__sa_operate__"):
586
+ return left.operate(self, right, *other, **kwargs) # type: ignore
587
+ elif self.python_impl:
588
+ return self.python_impl(left, right, *other, **kwargs) # type: ignore # noqa: E501
589
+ else:
590
+ raise exc.InvalidRequestError(
591
+ f"Custom operator {self.opstring!r} can't be used with "
592
+ "plain Python objects unless it includes the "
593
+ "'python_impl' parameter."
594
+ )
595
+
596
+
597
+ class OrderingOperators(Operators):
598
+ """defines ORDER BY operators, which can operate as single expressions
599
+ or comma-separated lists
600
+
601
+ """
602
+
603
+ __slots__ = ()
604
+
605
+ if typing.TYPE_CHECKING:
606
+
607
+ def operate(
608
+ self, op: OperatorType, *other: Any, **kwargs: Any
609
+ ) -> OrderingOperators: ...
610
+
611
+ def reverse_operate(
612
+ self, op: OperatorType, other: Any, **kwargs: Any
613
+ ) -> OrderingOperators: ...
614
+
615
+ def desc(self) -> OrderingOperators:
616
+ """Produce a :func:`_expression.desc` clause against the
617
+ parent object."""
618
+ return self.operate(desc_op)
619
+
620
+ def asc(self) -> OrderingOperators:
621
+ """Produce a :func:`_expression.asc` clause against the
622
+ parent object."""
623
+ return self.operate(asc_op)
624
+
625
+ def nulls_first(self) -> OrderingOperators:
626
+ """Produce a :func:`_expression.nulls_first` clause against the
627
+ parent object.
628
+
629
+ .. versionchanged:: 1.4 The ``nulls_first()`` operator is
630
+ renamed from ``nullsfirst()`` in previous releases.
631
+ The previous name remains available for backwards compatibility.
632
+ """
633
+ return self.operate(nulls_first_op)
634
+
635
+ # deprecated 1.4; see #5435
636
+ if TYPE_CHECKING:
637
+
638
+ def nullsfirst(self) -> OrderingOperators: ...
639
+
640
+ else:
641
+ nullsfirst = nulls_first
642
+
643
+ def nulls_last(self) -> OrderingOperators:
644
+ """Produce a :func:`_expression.nulls_last` clause against the
645
+ parent object.
646
+
647
+ .. versionchanged:: 1.4 The ``nulls_last()`` operator is
648
+ renamed from ``nullslast()`` in previous releases.
649
+ The previous name remains available for backwards compatibility.
650
+ """
651
+ return self.operate(nulls_last_op)
652
+
653
+ # deprecated 1.4; see #5429
654
+ if TYPE_CHECKING:
655
+
656
+ def nullslast(self) -> OrderingOperators: ...
657
+
658
+ else:
659
+ nullslast = nulls_last
660
+
661
+
662
+ class ColumnOperators(OrderingOperators):
663
+ """Defines boolean, comparison, and other operators for
664
+ :class:`_expression.ColumnElement` expressions.
665
+
666
+ By default, all methods call down to
667
+ :meth:`.operate` or :meth:`.reverse_operate`,
668
+ passing in the appropriate operator function from the
669
+ Python builtin ``operator`` module or
670
+ a SQLAlchemy-specific operator function from
671
+ :mod:`sqlalchemy.expression.operators`. For example
672
+ the ``__eq__`` function::
673
+
674
+ def __eq__(self, other):
675
+ return self.operate(operators.eq, other)
676
+
677
+ Where ``operators.eq`` is essentially::
678
+
679
+ def eq(a, b):
680
+ return a == b
681
+
682
+ The core column expression unit :class:`_expression.ColumnElement`
683
+ overrides :meth:`.Operators.operate` and others
684
+ to return further :class:`_expression.ColumnElement` constructs,
685
+ so that the ``==`` operation above is replaced by a clause
686
+ construct.
687
+
688
+ .. seealso::
689
+
690
+ :ref:`types_operators`
691
+
692
+ :attr:`.TypeEngine.comparator_factory`
693
+
694
+ :class:`.ColumnOperators`
695
+
696
+ :class:`.PropComparator`
697
+
698
+ """
699
+
700
+ __slots__ = ()
701
+
702
+ timetuple: Literal[None] = None
703
+ """Hack, allows datetime objects to be compared on the LHS."""
704
+
705
+ if typing.TYPE_CHECKING:
706
+
707
+ def operate(
708
+ self, op: OperatorType, *other: Any, **kwargs: Any
709
+ ) -> ColumnOperators: ...
710
+
711
+ def reverse_operate(
712
+ self, op: OperatorType, other: Any, **kwargs: Any
713
+ ) -> ColumnOperators: ...
714
+
715
+ def __lt__(self, other: Any) -> ColumnOperators:
716
+ """Implement the ``<`` operator.
717
+
718
+ In a column context, produces the clause ``a < b``.
719
+
720
+ """
721
+ return self.operate(lt, other)
722
+
723
+ def __le__(self, other: Any) -> ColumnOperators:
724
+ """Implement the ``<=`` operator.
725
+
726
+ In a column context, produces the clause ``a <= b``.
727
+
728
+ """
729
+ return self.operate(le, other)
730
+
731
+ # ColumnOperators defines an __eq__ so it must explicitly declare also
732
+ # an hash or it's set to None by python:
733
+ # https://docs.python.org/3/reference/datamodel.html#object.__hash__
734
+ if TYPE_CHECKING:
735
+
736
+ def __hash__(self) -> int: ...
737
+
738
+ else:
739
+ __hash__ = Operators.__hash__
740
+
741
+ def __eq__(self, other: Any) -> ColumnOperators: # type: ignore[override]
742
+ """Implement the ``==`` operator.
743
+
744
+ In a column context, produces the clause ``a = b``.
745
+ If the target is ``None``, produces ``a IS NULL``.
746
+
747
+ """
748
+ return self.operate(eq, other)
749
+
750
+ def __ne__(self, other: Any) -> ColumnOperators: # type: ignore[override]
751
+ """Implement the ``!=`` operator.
752
+
753
+ In a column context, produces the clause ``a != b``.
754
+ If the target is ``None``, produces ``a IS NOT NULL``.
755
+
756
+ """
757
+ return self.operate(ne, other)
758
+
759
+ def is_distinct_from(self, other: Any) -> ColumnOperators:
760
+ """Implement the ``IS DISTINCT FROM`` operator.
761
+
762
+ Renders "a IS DISTINCT FROM b" on most platforms;
763
+ on some such as SQLite may render "a IS NOT b".
764
+
765
+ """
766
+ return self.operate(is_distinct_from, other)
767
+
768
+ def is_not_distinct_from(self, other: Any) -> ColumnOperators:
769
+ """Implement the ``IS NOT DISTINCT FROM`` operator.
770
+
771
+ Renders "a IS NOT DISTINCT FROM b" on most platforms;
772
+ on some such as SQLite may render "a IS b".
773
+
774
+ .. versionchanged:: 1.4 The ``is_not_distinct_from()`` operator is
775
+ renamed from ``isnot_distinct_from()`` in previous releases.
776
+ The previous name remains available for backwards compatibility.
777
+
778
+ """
779
+ return self.operate(is_not_distinct_from, other)
780
+
781
+ # deprecated 1.4; see #5435
782
+ if TYPE_CHECKING:
783
+
784
+ def isnot_distinct_from(self, other: Any) -> ColumnOperators: ...
785
+
786
+ else:
787
+ isnot_distinct_from = is_not_distinct_from
788
+
789
+ def __gt__(self, other: Any) -> ColumnOperators:
790
+ """Implement the ``>`` operator.
791
+
792
+ In a column context, produces the clause ``a > b``.
793
+
794
+ """
795
+ return self.operate(gt, other)
796
+
797
+ def __ge__(self, other: Any) -> ColumnOperators:
798
+ """Implement the ``>=`` operator.
799
+
800
+ In a column context, produces the clause ``a >= b``.
801
+
802
+ """
803
+ return self.operate(ge, other)
804
+
805
+ def __neg__(self) -> ColumnOperators:
806
+ """Implement the ``-`` operator.
807
+
808
+ In a column context, produces the clause ``-a``.
809
+
810
+ """
811
+ return self.operate(neg)
812
+
813
+ def __contains__(self, other: Any) -> ColumnOperators:
814
+ return self.operate(contains, other)
815
+
816
+ def __getitem__(self, index: Any) -> ColumnOperators:
817
+ """Implement the [] operator.
818
+
819
+ This can be used by some database-specific types
820
+ such as PostgreSQL ARRAY and HSTORE.
821
+
822
+ """
823
+ return self.operate(getitem, index)
824
+
825
+ def __lshift__(self, other: Any) -> ColumnOperators:
826
+ """Implement the ``<<`` operator.
827
+
828
+ Not used by SQLAlchemy core, this is provided
829
+ for custom operator systems which want to use
830
+ << as an extension point.
831
+ """
832
+ return self.operate(lshift, other)
833
+
834
+ def __rlshift__(self, other: Any) -> ColumnOperators:
835
+ """Implement the ``<<`` operator in reverse.
836
+
837
+ Not used by SQLAlchemy core, this is provided
838
+ for custom operator systems which want to use
839
+ << as an extension point.
840
+ """
841
+ return self.reverse_operate(lshift, other)
842
+
843
+ def __rshift__(self, other: Any) -> ColumnOperators:
844
+ """Implement the ``>>`` operator.
845
+
846
+ Not used by SQLAlchemy core, this is provided
847
+ for custom operator systems which want to use
848
+ >> as an extension point.
849
+ """
850
+ return self.operate(rshift, other)
851
+
852
+ def __rrshift__(self, other: Any) -> ColumnOperators:
853
+ """Implement the ``>>`` operator in reverse.
854
+
855
+ Not used by SQLAlchemy core, this is provided
856
+ for custom operator systems which want to use
857
+ >> as an extension point.
858
+ """
859
+ return self.reverse_operate(rshift, other)
860
+
861
+ def __matmul__(self, other: Any) -> ColumnOperators:
862
+ """Implement the ``@`` operator.
863
+
864
+ Not used by SQLAlchemy core, this is provided
865
+ for custom operator systems which want to use
866
+ @ as an extension point.
867
+ """
868
+ return self.operate(matmul, other)
869
+
870
+ def __rmatmul__(self, other: Any) -> ColumnOperators:
871
+ """Implement the ``@`` operator in reverse.
872
+
873
+ Not used by SQLAlchemy core, this is provided
874
+ for custom operator systems which want to use
875
+ @ as an extension point.
876
+ """
877
+ return self.reverse_operate(matmul, other)
878
+
879
+ def concat(self, other: Any) -> ColumnOperators:
880
+ """Implement the 'concat' operator.
881
+
882
+ In a column context, produces the clause ``a || b``,
883
+ or uses the ``concat()`` operator on MySQL.
884
+
885
+ """
886
+ return self.operate(concat_op, other)
887
+
888
+ def _rconcat(self, other: Any) -> ColumnOperators:
889
+ """Implement an 'rconcat' operator.
890
+
891
+ this is for internal use at the moment
892
+
893
+ .. versionadded:: 1.4.40
894
+
895
+ """
896
+ return self.reverse_operate(concat_op, other)
897
+
898
+ def like(
899
+ self, other: Any, escape: Optional[str] = None
900
+ ) -> ColumnOperators:
901
+ r"""Implement the ``like`` operator.
902
+
903
+ In a column context, produces the expression:
904
+
905
+ .. sourcecode:: sql
906
+
907
+ a LIKE other
908
+
909
+ E.g.::
910
+
911
+ stmt = select(sometable).where(sometable.c.column.like("%foobar%"))
912
+
913
+ :param other: expression to be compared
914
+ :param escape: optional escape character, renders the ``ESCAPE``
915
+ keyword, e.g.::
916
+
917
+ somecolumn.like("foo/%bar", escape="/")
918
+
919
+ .. seealso::
920
+
921
+ :meth:`.ColumnOperators.ilike`
922
+
923
+ """
924
+ return self.operate(like_op, other, escape=escape)
925
+
926
+ def ilike(
927
+ self, other: Any, escape: Optional[str] = None
928
+ ) -> ColumnOperators:
929
+ r"""Implement the ``ilike`` operator, e.g. case insensitive LIKE.
930
+
931
+ In a column context, produces an expression either of the form:
932
+
933
+ .. sourcecode:: sql
934
+
935
+ lower(a) LIKE lower(other)
936
+
937
+ Or on backends that support the ILIKE operator:
938
+
939
+ .. sourcecode:: sql
940
+
941
+ a ILIKE other
942
+
943
+ E.g.::
944
+
945
+ stmt = select(sometable).where(sometable.c.column.ilike("%foobar%"))
946
+
947
+ :param other: expression to be compared
948
+ :param escape: optional escape character, renders the ``ESCAPE``
949
+ keyword, e.g.::
950
+
951
+ somecolumn.ilike("foo/%bar", escape="/")
952
+
953
+ .. seealso::
954
+
955
+ :meth:`.ColumnOperators.like`
956
+
957
+ """ # noqa: E501
958
+ return self.operate(ilike_op, other, escape=escape)
959
+
960
+ def bitwise_xor(self, other: Any) -> ColumnOperators:
961
+ """Produce a bitwise XOR operation, typically via the ``^``
962
+ operator, or ``#`` for PostgreSQL.
963
+
964
+ .. versionadded:: 2.0.2
965
+
966
+ .. seealso::
967
+
968
+ :ref:`operators_bitwise`
969
+
970
+ """
971
+
972
+ return self.operate(bitwise_xor_op, other)
973
+
974
+ def bitwise_or(self, other: Any) -> ColumnOperators:
975
+ """Produce a bitwise OR operation, typically via the ``|``
976
+ operator.
977
+
978
+ .. versionadded:: 2.0.2
979
+
980
+ .. seealso::
981
+
982
+ :ref:`operators_bitwise`
983
+
984
+ """
985
+
986
+ return self.operate(bitwise_or_op, other)
987
+
988
+ def bitwise_and(self, other: Any) -> ColumnOperators:
989
+ """Produce a bitwise AND operation, typically via the ``&``
990
+ operator.
991
+
992
+ .. versionadded:: 2.0.2
993
+
994
+ .. seealso::
995
+
996
+ :ref:`operators_bitwise`
997
+
998
+ """
999
+
1000
+ return self.operate(bitwise_and_op, other)
1001
+
1002
+ def bitwise_not(self) -> ColumnOperators:
1003
+ """Produce a bitwise NOT operation, typically via the ``~``
1004
+ operator.
1005
+
1006
+ .. versionadded:: 2.0.2
1007
+
1008
+ .. seealso::
1009
+
1010
+ :ref:`operators_bitwise`
1011
+
1012
+ """
1013
+
1014
+ return self.operate(bitwise_not_op)
1015
+
1016
+ def bitwise_lshift(self, other: Any) -> ColumnOperators:
1017
+ """Produce a bitwise LSHIFT operation, typically via the ``<<``
1018
+ operator.
1019
+
1020
+ .. versionadded:: 2.0.2
1021
+
1022
+ .. seealso::
1023
+
1024
+ :ref:`operators_bitwise`
1025
+
1026
+ """
1027
+
1028
+ return self.operate(bitwise_lshift_op, other)
1029
+
1030
+ def bitwise_rshift(self, other: Any) -> ColumnOperators:
1031
+ """Produce a bitwise RSHIFT operation, typically via the ``>>``
1032
+ operator.
1033
+
1034
+ .. versionadded:: 2.0.2
1035
+
1036
+ .. seealso::
1037
+
1038
+ :ref:`operators_bitwise`
1039
+
1040
+ """
1041
+
1042
+ return self.operate(bitwise_rshift_op, other)
1043
+
1044
+ def in_(self, other: Any) -> ColumnOperators:
1045
+ """Implement the ``in`` operator.
1046
+
1047
+ In a column context, produces the clause ``column IN <other>``.
1048
+
1049
+ The given parameter ``other`` may be:
1050
+
1051
+ * A list of literal values,
1052
+ e.g.::
1053
+
1054
+ stmt.where(column.in_([1, 2, 3]))
1055
+
1056
+ In this calling form, the list of items is converted to a set of
1057
+ bound parameters the same length as the list given:
1058
+
1059
+ .. sourcecode:: sql
1060
+
1061
+ WHERE COL IN (?, ?, ?)
1062
+
1063
+ * A list of tuples may be provided if the comparison is against a
1064
+ :func:`.tuple_` containing multiple expressions::
1065
+
1066
+ from sqlalchemy import tuple_
1067
+
1068
+ stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)]))
1069
+
1070
+ * An empty list,
1071
+ e.g.::
1072
+
1073
+ stmt.where(column.in_([]))
1074
+
1075
+ In this calling form, the expression renders an "empty set"
1076
+ expression. These expressions are tailored to individual backends
1077
+ and are generally trying to get an empty SELECT statement as a
1078
+ subquery. Such as on SQLite, the expression is:
1079
+
1080
+ .. sourcecode:: sql
1081
+
1082
+ WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)
1083
+
1084
+ .. versionchanged:: 1.4 empty IN expressions now use an
1085
+ execution-time generated SELECT subquery in all cases.
1086
+
1087
+ * A bound parameter, e.g. :func:`.bindparam`, may be used if it
1088
+ includes the :paramref:`.bindparam.expanding` flag::
1089
+
1090
+ stmt.where(column.in_(bindparam("value", expanding=True)))
1091
+
1092
+ In this calling form, the expression renders a special non-SQL
1093
+ placeholder expression that looks like:
1094
+
1095
+ .. sourcecode:: sql
1096
+
1097
+ WHERE COL IN ([EXPANDING_value])
1098
+
1099
+ This placeholder expression is intercepted at statement execution
1100
+ time to be converted into the variable number of bound parameter
1101
+ form illustrated earlier. If the statement were executed as::
1102
+
1103
+ connection.execute(stmt, {"value": [1, 2, 3]})
1104
+
1105
+ The database would be passed a bound parameter for each value:
1106
+
1107
+ .. sourcecode:: sql
1108
+
1109
+ WHERE COL IN (?, ?, ?)
1110
+
1111
+ If an empty list is passed, a special "empty list" expression,
1112
+ which is specific to the database in use, is rendered. On
1113
+ SQLite this would be:
1114
+
1115
+ .. sourcecode:: sql
1116
+
1117
+ WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)
1118
+
1119
+ * a :func:`_expression.select` construct, which is usually a
1120
+ correlated scalar select::
1121
+
1122
+ stmt.where(
1123
+ column.in_(select(othertable.c.y).where(table.c.x == othertable.c.x))
1124
+ )
1125
+
1126
+ In this calling form, :meth:`.ColumnOperators.in_` renders as given:
1127
+
1128
+ .. sourcecode:: sql
1129
+
1130
+ WHERE COL IN (SELECT othertable.y
1131
+ FROM othertable WHERE othertable.x = table.x)
1132
+
1133
+ :param other: a list of literals, a :func:`_expression.select`
1134
+ construct, or a :func:`.bindparam` construct that includes the
1135
+ :paramref:`.bindparam.expanding` flag set to True.
1136
+
1137
+ """ # noqa: E501
1138
+ return self.operate(in_op, other)
1139
+
1140
+ def not_in(self, other: Any) -> ColumnOperators:
1141
+ """implement the ``NOT IN`` operator.
1142
+
1143
+ This is equivalent to using negation with
1144
+ :meth:`.ColumnOperators.in_`, i.e. ``~x.in_(y)``.
1145
+
1146
+ In the case that ``other`` is an empty sequence, the compiler
1147
+ produces an "empty not in" expression. This defaults to the
1148
+ expression "1 = 1" to produce true in all cases. The
1149
+ :paramref:`_sa.create_engine.empty_in_strategy` may be used to
1150
+ alter this behavior.
1151
+
1152
+ .. versionchanged:: 1.4 The ``not_in()`` operator is renamed from
1153
+ ``notin_()`` in previous releases. The previous name remains
1154
+ available for backwards compatibility.
1155
+
1156
+ .. seealso::
1157
+
1158
+ :meth:`.ColumnOperators.in_`
1159
+
1160
+ """
1161
+ return self.operate(not_in_op, other)
1162
+
1163
+ # deprecated 1.4; see #5429
1164
+ if TYPE_CHECKING:
1165
+
1166
+ def notin_(self, other: Any) -> ColumnOperators: ...
1167
+
1168
+ else:
1169
+ notin_ = not_in
1170
+
1171
+ def not_like(
1172
+ self, other: Any, escape: Optional[str] = None
1173
+ ) -> ColumnOperators:
1174
+ """implement the ``NOT LIKE`` operator.
1175
+
1176
+ This is equivalent to using negation with
1177
+ :meth:`.ColumnOperators.like`, i.e. ``~x.like(y)``.
1178
+
1179
+ .. versionchanged:: 1.4 The ``not_like()`` operator is renamed from
1180
+ ``notlike()`` in previous releases. The previous name remains
1181
+ available for backwards compatibility.
1182
+
1183
+ .. seealso::
1184
+
1185
+ :meth:`.ColumnOperators.like`
1186
+
1187
+ """
1188
+ return self.operate(not_like_op, other, escape=escape)
1189
+
1190
+ # deprecated 1.4; see #5435
1191
+ if TYPE_CHECKING:
1192
+
1193
+ def notlike(
1194
+ self, other: Any, escape: Optional[str] = None
1195
+ ) -> ColumnOperators: ...
1196
+
1197
+ else:
1198
+ notlike = not_like
1199
+
1200
+ def not_ilike(
1201
+ self, other: Any, escape: Optional[str] = None
1202
+ ) -> ColumnOperators:
1203
+ """implement the ``NOT ILIKE`` operator.
1204
+
1205
+ This is equivalent to using negation with
1206
+ :meth:`.ColumnOperators.ilike`, i.e. ``~x.ilike(y)``.
1207
+
1208
+ .. versionchanged:: 1.4 The ``not_ilike()`` operator is renamed from
1209
+ ``notilike()`` in previous releases. The previous name remains
1210
+ available for backwards compatibility.
1211
+
1212
+ .. seealso::
1213
+
1214
+ :meth:`.ColumnOperators.ilike`
1215
+
1216
+ """
1217
+ return self.operate(not_ilike_op, other, escape=escape)
1218
+
1219
+ # deprecated 1.4; see #5435
1220
+ if TYPE_CHECKING:
1221
+
1222
+ def notilike(
1223
+ self, other: Any, escape: Optional[str] = None
1224
+ ) -> ColumnOperators: ...
1225
+
1226
+ else:
1227
+ notilike = not_ilike
1228
+
1229
+ def is_(self, other: Any) -> ColumnOperators:
1230
+ """Implement the ``IS`` operator.
1231
+
1232
+ Normally, ``IS`` is generated automatically when comparing to a
1233
+ value of ``None``, which resolves to ``NULL``. However, explicit
1234
+ usage of ``IS`` may be desirable if comparing to boolean values
1235
+ on certain platforms.
1236
+
1237
+ .. seealso:: :meth:`.ColumnOperators.is_not`
1238
+
1239
+ """
1240
+ return self.operate(is_, other)
1241
+
1242
+ def is_not(self, other: Any) -> ColumnOperators:
1243
+ """Implement the ``IS NOT`` operator.
1244
+
1245
+ Normally, ``IS NOT`` is generated automatically when comparing to a
1246
+ value of ``None``, which resolves to ``NULL``. However, explicit
1247
+ usage of ``IS NOT`` may be desirable if comparing to boolean values
1248
+ on certain platforms.
1249
+
1250
+ .. versionchanged:: 1.4 The ``is_not()`` operator is renamed from
1251
+ ``isnot()`` in previous releases. The previous name remains
1252
+ available for backwards compatibility.
1253
+
1254
+ .. seealso:: :meth:`.ColumnOperators.is_`
1255
+
1256
+ """
1257
+ return self.operate(is_not, other)
1258
+
1259
+ # deprecated 1.4; see #5429
1260
+ if TYPE_CHECKING:
1261
+
1262
+ def isnot(self, other: Any) -> ColumnOperators: ...
1263
+
1264
+ else:
1265
+ isnot = is_not
1266
+
1267
+ def startswith(
1268
+ self,
1269
+ other: Any,
1270
+ escape: Optional[str] = None,
1271
+ autoescape: bool = False,
1272
+ ) -> ColumnOperators:
1273
+ r"""Implement the ``startswith`` operator.
1274
+
1275
+ Produces a LIKE expression that tests against a match for the start
1276
+ of a string value:
1277
+
1278
+ .. sourcecode:: sql
1279
+
1280
+ column LIKE <other> || '%'
1281
+
1282
+ E.g.::
1283
+
1284
+ stmt = select(sometable).where(sometable.c.column.startswith("foobar"))
1285
+
1286
+ Since the operator uses ``LIKE``, wildcard characters
1287
+ ``"%"`` and ``"_"`` that are present inside the <other> expression
1288
+ will behave like wildcards as well. For literal string
1289
+ values, the :paramref:`.ColumnOperators.startswith.autoescape` flag
1290
+ may be set to ``True`` to apply escaping to occurrences of these
1291
+ characters within the string value so that they match as themselves
1292
+ and not as wildcard characters. Alternatively, the
1293
+ :paramref:`.ColumnOperators.startswith.escape` parameter will establish
1294
+ a given character as an escape character which can be of use when
1295
+ the target expression is not a literal string.
1296
+
1297
+ :param other: expression to be compared. This is usually a plain
1298
+ string value, but can also be an arbitrary SQL expression. LIKE
1299
+ wildcard characters ``%`` and ``_`` are not escaped by default unless
1300
+ the :paramref:`.ColumnOperators.startswith.autoescape` flag is
1301
+ set to True.
1302
+
1303
+ :param autoescape: boolean; when True, establishes an escape character
1304
+ within the LIKE expression, then applies it to all occurrences of
1305
+ ``"%"``, ``"_"`` and the escape character itself within the
1306
+ comparison value, which is assumed to be a literal string and not a
1307
+ SQL expression.
1308
+
1309
+ An expression such as::
1310
+
1311
+ somecolumn.startswith("foo%bar", autoescape=True)
1312
+
1313
+ Will render as:
1314
+
1315
+ .. sourcecode:: sql
1316
+
1317
+ somecolumn LIKE :param || '%' ESCAPE '/'
1318
+
1319
+ With the value of ``:param`` as ``"foo/%bar"``.
1320
+
1321
+ :param escape: a character which when given will render with the
1322
+ ``ESCAPE`` keyword to establish that character as the escape
1323
+ character. This character can then be placed preceding occurrences
1324
+ of ``%`` and ``_`` to allow them to act as themselves and not
1325
+ wildcard characters.
1326
+
1327
+ An expression such as::
1328
+
1329
+ somecolumn.startswith("foo/%bar", escape="^")
1330
+
1331
+ Will render as:
1332
+
1333
+ .. sourcecode:: sql
1334
+
1335
+ somecolumn LIKE :param || '%' ESCAPE '^'
1336
+
1337
+ The parameter may also be combined with
1338
+ :paramref:`.ColumnOperators.startswith.autoescape`::
1339
+
1340
+ somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True)
1341
+
1342
+ Where above, the given literal parameter will be converted to
1343
+ ``"foo^%bar^^bat"`` before being passed to the database.
1344
+
1345
+ .. seealso::
1346
+
1347
+ :meth:`.ColumnOperators.endswith`
1348
+
1349
+ :meth:`.ColumnOperators.contains`
1350
+
1351
+ :meth:`.ColumnOperators.like`
1352
+
1353
+ """ # noqa: E501
1354
+ return self.operate(
1355
+ startswith_op, other, escape=escape, autoescape=autoescape
1356
+ )
1357
+
1358
+ def istartswith(
1359
+ self,
1360
+ other: Any,
1361
+ escape: Optional[str] = None,
1362
+ autoescape: bool = False,
1363
+ ) -> ColumnOperators:
1364
+ r"""Implement the ``istartswith`` operator, e.g. case insensitive
1365
+ version of :meth:`.ColumnOperators.startswith`.
1366
+
1367
+ Produces a LIKE expression that tests against an insensitive
1368
+ match for the start of a string value:
1369
+
1370
+ .. sourcecode:: sql
1371
+
1372
+ lower(column) LIKE lower(<other>) || '%'
1373
+
1374
+ E.g.::
1375
+
1376
+ stmt = select(sometable).where(sometable.c.column.istartswith("foobar"))
1377
+
1378
+ Since the operator uses ``LIKE``, wildcard characters
1379
+ ``"%"`` and ``"_"`` that are present inside the <other> expression
1380
+ will behave like wildcards as well. For literal string
1381
+ values, the :paramref:`.ColumnOperators.istartswith.autoescape` flag
1382
+ may be set to ``True`` to apply escaping to occurrences of these
1383
+ characters within the string value so that they match as themselves
1384
+ and not as wildcard characters. Alternatively, the
1385
+ :paramref:`.ColumnOperators.istartswith.escape` parameter will
1386
+ establish a given character as an escape character which can be of
1387
+ use when the target expression is not a literal string.
1388
+
1389
+ :param other: expression to be compared. This is usually a plain
1390
+ string value, but can also be an arbitrary SQL expression. LIKE
1391
+ wildcard characters ``%`` and ``_`` are not escaped by default unless
1392
+ the :paramref:`.ColumnOperators.istartswith.autoescape` flag is
1393
+ set to True.
1394
+
1395
+ :param autoescape: boolean; when True, establishes an escape character
1396
+ within the LIKE expression, then applies it to all occurrences of
1397
+ ``"%"``, ``"_"`` and the escape character itself within the
1398
+ comparison value, which is assumed to be a literal string and not a
1399
+ SQL expression.
1400
+
1401
+ An expression such as::
1402
+
1403
+ somecolumn.istartswith("foo%bar", autoescape=True)
1404
+
1405
+ Will render as:
1406
+
1407
+ .. sourcecode:: sql
1408
+
1409
+ lower(somecolumn) LIKE lower(:param) || '%' ESCAPE '/'
1410
+
1411
+ With the value of ``:param`` as ``"foo/%bar"``.
1412
+
1413
+ :param escape: a character which when given will render with the
1414
+ ``ESCAPE`` keyword to establish that character as the escape
1415
+ character. This character can then be placed preceding occurrences
1416
+ of ``%`` and ``_`` to allow them to act as themselves and not
1417
+ wildcard characters.
1418
+
1419
+ An expression such as::
1420
+
1421
+ somecolumn.istartswith("foo/%bar", escape="^")
1422
+
1423
+ Will render as:
1424
+
1425
+ .. sourcecode:: sql
1426
+
1427
+ lower(somecolumn) LIKE lower(:param) || '%' ESCAPE '^'
1428
+
1429
+ The parameter may also be combined with
1430
+ :paramref:`.ColumnOperators.istartswith.autoescape`::
1431
+
1432
+ somecolumn.istartswith("foo%bar^bat", escape="^", autoescape=True)
1433
+
1434
+ Where above, the given literal parameter will be converted to
1435
+ ``"foo^%bar^^bat"`` before being passed to the database.
1436
+
1437
+ .. seealso::
1438
+
1439
+ :meth:`.ColumnOperators.startswith`
1440
+ """ # noqa: E501
1441
+ return self.operate(
1442
+ istartswith_op, other, escape=escape, autoescape=autoescape
1443
+ )
1444
+
1445
+ def endswith(
1446
+ self,
1447
+ other: Any,
1448
+ escape: Optional[str] = None,
1449
+ autoescape: bool = False,
1450
+ ) -> ColumnOperators:
1451
+ r"""Implement the 'endswith' operator.
1452
+
1453
+ Produces a LIKE expression that tests against a match for the end
1454
+ of a string value:
1455
+
1456
+ .. sourcecode:: sql
1457
+
1458
+ column LIKE '%' || <other>
1459
+
1460
+ E.g.::
1461
+
1462
+ stmt = select(sometable).where(sometable.c.column.endswith("foobar"))
1463
+
1464
+ Since the operator uses ``LIKE``, wildcard characters
1465
+ ``"%"`` and ``"_"`` that are present inside the <other> expression
1466
+ will behave like wildcards as well. For literal string
1467
+ values, the :paramref:`.ColumnOperators.endswith.autoescape` flag
1468
+ may be set to ``True`` to apply escaping to occurrences of these
1469
+ characters within the string value so that they match as themselves
1470
+ and not as wildcard characters. Alternatively, the
1471
+ :paramref:`.ColumnOperators.endswith.escape` parameter will establish
1472
+ a given character as an escape character which can be of use when
1473
+ the target expression is not a literal string.
1474
+
1475
+ :param other: expression to be compared. This is usually a plain
1476
+ string value, but can also be an arbitrary SQL expression. LIKE
1477
+ wildcard characters ``%`` and ``_`` are not escaped by default unless
1478
+ the :paramref:`.ColumnOperators.endswith.autoescape` flag is
1479
+ set to True.
1480
+
1481
+ :param autoescape: boolean; when True, establishes an escape character
1482
+ within the LIKE expression, then applies it to all occurrences of
1483
+ ``"%"``, ``"_"`` and the escape character itself within the
1484
+ comparison value, which is assumed to be a literal string and not a
1485
+ SQL expression.
1486
+
1487
+ An expression such as::
1488
+
1489
+ somecolumn.endswith("foo%bar", autoescape=True)
1490
+
1491
+ Will render as:
1492
+
1493
+ .. sourcecode:: sql
1494
+
1495
+ somecolumn LIKE '%' || :param ESCAPE '/'
1496
+
1497
+ With the value of ``:param`` as ``"foo/%bar"``.
1498
+
1499
+ :param escape: a character which when given will render with the
1500
+ ``ESCAPE`` keyword to establish that character as the escape
1501
+ character. This character can then be placed preceding occurrences
1502
+ of ``%`` and ``_`` to allow them to act as themselves and not
1503
+ wildcard characters.
1504
+
1505
+ An expression such as::
1506
+
1507
+ somecolumn.endswith("foo/%bar", escape="^")
1508
+
1509
+ Will render as:
1510
+
1511
+ .. sourcecode:: sql
1512
+
1513
+ somecolumn LIKE '%' || :param ESCAPE '^'
1514
+
1515
+ The parameter may also be combined with
1516
+ :paramref:`.ColumnOperators.endswith.autoescape`::
1517
+
1518
+ somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)
1519
+
1520
+ Where above, the given literal parameter will be converted to
1521
+ ``"foo^%bar^^bat"`` before being passed to the database.
1522
+
1523
+ .. seealso::
1524
+
1525
+ :meth:`.ColumnOperators.startswith`
1526
+
1527
+ :meth:`.ColumnOperators.contains`
1528
+
1529
+ :meth:`.ColumnOperators.like`
1530
+
1531
+ """ # noqa: E501
1532
+ return self.operate(
1533
+ endswith_op, other, escape=escape, autoescape=autoescape
1534
+ )
1535
+
1536
+ def iendswith(
1537
+ self,
1538
+ other: Any,
1539
+ escape: Optional[str] = None,
1540
+ autoescape: bool = False,
1541
+ ) -> ColumnOperators:
1542
+ r"""Implement the ``iendswith`` operator, e.g. case insensitive
1543
+ version of :meth:`.ColumnOperators.endswith`.
1544
+
1545
+ Produces a LIKE expression that tests against an insensitive match
1546
+ for the end of a string value:
1547
+
1548
+ .. sourcecode:: sql
1549
+
1550
+ lower(column) LIKE '%' || lower(<other>)
1551
+
1552
+ E.g.::
1553
+
1554
+ stmt = select(sometable).where(sometable.c.column.iendswith("foobar"))
1555
+
1556
+ Since the operator uses ``LIKE``, wildcard characters
1557
+ ``"%"`` and ``"_"`` that are present inside the <other> expression
1558
+ will behave like wildcards as well. For literal string
1559
+ values, the :paramref:`.ColumnOperators.iendswith.autoescape` flag
1560
+ may be set to ``True`` to apply escaping to occurrences of these
1561
+ characters within the string value so that they match as themselves
1562
+ and not as wildcard characters. Alternatively, the
1563
+ :paramref:`.ColumnOperators.iendswith.escape` parameter will establish
1564
+ a given character as an escape character which can be of use when
1565
+ the target expression is not a literal string.
1566
+
1567
+ :param other: expression to be compared. This is usually a plain
1568
+ string value, but can also be an arbitrary SQL expression. LIKE
1569
+ wildcard characters ``%`` and ``_`` are not escaped by default unless
1570
+ the :paramref:`.ColumnOperators.iendswith.autoescape` flag is
1571
+ set to True.
1572
+
1573
+ :param autoescape: boolean; when True, establishes an escape character
1574
+ within the LIKE expression, then applies it to all occurrences of
1575
+ ``"%"``, ``"_"`` and the escape character itself within the
1576
+ comparison value, which is assumed to be a literal string and not a
1577
+ SQL expression.
1578
+
1579
+ An expression such as::
1580
+
1581
+ somecolumn.iendswith("foo%bar", autoescape=True)
1582
+
1583
+ Will render as:
1584
+
1585
+ .. sourcecode:: sql
1586
+
1587
+ lower(somecolumn) LIKE '%' || lower(:param) ESCAPE '/'
1588
+
1589
+ With the value of ``:param`` as ``"foo/%bar"``.
1590
+
1591
+ :param escape: a character which when given will render with the
1592
+ ``ESCAPE`` keyword to establish that character as the escape
1593
+ character. This character can then be placed preceding occurrences
1594
+ of ``%`` and ``_`` to allow them to act as themselves and not
1595
+ wildcard characters.
1596
+
1597
+ An expression such as::
1598
+
1599
+ somecolumn.iendswith("foo/%bar", escape="^")
1600
+
1601
+ Will render as:
1602
+
1603
+ .. sourcecode:: sql
1604
+
1605
+ lower(somecolumn) LIKE '%' || lower(:param) ESCAPE '^'
1606
+
1607
+ The parameter may also be combined with
1608
+ :paramref:`.ColumnOperators.iendswith.autoescape`::
1609
+
1610
+ somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)
1611
+
1612
+ Where above, the given literal parameter will be converted to
1613
+ ``"foo^%bar^^bat"`` before being passed to the database.
1614
+
1615
+ .. seealso::
1616
+
1617
+ :meth:`.ColumnOperators.endswith`
1618
+ """ # noqa: E501
1619
+ return self.operate(
1620
+ iendswith_op, other, escape=escape, autoescape=autoescape
1621
+ )
1622
+
1623
+ def contains(self, other: Any, **kw: Any) -> ColumnOperators:
1624
+ r"""Implement the 'contains' operator.
1625
+
1626
+ Produces a LIKE expression that tests against a match for the middle
1627
+ of a string value:
1628
+
1629
+ .. sourcecode:: sql
1630
+
1631
+ column LIKE '%' || <other> || '%'
1632
+
1633
+ E.g.::
1634
+
1635
+ stmt = select(sometable).where(sometable.c.column.contains("foobar"))
1636
+
1637
+ Since the operator uses ``LIKE``, wildcard characters
1638
+ ``"%"`` and ``"_"`` that are present inside the <other> expression
1639
+ will behave like wildcards as well. For literal string
1640
+ values, the :paramref:`.ColumnOperators.contains.autoescape` flag
1641
+ may be set to ``True`` to apply escaping to occurrences of these
1642
+ characters within the string value so that they match as themselves
1643
+ and not as wildcard characters. Alternatively, the
1644
+ :paramref:`.ColumnOperators.contains.escape` parameter will establish
1645
+ a given character as an escape character which can be of use when
1646
+ the target expression is not a literal string.
1647
+
1648
+ :param other: expression to be compared. This is usually a plain
1649
+ string value, but can also be an arbitrary SQL expression. LIKE
1650
+ wildcard characters ``%`` and ``_`` are not escaped by default unless
1651
+ the :paramref:`.ColumnOperators.contains.autoescape` flag is
1652
+ set to True.
1653
+
1654
+ :param autoescape: boolean; when True, establishes an escape character
1655
+ within the LIKE expression, then applies it to all occurrences of
1656
+ ``"%"``, ``"_"`` and the escape character itself within the
1657
+ comparison value, which is assumed to be a literal string and not a
1658
+ SQL expression.
1659
+
1660
+ An expression such as::
1661
+
1662
+ somecolumn.contains("foo%bar", autoescape=True)
1663
+
1664
+ Will render as:
1665
+
1666
+ .. sourcecode:: sql
1667
+
1668
+ somecolumn LIKE '%' || :param || '%' ESCAPE '/'
1669
+
1670
+ With the value of ``:param`` as ``"foo/%bar"``.
1671
+
1672
+ :param escape: a character which when given will render with the
1673
+ ``ESCAPE`` keyword to establish that character as the escape
1674
+ character. This character can then be placed preceding occurrences
1675
+ of ``%`` and ``_`` to allow them to act as themselves and not
1676
+ wildcard characters.
1677
+
1678
+ An expression such as::
1679
+
1680
+ somecolumn.contains("foo/%bar", escape="^")
1681
+
1682
+ Will render as:
1683
+
1684
+ .. sourcecode:: sql
1685
+
1686
+ somecolumn LIKE '%' || :param || '%' ESCAPE '^'
1687
+
1688
+ The parameter may also be combined with
1689
+ :paramref:`.ColumnOperators.contains.autoescape`::
1690
+
1691
+ somecolumn.contains("foo%bar^bat", escape="^", autoescape=True)
1692
+
1693
+ Where above, the given literal parameter will be converted to
1694
+ ``"foo^%bar^^bat"`` before being passed to the database.
1695
+
1696
+ .. seealso::
1697
+
1698
+ :meth:`.ColumnOperators.startswith`
1699
+
1700
+ :meth:`.ColumnOperators.endswith`
1701
+
1702
+ :meth:`.ColumnOperators.like`
1703
+
1704
+
1705
+ """ # noqa: E501
1706
+ return self.operate(contains_op, other, **kw)
1707
+
1708
+ def icontains(self, other: Any, **kw: Any) -> ColumnOperators:
1709
+ r"""Implement the ``icontains`` operator, e.g. case insensitive
1710
+ version of :meth:`.ColumnOperators.contains`.
1711
+
1712
+ Produces a LIKE expression that tests against an insensitive match
1713
+ for the middle of a string value:
1714
+
1715
+ .. sourcecode:: sql
1716
+
1717
+ lower(column) LIKE '%' || lower(<other>) || '%'
1718
+
1719
+ E.g.::
1720
+
1721
+ stmt = select(sometable).where(sometable.c.column.icontains("foobar"))
1722
+
1723
+ Since the operator uses ``LIKE``, wildcard characters
1724
+ ``"%"`` and ``"_"`` that are present inside the <other> expression
1725
+ will behave like wildcards as well. For literal string
1726
+ values, the :paramref:`.ColumnOperators.icontains.autoescape` flag
1727
+ may be set to ``True`` to apply escaping to occurrences of these
1728
+ characters within the string value so that they match as themselves
1729
+ and not as wildcard characters. Alternatively, the
1730
+ :paramref:`.ColumnOperators.icontains.escape` parameter will establish
1731
+ a given character as an escape character which can be of use when
1732
+ the target expression is not a literal string.
1733
+
1734
+ :param other: expression to be compared. This is usually a plain
1735
+ string value, but can also be an arbitrary SQL expression. LIKE
1736
+ wildcard characters ``%`` and ``_`` are not escaped by default unless
1737
+ the :paramref:`.ColumnOperators.icontains.autoescape` flag is
1738
+ set to True.
1739
+
1740
+ :param autoescape: boolean; when True, establishes an escape character
1741
+ within the LIKE expression, then applies it to all occurrences of
1742
+ ``"%"``, ``"_"`` and the escape character itself within the
1743
+ comparison value, which is assumed to be a literal string and not a
1744
+ SQL expression.
1745
+
1746
+ An expression such as::
1747
+
1748
+ somecolumn.icontains("foo%bar", autoescape=True)
1749
+
1750
+ Will render as:
1751
+
1752
+ .. sourcecode:: sql
1753
+
1754
+ lower(somecolumn) LIKE '%' || lower(:param) || '%' ESCAPE '/'
1755
+
1756
+ With the value of ``:param`` as ``"foo/%bar"``.
1757
+
1758
+ :param escape: a character which when given will render with the
1759
+ ``ESCAPE`` keyword to establish that character as the escape
1760
+ character. This character can then be placed preceding occurrences
1761
+ of ``%`` and ``_`` to allow them to act as themselves and not
1762
+ wildcard characters.
1763
+
1764
+ An expression such as::
1765
+
1766
+ somecolumn.icontains("foo/%bar", escape="^")
1767
+
1768
+ Will render as:
1769
+
1770
+ .. sourcecode:: sql
1771
+
1772
+ lower(somecolumn) LIKE '%' || lower(:param) || '%' ESCAPE '^'
1773
+
1774
+ The parameter may also be combined with
1775
+ :paramref:`.ColumnOperators.contains.autoescape`::
1776
+
1777
+ somecolumn.icontains("foo%bar^bat", escape="^", autoescape=True)
1778
+
1779
+ Where above, the given literal parameter will be converted to
1780
+ ``"foo^%bar^^bat"`` before being passed to the database.
1781
+
1782
+ .. seealso::
1783
+
1784
+ :meth:`.ColumnOperators.contains`
1785
+
1786
+ """ # noqa: E501
1787
+ return self.operate(icontains_op, other, **kw)
1788
+
1789
+ def match(self, other: Any, **kwargs: Any) -> ColumnOperators:
1790
+ """Implements a database-specific 'match' operator.
1791
+
1792
+ :meth:`_sql.ColumnOperators.match` attempts to resolve to
1793
+ a MATCH-like function or operator provided by the backend.
1794
+ Examples include:
1795
+
1796
+ * PostgreSQL - renders ``x @@ plainto_tsquery(y)``
1797
+
1798
+ .. versionchanged:: 2.0 ``plainto_tsquery()`` is used instead
1799
+ of ``to_tsquery()`` for PostgreSQL now; for compatibility with
1800
+ other forms, see :ref:`postgresql_match`.
1801
+
1802
+
1803
+ * MySQL - renders ``MATCH (x) AGAINST (y IN BOOLEAN MODE)``
1804
+
1805
+ .. seealso::
1806
+
1807
+ :class:`_mysql.match` - MySQL specific construct with
1808
+ additional features.
1809
+
1810
+ * Oracle Database - renders ``CONTAINS(x, y)``
1811
+ * other backends may provide special implementations.
1812
+ * Backends without any special implementation will emit
1813
+ the operator as "MATCH". This is compatible with SQLite, for
1814
+ example.
1815
+
1816
+ """
1817
+ return self.operate(match_op, other, **kwargs)
1818
+
1819
+ def regexp_match(
1820
+ self, pattern: Any, flags: Optional[str] = None
1821
+ ) -> ColumnOperators:
1822
+ """Implements a database-specific 'regexp match' operator.
1823
+
1824
+ E.g.::
1825
+
1826
+ stmt = select(table.c.some_column).where(
1827
+ table.c.some_column.regexp_match("^(b|c)")
1828
+ )
1829
+
1830
+ :meth:`_sql.ColumnOperators.regexp_match` attempts to resolve to
1831
+ a REGEXP-like function or operator provided by the backend, however
1832
+ the specific regular expression syntax and flags available are
1833
+ **not backend agnostic**.
1834
+
1835
+ Examples include:
1836
+
1837
+ * PostgreSQL - renders ``x ~ y`` or ``x !~ y`` when negated.
1838
+ * Oracle Database - renders ``REGEXP_LIKE(x, y)``
1839
+ * SQLite - uses SQLite's ``REGEXP`` placeholder operator and calls into
1840
+ the Python ``re.match()`` builtin.
1841
+ * other backends may provide special implementations.
1842
+ * Backends without any special implementation will emit
1843
+ the operator as "REGEXP" or "NOT REGEXP". This is compatible with
1844
+ SQLite and MySQL, for example.
1845
+
1846
+ Regular expression support is currently implemented for Oracle
1847
+ Database, PostgreSQL, MySQL and MariaDB. Partial support is available
1848
+ for SQLite. Support among third-party dialects may vary.
1849
+
1850
+ :param pattern: The regular expression pattern string or column
1851
+ clause.
1852
+ :param flags: Any regular expression string flags to apply, passed as
1853
+ plain Python string only. These flags are backend specific.
1854
+ Some backends, like PostgreSQL and MariaDB, may alternatively
1855
+ specify the flags as part of the pattern.
1856
+ When using the ignore case flag 'i' in PostgreSQL, the ignore case
1857
+ regexp match operator ``~*`` or ``!~*`` will be used.
1858
+
1859
+ .. versionadded:: 1.4
1860
+
1861
+ .. versionchanged:: 1.4.48, 2.0.18 Note that due to an implementation
1862
+ error, the "flags" parameter previously accepted SQL expression
1863
+ objects such as column expressions in addition to plain Python
1864
+ strings. This implementation did not work correctly with caching
1865
+ and was removed; strings only should be passed for the "flags"
1866
+ parameter, as these flags are rendered as literal inline values
1867
+ within SQL expressions.
1868
+
1869
+ .. seealso::
1870
+
1871
+ :meth:`_sql.ColumnOperators.regexp_replace`
1872
+
1873
+
1874
+ """
1875
+ return self.operate(regexp_match_op, pattern, flags=flags)
1876
+
1877
+ def regexp_replace(
1878
+ self, pattern: Any, replacement: Any, flags: Optional[str] = None
1879
+ ) -> ColumnOperators:
1880
+ """Implements a database-specific 'regexp replace' operator.
1881
+
1882
+ E.g.::
1883
+
1884
+ stmt = select(
1885
+ table.c.some_column.regexp_replace("b(..)", "X\1Y", flags="g")
1886
+ )
1887
+
1888
+ :meth:`_sql.ColumnOperators.regexp_replace` attempts to resolve to
1889
+ a REGEXP_REPLACE-like function provided by the backend, that
1890
+ usually emit the function ``REGEXP_REPLACE()``. However,
1891
+ the specific regular expression syntax and flags available are
1892
+ **not backend agnostic**.
1893
+
1894
+ Regular expression replacement support is currently implemented for
1895
+ Oracle Database, PostgreSQL, MySQL 8 or greater and MariaDB. Support
1896
+ among third-party dialects may vary.
1897
+
1898
+ :param pattern: The regular expression pattern string or column
1899
+ clause.
1900
+ :param pattern: The replacement string or column clause.
1901
+ :param flags: Any regular expression string flags to apply, passed as
1902
+ plain Python string only. These flags are backend specific.
1903
+ Some backends, like PostgreSQL and MariaDB, may alternatively
1904
+ specify the flags as part of the pattern.
1905
+
1906
+ .. versionadded:: 1.4
1907
+
1908
+ .. versionchanged:: 1.4.48, 2.0.18 Note that due to an implementation
1909
+ error, the "flags" parameter previously accepted SQL expression
1910
+ objects such as column expressions in addition to plain Python
1911
+ strings. This implementation did not work correctly with caching
1912
+ and was removed; strings only should be passed for the "flags"
1913
+ parameter, as these flags are rendered as literal inline values
1914
+ within SQL expressions.
1915
+
1916
+
1917
+ .. seealso::
1918
+
1919
+ :meth:`_sql.ColumnOperators.regexp_match`
1920
+
1921
+ """
1922
+ return self.operate(
1923
+ regexp_replace_op,
1924
+ pattern,
1925
+ replacement=replacement,
1926
+ flags=flags,
1927
+ )
1928
+
1929
+ def collate(self, collation: str) -> ColumnOperators:
1930
+ """Produce a :func:`_expression.collate` clause against
1931
+ the parent object, given the collation string.
1932
+
1933
+ .. seealso::
1934
+
1935
+ :func:`_expression.collate`
1936
+
1937
+ """
1938
+ return self.operate(collate, collation)
1939
+
1940
+ def __radd__(self, other: Any) -> ColumnOperators:
1941
+ """Implement the ``+`` operator in reverse.
1942
+
1943
+ See :meth:`.ColumnOperators.__add__`.
1944
+
1945
+ """
1946
+ return self.reverse_operate(add, other)
1947
+
1948
+ def __rsub__(self, other: Any) -> ColumnOperators:
1949
+ """Implement the ``-`` operator in reverse.
1950
+
1951
+ See :meth:`.ColumnOperators.__sub__`.
1952
+
1953
+ """
1954
+ return self.reverse_operate(sub, other)
1955
+
1956
+ def __rmul__(self, other: Any) -> ColumnOperators:
1957
+ """Implement the ``*`` operator in reverse.
1958
+
1959
+ See :meth:`.ColumnOperators.__mul__`.
1960
+
1961
+ """
1962
+ return self.reverse_operate(mul, other)
1963
+
1964
+ def __rmod__(self, other: Any) -> ColumnOperators:
1965
+ """Implement the ``%`` operator in reverse.
1966
+
1967
+ See :meth:`.ColumnOperators.__mod__`.
1968
+
1969
+ """
1970
+ return self.reverse_operate(mod, other)
1971
+
1972
+ def between(
1973
+ self, cleft: Any, cright: Any, symmetric: bool = False
1974
+ ) -> ColumnOperators:
1975
+ """Produce a :func:`_expression.between` clause against
1976
+ the parent object, given the lower and upper range.
1977
+
1978
+ """
1979
+ return self.operate(between_op, cleft, cright, symmetric=symmetric)
1980
+
1981
+ def distinct(self) -> ColumnOperators:
1982
+ """Produce a :func:`_expression.distinct` clause against the
1983
+ parent object.
1984
+
1985
+ """
1986
+ return self.operate(distinct_op)
1987
+
1988
+ def any_(self) -> ColumnOperators:
1989
+ """Produce an :func:`_expression.any_` clause against the
1990
+ parent object.
1991
+
1992
+ See the documentation for :func:`_sql.any_` for examples.
1993
+
1994
+ .. note:: be sure to not confuse the newer
1995
+ :meth:`_sql.ColumnOperators.any_` method with the **legacy**
1996
+ version of this method, the :meth:`_types.ARRAY.Comparator.any`
1997
+ method that's specific to :class:`_types.ARRAY`, which uses a
1998
+ different calling style.
1999
+
2000
+ """
2001
+ return self.operate(any_op)
2002
+
2003
+ def all_(self) -> ColumnOperators:
2004
+ """Produce an :func:`_expression.all_` clause against the
2005
+ parent object.
2006
+
2007
+ See the documentation for :func:`_sql.all_` for examples.
2008
+
2009
+ .. note:: be sure to not confuse the newer
2010
+ :meth:`_sql.ColumnOperators.all_` method with the **legacy**
2011
+ version of this method, the :meth:`_types.ARRAY.Comparator.all`
2012
+ method that's specific to :class:`_types.ARRAY`, which uses a
2013
+ different calling style.
2014
+
2015
+ """
2016
+ return self.operate(all_op)
2017
+
2018
+ def __add__(self, other: Any) -> ColumnOperators:
2019
+ """Implement the ``+`` operator.
2020
+
2021
+ In a column context, produces the clause ``a + b``
2022
+ if the parent object has non-string affinity.
2023
+ If the parent object has a string affinity,
2024
+ produces the concatenation operator, ``a || b`` -
2025
+ see :meth:`.ColumnOperators.concat`.
2026
+
2027
+ """
2028
+ return self.operate(add, other)
2029
+
2030
+ def __sub__(self, other: Any) -> ColumnOperators:
2031
+ """Implement the ``-`` operator.
2032
+
2033
+ In a column context, produces the clause ``a - b``.
2034
+
2035
+ """
2036
+ return self.operate(sub, other)
2037
+
2038
+ def __mul__(self, other: Any) -> ColumnOperators:
2039
+ """Implement the ``*`` operator.
2040
+
2041
+ In a column context, produces the clause ``a * b``.
2042
+
2043
+ """
2044
+ return self.operate(mul, other)
2045
+
2046
+ def __mod__(self, other: Any) -> ColumnOperators:
2047
+ """Implement the ``%`` operator.
2048
+
2049
+ In a column context, produces the clause ``a % b``.
2050
+
2051
+ """
2052
+ return self.operate(mod, other)
2053
+
2054
+ def __truediv__(self, other: Any) -> ColumnOperators:
2055
+ """Implement the ``/`` operator.
2056
+
2057
+ In a column context, produces the clause ``a / b``, and
2058
+ considers the result type to be numeric.
2059
+
2060
+ .. versionchanged:: 2.0 The truediv operator against two integers
2061
+ is now considered to return a numeric value. Behavior on specific
2062
+ backends may vary.
2063
+
2064
+ """
2065
+ return self.operate(truediv, other)
2066
+
2067
+ def __rtruediv__(self, other: Any) -> ColumnOperators:
2068
+ """Implement the ``/`` operator in reverse.
2069
+
2070
+ See :meth:`.ColumnOperators.__truediv__`.
2071
+
2072
+ """
2073
+ return self.reverse_operate(truediv, other)
2074
+
2075
+ def __floordiv__(self, other: Any) -> ColumnOperators:
2076
+ """Implement the ``//`` operator.
2077
+
2078
+ In a column context, produces the clause ``a / b``,
2079
+ which is the same as "truediv", but considers the result
2080
+ type to be integer.
2081
+
2082
+ .. versionadded:: 2.0
2083
+
2084
+ """
2085
+ return self.operate(floordiv, other)
2086
+
2087
+ def __rfloordiv__(self, other: Any) -> ColumnOperators:
2088
+ """Implement the ``//`` operator in reverse.
2089
+
2090
+ See :meth:`.ColumnOperators.__floordiv__`.
2091
+
2092
+ """
2093
+ return self.reverse_operate(floordiv, other)
2094
+
2095
+ def __pow__(self, other: Any) -> ColumnOperators:
2096
+ """Implement the ``**`` operator.
2097
+
2098
+ In a column context, produces the clause ``pow(a, b)``, or a similar
2099
+ dialect-specific expression.
2100
+
2101
+ .. versionadded:: 2.1
2102
+
2103
+ """
2104
+ return self.operate(pow_, other)
2105
+
2106
+ def __rpow__(self, other: Any) -> ColumnOperators:
2107
+ """Implement the ``**`` operator in reverse.
2108
+
2109
+ .. seealso::
2110
+
2111
+ :meth:`.ColumnOperators.__pow__`.
2112
+
2113
+ .. versionadded:: 2.1
2114
+
2115
+ """
2116
+ return self.reverse_operate(pow_, other)
2117
+
2118
+
2119
+ _commutative: Set[Any] = {eq, ne, add, mul}
2120
+ _comparison: Set[Any] = {eq, ne, lt, gt, ge, le}
2121
+
2122
+
2123
+ def _operator_fn(fn: Callable[..., Any]) -> OperatorType:
2124
+ return cast(OperatorType, fn)
2125
+
2126
+
2127
+ def commutative_op(fn: _FN) -> _FN:
2128
+ _commutative.add(fn)
2129
+ return fn
2130
+
2131
+
2132
+ def comparison_op(fn: _FN) -> _FN:
2133
+ _comparison.add(fn)
2134
+ return fn
2135
+
2136
+
2137
+ @_operator_fn
2138
+ def from_() -> Any:
2139
+ raise NotImplementedError()
2140
+
2141
+
2142
+ @_operator_fn
2143
+ @comparison_op
2144
+ def function_as_comparison_op() -> Any:
2145
+ raise NotImplementedError()
2146
+
2147
+
2148
+ @_operator_fn
2149
+ def as_() -> Any:
2150
+ raise NotImplementedError()
2151
+
2152
+
2153
+ @_operator_fn
2154
+ def exists() -> Any:
2155
+ raise NotImplementedError()
2156
+
2157
+
2158
+ @_operator_fn
2159
+ def is_true(a: Any) -> Any:
2160
+ raise NotImplementedError()
2161
+
2162
+
2163
+ # 1.4 deprecated; see #5435
2164
+ if TYPE_CHECKING:
2165
+
2166
+ @_operator_fn
2167
+ def istrue(a: Any) -> Any: ...
2168
+
2169
+ else:
2170
+ istrue = is_true
2171
+
2172
+
2173
+ @_operator_fn
2174
+ def is_false(a: Any) -> Any:
2175
+ raise NotImplementedError()
2176
+
2177
+
2178
+ # 1.4 deprecated; see #5435
2179
+ if TYPE_CHECKING:
2180
+
2181
+ @_operator_fn
2182
+ def isfalse(a: Any) -> Any: ...
2183
+
2184
+ else:
2185
+ isfalse = is_false
2186
+
2187
+
2188
+ @comparison_op
2189
+ @_operator_fn
2190
+ def is_distinct_from(a: Any, b: Any) -> Any:
2191
+ return a.is_distinct_from(b)
2192
+
2193
+
2194
+ @comparison_op
2195
+ @_operator_fn
2196
+ def is_not_distinct_from(a: Any, b: Any) -> Any:
2197
+ return a.is_not_distinct_from(b)
2198
+
2199
+
2200
+ # deprecated 1.4; see #5435
2201
+ if TYPE_CHECKING:
2202
+
2203
+ @_operator_fn
2204
+ def isnot_distinct_from(a: Any, b: Any) -> Any: ...
2205
+
2206
+ else:
2207
+ isnot_distinct_from = is_not_distinct_from
2208
+
2209
+
2210
+ @comparison_op
2211
+ @_operator_fn
2212
+ def is_(a: Any, b: Any) -> Any:
2213
+ return a.is_(b)
2214
+
2215
+
2216
+ @comparison_op
2217
+ @_operator_fn
2218
+ def is_not(a: Any, b: Any) -> Any:
2219
+ return a.is_not(b)
2220
+
2221
+
2222
+ # 1.4 deprecated; see #5429
2223
+ if TYPE_CHECKING:
2224
+
2225
+ @_operator_fn
2226
+ def isnot(a: Any, b: Any) -> Any: ...
2227
+
2228
+ else:
2229
+ isnot = is_not
2230
+
2231
+
2232
+ @_operator_fn
2233
+ def collate(a: Any, b: Any) -> Any:
2234
+ return a.collate(b)
2235
+
2236
+
2237
+ @_operator_fn
2238
+ def op(a: Any, opstring: str, b: Any) -> Any:
2239
+ return a.op(opstring)(b)
2240
+
2241
+
2242
+ @comparison_op
2243
+ @_operator_fn
2244
+ def like_op(a: Any, b: Any, escape: Optional[str] = None) -> Any:
2245
+ return a.like(b, escape=escape)
2246
+
2247
+
2248
+ @comparison_op
2249
+ @_operator_fn
2250
+ def not_like_op(a: Any, b: Any, escape: Optional[str] = None) -> Any:
2251
+ return a.notlike(b, escape=escape)
2252
+
2253
+
2254
+ # 1.4 deprecated; see #5435
2255
+ if TYPE_CHECKING:
2256
+
2257
+ @_operator_fn
2258
+ def notlike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any: ...
2259
+
2260
+ else:
2261
+ notlike_op = not_like_op
2262
+
2263
+
2264
+ @comparison_op
2265
+ @_operator_fn
2266
+ def ilike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any:
2267
+ return a.ilike(b, escape=escape)
2268
+
2269
+
2270
+ @comparison_op
2271
+ @_operator_fn
2272
+ def not_ilike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any:
2273
+ return a.not_ilike(b, escape=escape)
2274
+
2275
+
2276
+ # 1.4 deprecated; see #5435
2277
+ if TYPE_CHECKING:
2278
+
2279
+ @_operator_fn
2280
+ def notilike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any: ...
2281
+
2282
+ else:
2283
+ notilike_op = not_ilike_op
2284
+
2285
+
2286
+ @comparison_op
2287
+ @_operator_fn
2288
+ def between_op(a: Any, b: Any, c: Any, symmetric: bool = False) -> Any:
2289
+ return a.between(b, c, symmetric=symmetric)
2290
+
2291
+
2292
+ @comparison_op
2293
+ @_operator_fn
2294
+ def not_between_op(a: Any, b: Any, c: Any, symmetric: bool = False) -> Any:
2295
+ return ~a.between(b, c, symmetric=symmetric)
2296
+
2297
+
2298
+ # 1.4 deprecated; see #5435
2299
+ if TYPE_CHECKING:
2300
+
2301
+ @_operator_fn
2302
+ def notbetween_op(
2303
+ a: Any, b: Any, c: Any, symmetric: bool = False
2304
+ ) -> Any: ...
2305
+
2306
+ else:
2307
+ notbetween_op = not_between_op
2308
+
2309
+
2310
+ @comparison_op
2311
+ @_operator_fn
2312
+ def in_op(a: Any, b: Any) -> Any:
2313
+ return a.in_(b)
2314
+
2315
+
2316
+ @comparison_op
2317
+ @_operator_fn
2318
+ def not_in_op(a: Any, b: Any) -> Any:
2319
+ return a.not_in(b)
2320
+
2321
+
2322
+ # 1.4 deprecated; see #5429
2323
+ if TYPE_CHECKING:
2324
+
2325
+ @_operator_fn
2326
+ def notin_op(a: Any, b: Any) -> Any: ...
2327
+
2328
+ else:
2329
+ notin_op = not_in_op
2330
+
2331
+
2332
+ @_operator_fn
2333
+ def distinct_op(a: Any) -> Any:
2334
+ return a.distinct()
2335
+
2336
+
2337
+ @_operator_fn
2338
+ def any_op(a: Any) -> Any:
2339
+ return a.any_()
2340
+
2341
+
2342
+ @_operator_fn
2343
+ def all_op(a: Any) -> Any:
2344
+ return a.all_()
2345
+
2346
+
2347
+ def _escaped_like_impl(
2348
+ fn: Callable[..., Any], other: Any, escape: Optional[str], autoescape: bool
2349
+ ) -> Any:
2350
+ if autoescape:
2351
+ if autoescape is not True:
2352
+ util.warn(
2353
+ "The autoescape parameter is now a simple boolean True/False"
2354
+ )
2355
+ if escape is None:
2356
+ escape = "/"
2357
+
2358
+ if not isinstance(other, str):
2359
+ raise TypeError("String value expected when autoescape=True")
2360
+
2361
+ if escape not in ("%", "_"):
2362
+ other = other.replace(escape, escape + escape)
2363
+
2364
+ other = other.replace("%", escape + "%").replace("_", escape + "_")
2365
+
2366
+ return fn(other, escape=escape)
2367
+
2368
+
2369
+ @comparison_op
2370
+ @_operator_fn
2371
+ def startswith_op(
2372
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2373
+ ) -> Any:
2374
+ return _escaped_like_impl(a.startswith, b, escape, autoescape)
2375
+
2376
+
2377
+ @comparison_op
2378
+ @_operator_fn
2379
+ def not_startswith_op(
2380
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2381
+ ) -> Any:
2382
+ return ~_escaped_like_impl(a.startswith, b, escape, autoescape)
2383
+
2384
+
2385
+ # 1.4 deprecated; see #5435
2386
+ if TYPE_CHECKING:
2387
+
2388
+ @_operator_fn
2389
+ def notstartswith_op(
2390
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2391
+ ) -> Any: ...
2392
+
2393
+ else:
2394
+ notstartswith_op = not_startswith_op
2395
+
2396
+
2397
+ @comparison_op
2398
+ @_operator_fn
2399
+ def istartswith_op(
2400
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2401
+ ) -> Any:
2402
+ return _escaped_like_impl(a.istartswith, b, escape, autoescape)
2403
+
2404
+
2405
+ @comparison_op
2406
+ @_operator_fn
2407
+ def not_istartswith_op(
2408
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2409
+ ) -> Any:
2410
+ return ~_escaped_like_impl(a.istartswith, b, escape, autoescape)
2411
+
2412
+
2413
+ @comparison_op
2414
+ @_operator_fn
2415
+ def endswith_op(
2416
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2417
+ ) -> Any:
2418
+ return _escaped_like_impl(a.endswith, b, escape, autoescape)
2419
+
2420
+
2421
+ @comparison_op
2422
+ @_operator_fn
2423
+ def not_endswith_op(
2424
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2425
+ ) -> Any:
2426
+ return ~_escaped_like_impl(a.endswith, b, escape, autoescape)
2427
+
2428
+
2429
+ # 1.4 deprecated; see #5435
2430
+ if TYPE_CHECKING:
2431
+
2432
+ @_operator_fn
2433
+ def notendswith_op(
2434
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2435
+ ) -> Any: ...
2436
+
2437
+ else:
2438
+ notendswith_op = not_endswith_op
2439
+
2440
+
2441
+ @comparison_op
2442
+ @_operator_fn
2443
+ def iendswith_op(
2444
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2445
+ ) -> Any:
2446
+ return _escaped_like_impl(a.iendswith, b, escape, autoescape)
2447
+
2448
+
2449
+ @comparison_op
2450
+ @_operator_fn
2451
+ def not_iendswith_op(
2452
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2453
+ ) -> Any:
2454
+ return ~_escaped_like_impl(a.iendswith, b, escape, autoescape)
2455
+
2456
+
2457
+ @comparison_op
2458
+ @_operator_fn
2459
+ def contains_op(
2460
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2461
+ ) -> Any:
2462
+ return _escaped_like_impl(a.contains, b, escape, autoescape)
2463
+
2464
+
2465
+ @comparison_op
2466
+ @_operator_fn
2467
+ def not_contains_op(
2468
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2469
+ ) -> Any:
2470
+ return ~_escaped_like_impl(a.contains, b, escape, autoescape)
2471
+
2472
+
2473
+ # 1.4 deprecated; see #5435
2474
+ if TYPE_CHECKING:
2475
+
2476
+ @_operator_fn
2477
+ def notcontains_op(
2478
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2479
+ ) -> Any: ...
2480
+
2481
+ else:
2482
+ notcontains_op = not_contains_op
2483
+
2484
+
2485
+ @comparison_op
2486
+ @_operator_fn
2487
+ def icontains_op(
2488
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2489
+ ) -> Any:
2490
+ return _escaped_like_impl(a.icontains, b, escape, autoescape)
2491
+
2492
+
2493
+ @comparison_op
2494
+ @_operator_fn
2495
+ def not_icontains_op(
2496
+ a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False
2497
+ ) -> Any:
2498
+ return ~_escaped_like_impl(a.icontains, b, escape, autoescape)
2499
+
2500
+
2501
+ @comparison_op
2502
+ @_operator_fn
2503
+ def match_op(a: Any, b: Any, **kw: Any) -> Any:
2504
+ return a.match(b, **kw)
2505
+
2506
+
2507
+ @comparison_op
2508
+ @_operator_fn
2509
+ def regexp_match_op(a: Any, b: Any, flags: Optional[str] = None) -> Any:
2510
+ return a.regexp_match(b, flags=flags)
2511
+
2512
+
2513
+ @comparison_op
2514
+ @_operator_fn
2515
+ def not_regexp_match_op(a: Any, b: Any, flags: Optional[str] = None) -> Any:
2516
+ return ~a.regexp_match(b, flags=flags)
2517
+
2518
+
2519
+ @_operator_fn
2520
+ def regexp_replace_op(
2521
+ a: Any, b: Any, replacement: Any, flags: Optional[str] = None
2522
+ ) -> Any:
2523
+ return a.regexp_replace(b, replacement=replacement, flags=flags)
2524
+
2525
+
2526
+ @comparison_op
2527
+ @_operator_fn
2528
+ def not_match_op(a: Any, b: Any, **kw: Any) -> Any:
2529
+ return ~a.match(b, **kw)
2530
+
2531
+
2532
+ # 1.4 deprecated; see #5429
2533
+ if TYPE_CHECKING:
2534
+
2535
+ @_operator_fn
2536
+ def notmatch_op(a: Any, b: Any, **kw: Any) -> Any: ...
2537
+
2538
+ else:
2539
+ notmatch_op = not_match_op
2540
+
2541
+
2542
+ @_operator_fn
2543
+ def comma_op(a: Any, b: Any) -> Any:
2544
+ raise NotImplementedError()
2545
+
2546
+
2547
+ @_operator_fn
2548
+ def filter_op(a: Any, b: Any) -> Any:
2549
+ raise NotImplementedError()
2550
+
2551
+
2552
+ @_operator_fn
2553
+ def concat_op(a: Any, b: Any) -> Any:
2554
+ try:
2555
+ concat = a.concat
2556
+ except AttributeError:
2557
+ return b._rconcat(a)
2558
+ else:
2559
+ return concat(b)
2560
+
2561
+
2562
+ @_operator_fn
2563
+ def desc_op(a: Any) -> Any:
2564
+ return a.desc()
2565
+
2566
+
2567
+ @_operator_fn
2568
+ def asc_op(a: Any) -> Any:
2569
+ return a.asc()
2570
+
2571
+
2572
+ @_operator_fn
2573
+ def nulls_first_op(a: Any) -> Any:
2574
+ return a.nulls_first()
2575
+
2576
+
2577
+ # 1.4 deprecated; see #5435
2578
+ if TYPE_CHECKING:
2579
+
2580
+ @_operator_fn
2581
+ def nullsfirst_op(a: Any) -> Any: ...
2582
+
2583
+ else:
2584
+ nullsfirst_op = nulls_first_op
2585
+
2586
+
2587
+ @_operator_fn
2588
+ def nulls_last_op(a: Any) -> Any:
2589
+ return a.nulls_last()
2590
+
2591
+
2592
+ # 1.4 deprecated; see #5435
2593
+ if TYPE_CHECKING:
2594
+
2595
+ @_operator_fn
2596
+ def nullslast_op(a: Any) -> Any: ...
2597
+
2598
+ else:
2599
+ nullslast_op = nulls_last_op
2600
+
2601
+
2602
+ @_operator_fn
2603
+ def json_getitem_op(a: Any, b: Any) -> Any:
2604
+ raise NotImplementedError()
2605
+
2606
+
2607
+ @_operator_fn
2608
+ def json_path_getitem_op(a: Any, b: Any) -> Any:
2609
+ raise NotImplementedError()
2610
+
2611
+
2612
+ @_operator_fn
2613
+ def bitwise_xor_op(a: Any, b: Any) -> Any:
2614
+ return a.bitwise_xor(b)
2615
+
2616
+
2617
+ @_operator_fn
2618
+ def bitwise_or_op(a: Any, b: Any) -> Any:
2619
+ return a.bitwise_or(b)
2620
+
2621
+
2622
+ @_operator_fn
2623
+ def bitwise_and_op(a: Any, b: Any) -> Any:
2624
+ return a.bitwise_and(b)
2625
+
2626
+
2627
+ @_operator_fn
2628
+ def bitwise_not_op(a: Any) -> Any:
2629
+ return a.bitwise_not()
2630
+
2631
+
2632
+ @_operator_fn
2633
+ def bitwise_lshift_op(a: Any, b: Any) -> Any:
2634
+ return a.bitwise_lshift(b)
2635
+
2636
+
2637
+ @_operator_fn
2638
+ def bitwise_rshift_op(a: Any, b: Any) -> Any:
2639
+ return a.bitwise_rshift(b)
2640
+
2641
+
2642
+ @_operator_fn
2643
+ def null_op(a: Any, b: Any) -> Any:
2644
+ """a 'null' operator that provides a boolean operation.
2645
+
2646
+ Does not compile in a SQL context, used for testing operators only.
2647
+
2648
+ .. versionadded:: 2.1
2649
+
2650
+ """
2651
+ return a._null_operate(b)
2652
+
2653
+
2654
+ def is_comparison(op: OperatorType) -> bool:
2655
+ return op in _comparison or isinstance(op, custom_op) and op.is_comparison
2656
+
2657
+
2658
+ def is_commutative(op: OperatorType) -> bool:
2659
+ return op in _commutative
2660
+
2661
+
2662
+ def is_ordering_modifier(op: OperatorType) -> bool:
2663
+ return op in (asc_op, desc_op, nulls_first_op, nulls_last_op)
2664
+
2665
+
2666
+ def is_natural_self_precedent(op: OperatorType) -> bool:
2667
+ return (
2668
+ op in _natural_self_precedent
2669
+ or isinstance(op, custom_op)
2670
+ and op.natural_self_precedent
2671
+ )
2672
+
2673
+
2674
+ _booleans = (inv, is_true, is_false, and_, or_)
2675
+
2676
+
2677
+ def is_boolean(op: OperatorType) -> bool:
2678
+ return is_comparison(op) or op in _booleans
2679
+
2680
+
2681
+ _mirror = {gt: lt, ge: le, lt: gt, le: ge}
2682
+
2683
+
2684
+ def mirror(op: OperatorType) -> OperatorType:
2685
+ """rotate a comparison operator 180 degrees.
2686
+
2687
+ Note this is not the same as negation.
2688
+
2689
+ """
2690
+ return _mirror.get(op, op)
2691
+
2692
+
2693
+ _associative = _commutative.union([concat_op, and_, or_]).difference([eq, ne])
2694
+
2695
+
2696
+ def is_associative(op: OperatorType) -> bool:
2697
+ return op in _associative
2698
+
2699
+
2700
+ def is_order_by_modifier(op: Optional[OperatorType]) -> bool:
2701
+ return op in _order_by_modifier
2702
+
2703
+
2704
+ _order_by_modifier = {desc_op, asc_op, nulls_first_op, nulls_last_op}
2705
+
2706
+ _natural_self_precedent = _associative.union(
2707
+ [getitem, json_getitem_op, json_path_getitem_op]
2708
+ )
2709
+ """Operators where if we have (a op b) op c, we don't want to
2710
+ parenthesize (a op b).
2711
+
2712
+ """
2713
+
2714
+
2715
+ @_operator_fn
2716
+ def _asbool(a: Any) -> Any:
2717
+ raise NotImplementedError()
2718
+
2719
+
2720
+ class _OpLimit(IntEnum):
2721
+ _smallest = -100
2722
+ _largest = 100
2723
+
2724
+
2725
+ _PRECEDENCE: Dict[OperatorType, int] = {
2726
+ from_: 15,
2727
+ function_as_comparison_op: 15,
2728
+ any_op: 15,
2729
+ all_op: 15,
2730
+ getitem: 15,
2731
+ json_getitem_op: 15,
2732
+ json_path_getitem_op: 15,
2733
+ pow_: 15,
2734
+ mul: 8,
2735
+ truediv: 8,
2736
+ floordiv: 8,
2737
+ mod: 8,
2738
+ neg: 8,
2739
+ bitwise_not_op: 8,
2740
+ add: 7,
2741
+ sub: 7,
2742
+ bitwise_xor_op: 7,
2743
+ bitwise_or_op: 7,
2744
+ bitwise_and_op: 7,
2745
+ bitwise_lshift_op: 7,
2746
+ bitwise_rshift_op: 7,
2747
+ null_op: 7,
2748
+ filter_op: 6,
2749
+ concat_op: 5,
2750
+ match_op: 5,
2751
+ not_match_op: 5,
2752
+ regexp_match_op: 5,
2753
+ not_regexp_match_op: 5,
2754
+ regexp_replace_op: 5,
2755
+ ilike_op: 5,
2756
+ not_ilike_op: 5,
2757
+ like_op: 5,
2758
+ not_like_op: 5,
2759
+ in_op: 5,
2760
+ not_in_op: 5,
2761
+ is_: 5,
2762
+ is_not: 5,
2763
+ eq: 5,
2764
+ ne: 5,
2765
+ is_distinct_from: 5,
2766
+ is_not_distinct_from: 5,
2767
+ gt: 5,
2768
+ lt: 5,
2769
+ ge: 5,
2770
+ le: 5,
2771
+ between_op: 5,
2772
+ not_between_op: 5,
2773
+ distinct_op: 5,
2774
+ inv: 5,
2775
+ is_true: 5,
2776
+ is_false: 5,
2777
+ and_: 3,
2778
+ or_: 2,
2779
+ comma_op: -1,
2780
+ desc_op: 3,
2781
+ asc_op: 3,
2782
+ collate: 4,
2783
+ as_: -1,
2784
+ exists: 0,
2785
+ _asbool: -10,
2786
+ }
2787
+
2788
+
2789
+ # Mapping of OperatorType objects to their corresponding OperatorClass
2790
+ # Derived from unified_operator_lookup in default_comparator.py
2791
+ _OPERATOR_CLASSES: util.immutabledict[OperatorType, OperatorClass] = (
2792
+ util.immutabledict(
2793
+ {
2794
+ # BASE operators
2795
+ null_op: OperatorClass.BASE,
2796
+ # COMPARISON operators
2797
+ lt: OperatorClass.COMPARISON,
2798
+ le: OperatorClass.COMPARISON,
2799
+ ne: OperatorClass.COMPARISON,
2800
+ gt: OperatorClass.COMPARISON,
2801
+ ge: OperatorClass.COMPARISON,
2802
+ eq: OperatorClass.COMPARISON,
2803
+ is_distinct_from: OperatorClass.COMPARISON,
2804
+ is_not_distinct_from: OperatorClass.COMPARISON,
2805
+ in_op: OperatorClass.COMPARISON,
2806
+ not_in_op: OperatorClass.COMPARISON,
2807
+ is_: OperatorClass.COMPARISON,
2808
+ is_not: OperatorClass.COMPARISON,
2809
+ between_op: OperatorClass.COMPARISON,
2810
+ not_between_op: OperatorClass.COMPARISON,
2811
+ desc_op: OperatorClass.COMPARISON,
2812
+ asc_op: OperatorClass.COMPARISON,
2813
+ nulls_first_op: OperatorClass.COMPARISON,
2814
+ nulls_last_op: OperatorClass.COMPARISON,
2815
+ distinct_op: OperatorClass.COMPARISON,
2816
+ any_op: OperatorClass.COMPARISON,
2817
+ all_op: OperatorClass.COMPARISON,
2818
+ # BOOLEAN_ALGEBRA operators
2819
+ and_: OperatorClass.BOOLEAN_ALGEBRA,
2820
+ or_: OperatorClass.BOOLEAN_ALGEBRA,
2821
+ inv: OperatorClass.BOOLEAN_ALGEBRA | OperatorClass.BITWISE,
2822
+ # CONCATENABLE | MATH | DATE_ARITHMETIC | BITWISE operators
2823
+ add: OperatorClass.CONCATENABLE
2824
+ | OperatorClass.MATH
2825
+ | OperatorClass.DATE_ARITHEMETIC
2826
+ | OperatorClass.BITWISE,
2827
+ # CONCATENABLE | BITWISE operators
2828
+ concat_op: OperatorClass.CONCATENABLE | OperatorClass.BITWISE,
2829
+ # INDEXABLE operators
2830
+ getitem: OperatorClass.INDEXABLE,
2831
+ # CONTAINS operators
2832
+ contains_op: OperatorClass.CONTAINS,
2833
+ icontains_op: OperatorClass.CONTAINS,
2834
+ contains: OperatorClass.CONTAINS,
2835
+ not_contains_op: OperatorClass.CONTAINS,
2836
+ not_icontains_op: OperatorClass.CONTAINS,
2837
+ # STRING_MATCH operators
2838
+ like_op: OperatorClass.STRING_MATCH,
2839
+ ilike_op: OperatorClass.STRING_MATCH,
2840
+ not_like_op: OperatorClass.STRING_MATCH,
2841
+ not_ilike_op: OperatorClass.STRING_MATCH,
2842
+ startswith_op: OperatorClass.STRING_MATCH,
2843
+ istartswith_op: OperatorClass.STRING_MATCH,
2844
+ endswith_op: OperatorClass.STRING_MATCH,
2845
+ iendswith_op: OperatorClass.STRING_MATCH,
2846
+ not_startswith_op: OperatorClass.STRING_MATCH,
2847
+ not_istartswith_op: OperatorClass.STRING_MATCH,
2848
+ not_endswith_op: OperatorClass.STRING_MATCH,
2849
+ not_iendswith_op: OperatorClass.STRING_MATCH,
2850
+ collate: OperatorClass.STRING_MATCH,
2851
+ match_op: OperatorClass.STRING_MATCH,
2852
+ not_match_op: OperatorClass.STRING_MATCH,
2853
+ regexp_match_op: OperatorClass.STRING_MATCH,
2854
+ not_regexp_match_op: OperatorClass.STRING_MATCH,
2855
+ regexp_replace_op: OperatorClass.STRING_MATCH,
2856
+ # BITWISE operators
2857
+ lshift: OperatorClass.BITWISE,
2858
+ rshift: OperatorClass.BITWISE,
2859
+ bitwise_xor_op: OperatorClass.BITWISE,
2860
+ bitwise_or_op: OperatorClass.BITWISE,
2861
+ bitwise_and_op: OperatorClass.BITWISE,
2862
+ bitwise_not_op: OperatorClass.BITWISE,
2863
+ bitwise_lshift_op: OperatorClass.BITWISE,
2864
+ bitwise_rshift_op: OperatorClass.BITWISE,
2865
+ # MATH operators
2866
+ matmul: OperatorClass.MATH,
2867
+ pow_: OperatorClass.MATH,
2868
+ neg: OperatorClass.MATH,
2869
+ mul: OperatorClass.MATH,
2870
+ sub: OperatorClass.MATH | OperatorClass.DATE_ARITHEMETIC,
2871
+ truediv: OperatorClass.MATH,
2872
+ floordiv: OperatorClass.MATH,
2873
+ mod: OperatorClass.MATH,
2874
+ # JSON_GETITEM operators
2875
+ json_path_getitem_op: OperatorClass.JSON_GETITEM,
2876
+ json_getitem_op: OperatorClass.JSON_GETITEM,
2877
+ }
2878
+ )
2879
+ )
2880
+
2881
+
2882
+ def is_precedent(
2883
+ operator: OperatorType, against: Optional[OperatorType]
2884
+ ) -> bool:
2885
+ if operator is against and is_natural_self_precedent(operator):
2886
+ return False
2887
+ elif against is None:
2888
+ return True
2889
+ else:
2890
+ return bool(
2891
+ _PRECEDENCE.get(
2892
+ operator, getattr(operator, "precedence", _OpLimit._smallest)
2893
+ )
2894
+ <= _PRECEDENCE.get(
2895
+ against, getattr(against, "precedence", _OpLimit._largest)
2896
+ )
2897
+ )