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