SQLAlchemy 2.0.36__cp313-cp313-win32.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 (273) hide show
  1. SQLAlchemy-2.0.36.dist-info/LICENSE +19 -0
  2. SQLAlchemy-2.0.36.dist-info/METADATA +243 -0
  3. SQLAlchemy-2.0.36.dist-info/RECORD +273 -0
  4. SQLAlchemy-2.0.36.dist-info/WHEEL +5 -0
  5. SQLAlchemy-2.0.36.dist-info/top_level.txt +1 -0
  6. sqlalchemy/__init__.py +294 -0
  7. sqlalchemy/connectors/__init__.py +18 -0
  8. sqlalchemy/connectors/aioodbc.py +174 -0
  9. sqlalchemy/connectors/asyncio.py +213 -0
  10. sqlalchemy/connectors/pyodbc.py +249 -0
  11. sqlalchemy/cyextension/__init__.py +6 -0
  12. sqlalchemy/cyextension/collections.cp313-win32.pyd +0 -0
  13. sqlalchemy/cyextension/collections.pyx +409 -0
  14. sqlalchemy/cyextension/immutabledict.cp313-win32.pyd +0 -0
  15. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  16. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  17. sqlalchemy/cyextension/processors.cp313-win32.pyd +0 -0
  18. sqlalchemy/cyextension/processors.pyx +68 -0
  19. sqlalchemy/cyextension/resultproxy.cp313-win32.pyd +0 -0
  20. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  21. sqlalchemy/cyextension/util.cp313-win32.pyd +0 -0
  22. sqlalchemy/cyextension/util.pyx +91 -0
  23. sqlalchemy/dialects/__init__.py +61 -0
  24. sqlalchemy/dialects/_typing.py +25 -0
  25. sqlalchemy/dialects/mssql/__init__.py +88 -0
  26. sqlalchemy/dialects/mssql/aioodbc.py +64 -0
  27. sqlalchemy/dialects/mssql/base.py +4010 -0
  28. sqlalchemy/dialects/mssql/information_schema.py +254 -0
  29. sqlalchemy/dialects/mssql/json.py +133 -0
  30. sqlalchemy/dialects/mssql/provision.py +162 -0
  31. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  32. sqlalchemy/dialects/mssql/pyodbc.py +745 -0
  33. sqlalchemy/dialects/mysql/__init__.py +101 -0
  34. sqlalchemy/dialects/mysql/aiomysql.py +333 -0
  35. sqlalchemy/dialects/mysql/asyncmy.py +337 -0
  36. sqlalchemy/dialects/mysql/base.py +3494 -0
  37. sqlalchemy/dialects/mysql/cymysql.py +84 -0
  38. sqlalchemy/dialects/mysql/dml.py +219 -0
  39. sqlalchemy/dialects/mysql/enumerated.py +244 -0
  40. sqlalchemy/dialects/mysql/expression.py +141 -0
  41. sqlalchemy/dialects/mysql/json.py +81 -0
  42. sqlalchemy/dialects/mysql/mariadb.py +32 -0
  43. sqlalchemy/dialects/mysql/mariadbconnector.py +277 -0
  44. sqlalchemy/dialects/mysql/mysqlconnector.py +180 -0
  45. sqlalchemy/dialects/mysql/mysqldb.py +303 -0
  46. sqlalchemy/dialects/mysql/provision.py +110 -0
  47. sqlalchemy/dialects/mysql/pymysql.py +137 -0
  48. sqlalchemy/dialects/mysql/pyodbc.py +138 -0
  49. sqlalchemy/dialects/mysql/reflection.py +677 -0
  50. sqlalchemy/dialects/mysql/reserved_words.py +571 -0
  51. sqlalchemy/dialects/mysql/types.py +774 -0
  52. sqlalchemy/dialects/oracle/__init__.py +67 -0
  53. sqlalchemy/dialects/oracle/base.py +3271 -0
  54. sqlalchemy/dialects/oracle/cx_oracle.py +1483 -0
  55. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  56. sqlalchemy/dialects/oracle/oracledb.py +431 -0
  57. sqlalchemy/dialects/oracle/provision.py +220 -0
  58. sqlalchemy/dialects/oracle/types.py +287 -0
  59. sqlalchemy/dialects/postgresql/__init__.py +167 -0
  60. sqlalchemy/dialects/postgresql/_psycopg_common.py +187 -0
  61. sqlalchemy/dialects/postgresql/array.py +425 -0
  62. sqlalchemy/dialects/postgresql/asyncpg.py +1274 -0
  63. sqlalchemy/dialects/postgresql/base.py +5008 -0
  64. sqlalchemy/dialects/postgresql/dml.py +310 -0
  65. sqlalchemy/dialects/postgresql/ext.py +496 -0
  66. sqlalchemy/dialects/postgresql/hstore.py +397 -0
  67. sqlalchemy/dialects/postgresql/json.py +333 -0
  68. sqlalchemy/dialects/postgresql/named_types.py +509 -0
  69. sqlalchemy/dialects/postgresql/operators.py +129 -0
  70. sqlalchemy/dialects/postgresql/pg8000.py +662 -0
  71. sqlalchemy/dialects/postgresql/pg_catalog.py +300 -0
  72. sqlalchemy/dialects/postgresql/provision.py +175 -0
  73. sqlalchemy/dialects/postgresql/psycopg.py +772 -0
  74. sqlalchemy/dialects/postgresql/psycopg2.py +886 -0
  75. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  76. sqlalchemy/dialects/postgresql/ranges.py +1029 -0
  77. sqlalchemy/dialects/postgresql/types.py +303 -0
  78. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  79. sqlalchemy/dialects/sqlite/aiosqlite.py +396 -0
  80. sqlalchemy/dialects/sqlite/base.py +2805 -0
  81. sqlalchemy/dialects/sqlite/dml.py +240 -0
  82. sqlalchemy/dialects/sqlite/json.py +92 -0
  83. sqlalchemy/dialects/sqlite/provision.py +198 -0
  84. sqlalchemy/dialects/sqlite/pysqlcipher.py +155 -0
  85. sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
  86. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  87. sqlalchemy/engine/__init__.py +62 -0
  88. sqlalchemy/engine/_py_processors.py +136 -0
  89. sqlalchemy/engine/_py_row.py +128 -0
  90. sqlalchemy/engine/_py_util.py +74 -0
  91. sqlalchemy/engine/base.py +3375 -0
  92. sqlalchemy/engine/characteristics.py +155 -0
  93. sqlalchemy/engine/create.py +875 -0
  94. sqlalchemy/engine/cursor.py +2181 -0
  95. sqlalchemy/engine/default.py +2365 -0
  96. sqlalchemy/engine/events.py +951 -0
  97. sqlalchemy/engine/interfaces.py +3403 -0
  98. sqlalchemy/engine/mock.py +131 -0
  99. sqlalchemy/engine/processors.py +61 -0
  100. sqlalchemy/engine/reflection.py +2098 -0
  101. sqlalchemy/engine/result.py +2382 -0
  102. sqlalchemy/engine/row.py +401 -0
  103. sqlalchemy/engine/strategies.py +19 -0
  104. sqlalchemy/engine/url.py +910 -0
  105. sqlalchemy/engine/util.py +167 -0
  106. sqlalchemy/event/__init__.py +25 -0
  107. sqlalchemy/event/api.py +225 -0
  108. sqlalchemy/event/attr.py +655 -0
  109. sqlalchemy/event/base.py +470 -0
  110. sqlalchemy/event/legacy.py +246 -0
  111. sqlalchemy/event/registry.py +386 -0
  112. sqlalchemy/events.py +17 -0
  113. sqlalchemy/exc.py +830 -0
  114. sqlalchemy/ext/__init__.py +11 -0
  115. sqlalchemy/ext/associationproxy.py +2013 -0
  116. sqlalchemy/ext/asyncio/__init__.py +25 -0
  117. sqlalchemy/ext/asyncio/base.py +279 -0
  118. sqlalchemy/ext/asyncio/engine.py +1466 -0
  119. sqlalchemy/ext/asyncio/exc.py +21 -0
  120. sqlalchemy/ext/asyncio/result.py +961 -0
  121. sqlalchemy/ext/asyncio/scoping.py +1614 -0
  122. sqlalchemy/ext/asyncio/session.py +1936 -0
  123. sqlalchemy/ext/automap.py +1691 -0
  124. sqlalchemy/ext/baked.py +574 -0
  125. sqlalchemy/ext/compiler.py +570 -0
  126. sqlalchemy/ext/declarative/__init__.py +65 -0
  127. sqlalchemy/ext/declarative/extensions.py +548 -0
  128. sqlalchemy/ext/horizontal_shard.py +481 -0
  129. sqlalchemy/ext/hybrid.py +1514 -0
  130. sqlalchemy/ext/indexable.py +341 -0
  131. sqlalchemy/ext/instrumentation.py +450 -0
  132. sqlalchemy/ext/mutable.py +1073 -0
  133. sqlalchemy/ext/mypy/__init__.py +6 -0
  134. sqlalchemy/ext/mypy/apply.py +320 -0
  135. sqlalchemy/ext/mypy/decl_class.py +515 -0
  136. sqlalchemy/ext/mypy/infer.py +590 -0
  137. sqlalchemy/ext/mypy/names.py +335 -0
  138. sqlalchemy/ext/mypy/plugin.py +303 -0
  139. sqlalchemy/ext/mypy/util.py +357 -0
  140. sqlalchemy/ext/orderinglist.py +416 -0
  141. sqlalchemy/ext/serializer.py +181 -0
  142. sqlalchemy/future/__init__.py +16 -0
  143. sqlalchemy/future/engine.py +15 -0
  144. sqlalchemy/inspection.py +174 -0
  145. sqlalchemy/log.py +288 -0
  146. sqlalchemy/orm/__init__.py +170 -0
  147. sqlalchemy/orm/_orm_constructors.py +2571 -0
  148. sqlalchemy/orm/_typing.py +179 -0
  149. sqlalchemy/orm/attributes.py +2835 -0
  150. sqlalchemy/orm/base.py +973 -0
  151. sqlalchemy/orm/bulk_persistence.py +2123 -0
  152. sqlalchemy/orm/clsregistry.py +571 -0
  153. sqlalchemy/orm/collections.py +1620 -0
  154. sqlalchemy/orm/context.py +3268 -0
  155. sqlalchemy/orm/decl_api.py +1883 -0
  156. sqlalchemy/orm/decl_base.py +2190 -0
  157. sqlalchemy/orm/dependency.py +1304 -0
  158. sqlalchemy/orm/descriptor_props.py +1076 -0
  159. sqlalchemy/orm/dynamic.py +300 -0
  160. sqlalchemy/orm/evaluator.py +379 -0
  161. sqlalchemy/orm/events.py +3261 -0
  162. sqlalchemy/orm/exc.py +228 -0
  163. sqlalchemy/orm/identity.py +302 -0
  164. sqlalchemy/orm/instrumentation.py +754 -0
  165. sqlalchemy/orm/interfaces.py +1474 -0
  166. sqlalchemy/orm/loading.py +1682 -0
  167. sqlalchemy/orm/mapped_collection.py +557 -0
  168. sqlalchemy/orm/mapper.py +4432 -0
  169. sqlalchemy/orm/path_registry.py +811 -0
  170. sqlalchemy/orm/persistence.py +1782 -0
  171. sqlalchemy/orm/properties.py +886 -0
  172. sqlalchemy/orm/query.py +3396 -0
  173. sqlalchemy/orm/relationships.py +3500 -0
  174. sqlalchemy/orm/scoping.py +2165 -0
  175. sqlalchemy/orm/session.py +5301 -0
  176. sqlalchemy/orm/state.py +1143 -0
  177. sqlalchemy/orm/state_changes.py +198 -0
  178. sqlalchemy/orm/strategies.py +3473 -0
  179. sqlalchemy/orm/strategy_options.py +2569 -0
  180. sqlalchemy/orm/sync.py +164 -0
  181. sqlalchemy/orm/unitofwork.py +796 -0
  182. sqlalchemy/orm/util.py +2424 -0
  183. sqlalchemy/orm/writeonly.py +678 -0
  184. sqlalchemy/pool/__init__.py +44 -0
  185. sqlalchemy/pool/base.py +1515 -0
  186. sqlalchemy/pool/events.py +370 -0
  187. sqlalchemy/pool/impl.py +581 -0
  188. sqlalchemy/py.typed +0 -0
  189. sqlalchemy/schema.py +70 -0
  190. sqlalchemy/sql/__init__.py +145 -0
  191. sqlalchemy/sql/_dml_constructors.py +140 -0
  192. sqlalchemy/sql/_elements_constructors.py +1850 -0
  193. sqlalchemy/sql/_orm_types.py +20 -0
  194. sqlalchemy/sql/_py_util.py +75 -0
  195. sqlalchemy/sql/_selectable_constructors.py +635 -0
  196. sqlalchemy/sql/_typing.py +460 -0
  197. sqlalchemy/sql/annotation.py +585 -0
  198. sqlalchemy/sql/base.py +2185 -0
  199. sqlalchemy/sql/cache_key.py +1057 -0
  200. sqlalchemy/sql/coercions.py +1405 -0
  201. sqlalchemy/sql/compiler.py +7818 -0
  202. sqlalchemy/sql/crud.py +1669 -0
  203. sqlalchemy/sql/ddl.py +1378 -0
  204. sqlalchemy/sql/default_comparator.py +552 -0
  205. sqlalchemy/sql/dml.py +1817 -0
  206. sqlalchemy/sql/elements.py +5499 -0
  207. sqlalchemy/sql/events.py +455 -0
  208. sqlalchemy/sql/expression.py +162 -0
  209. sqlalchemy/sql/functions.py +2055 -0
  210. sqlalchemy/sql/lambdas.py +1449 -0
  211. sqlalchemy/sql/naming.py +212 -0
  212. sqlalchemy/sql/operators.py +2579 -0
  213. sqlalchemy/sql/roles.py +323 -0
  214. sqlalchemy/sql/schema.py +6158 -0
  215. sqlalchemy/sql/selectable.py +7004 -0
  216. sqlalchemy/sql/sqltypes.py +3827 -0
  217. sqlalchemy/sql/traversals.py +1024 -0
  218. sqlalchemy/sql/type_api.py +2339 -0
  219. sqlalchemy/sql/util.py +1486 -0
  220. sqlalchemy/sql/visitors.py +1165 -0
  221. sqlalchemy/testing/__init__.py +96 -0
  222. sqlalchemy/testing/assertions.py +989 -0
  223. sqlalchemy/testing/assertsql.py +516 -0
  224. sqlalchemy/testing/asyncio.py +135 -0
  225. sqlalchemy/testing/config.py +427 -0
  226. sqlalchemy/testing/engines.py +472 -0
  227. sqlalchemy/testing/entities.py +117 -0
  228. sqlalchemy/testing/exclusions.py +435 -0
  229. sqlalchemy/testing/fixtures/__init__.py +28 -0
  230. sqlalchemy/testing/fixtures/base.py +366 -0
  231. sqlalchemy/testing/fixtures/mypy.py +312 -0
  232. sqlalchemy/testing/fixtures/orm.py +227 -0
  233. sqlalchemy/testing/fixtures/sql.py +503 -0
  234. sqlalchemy/testing/pickleable.py +155 -0
  235. sqlalchemy/testing/plugin/__init__.py +6 -0
  236. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  237. sqlalchemy/testing/plugin/plugin_base.py +779 -0
  238. sqlalchemy/testing/plugin/pytestplugin.py +868 -0
  239. sqlalchemy/testing/profiling.py +324 -0
  240. sqlalchemy/testing/provision.py +496 -0
  241. sqlalchemy/testing/requirements.py +1818 -0
  242. sqlalchemy/testing/schema.py +224 -0
  243. sqlalchemy/testing/suite/__init__.py +19 -0
  244. sqlalchemy/testing/suite/test_cte.py +211 -0
  245. sqlalchemy/testing/suite/test_ddl.py +389 -0
  246. sqlalchemy/testing/suite/test_deprecations.py +153 -0
  247. sqlalchemy/testing/suite/test_dialect.py +740 -0
  248. sqlalchemy/testing/suite/test_insert.py +630 -0
  249. sqlalchemy/testing/suite/test_reflection.py +3225 -0
  250. sqlalchemy/testing/suite/test_results.py +502 -0
  251. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  252. sqlalchemy/testing/suite/test_select.py +1999 -0
  253. sqlalchemy/testing/suite/test_sequence.py +317 -0
  254. sqlalchemy/testing/suite/test_types.py +2141 -0
  255. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  256. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  257. sqlalchemy/testing/util.py +537 -0
  258. sqlalchemy/testing/warnings.py +52 -0
  259. sqlalchemy/types.py +76 -0
  260. sqlalchemy/util/__init__.py +160 -0
  261. sqlalchemy/util/_collections.py +715 -0
  262. sqlalchemy/util/_concurrency_py3k.py +288 -0
  263. sqlalchemy/util/_has_cy.py +40 -0
  264. sqlalchemy/util/_py_collections.py +541 -0
  265. sqlalchemy/util/compat.py +301 -0
  266. sqlalchemy/util/concurrency.py +108 -0
  267. sqlalchemy/util/deprecations.py +401 -0
  268. sqlalchemy/util/langhelpers.py +2218 -0
  269. sqlalchemy/util/preloaded.py +150 -0
  270. sqlalchemy/util/queue.py +322 -0
  271. sqlalchemy/util/tool_support.py +201 -0
  272. sqlalchemy/util/topological.py +120 -0
  273. sqlalchemy/util/typing.py +629 -0
@@ -0,0 +1,552 @@
1
+ # sql/default_comparator.py
2
+ # Copyright (C) 2005-2024 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
+ """Default implementation of SQL comparison operations.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import typing
14
+ from typing import Any
15
+ from typing import Callable
16
+ from typing import Dict
17
+ from typing import NoReturn
18
+ from typing import Optional
19
+ from typing import Tuple
20
+ from typing import Type
21
+ from typing import Union
22
+
23
+ from . import coercions
24
+ from . import operators
25
+ from . import roles
26
+ from . import type_api
27
+ from .elements import and_
28
+ from .elements import BinaryExpression
29
+ from .elements import ClauseElement
30
+ from .elements import CollationClause
31
+ from .elements import CollectionAggregate
32
+ from .elements import ExpressionClauseList
33
+ from .elements import False_
34
+ from .elements import Null
35
+ from .elements import OperatorExpression
36
+ from .elements import or_
37
+ from .elements import True_
38
+ from .elements import UnaryExpression
39
+ from .operators import OperatorType
40
+ from .. import exc
41
+ from .. import util
42
+
43
+ _T = typing.TypeVar("_T", bound=Any)
44
+
45
+ if typing.TYPE_CHECKING:
46
+ from .elements import ColumnElement
47
+ from .operators import custom_op
48
+ from .type_api import TypeEngine
49
+
50
+
51
+ def _boolean_compare(
52
+ expr: ColumnElement[Any],
53
+ op: OperatorType,
54
+ obj: Any,
55
+ *,
56
+ negate_op: Optional[OperatorType] = None,
57
+ reverse: bool = False,
58
+ _python_is_types: Tuple[Type[Any], ...] = (type(None), bool),
59
+ result_type: Optional[TypeEngine[bool]] = None,
60
+ **kwargs: Any,
61
+ ) -> OperatorExpression[bool]:
62
+ if result_type is None:
63
+ result_type = type_api.BOOLEANTYPE
64
+
65
+ if isinstance(obj, _python_is_types + (Null, True_, False_)):
66
+ # allow x ==/!= True/False to be treated as a literal.
67
+ # this comes out to "== / != true/false" or "1/0" if those
68
+ # constants aren't supported and works on all platforms
69
+ if op in (operators.eq, operators.ne) and isinstance(
70
+ obj, (bool, True_, False_)
71
+ ):
72
+ return OperatorExpression._construct_for_op(
73
+ expr,
74
+ coercions.expect(roles.ConstExprRole, obj),
75
+ op,
76
+ type_=result_type,
77
+ negate=negate_op,
78
+ modifiers=kwargs,
79
+ )
80
+ elif op in (
81
+ operators.is_distinct_from,
82
+ operators.is_not_distinct_from,
83
+ ):
84
+ return OperatorExpression._construct_for_op(
85
+ expr,
86
+ coercions.expect(roles.ConstExprRole, obj),
87
+ op,
88
+ type_=result_type,
89
+ negate=negate_op,
90
+ modifiers=kwargs,
91
+ )
92
+ elif expr._is_collection_aggregate:
93
+ obj = coercions.expect(
94
+ roles.ConstExprRole, element=obj, operator=op, expr=expr
95
+ )
96
+ else:
97
+ # all other None uses IS, IS NOT
98
+ if op in (operators.eq, operators.is_):
99
+ return OperatorExpression._construct_for_op(
100
+ expr,
101
+ coercions.expect(roles.ConstExprRole, obj),
102
+ operators.is_,
103
+ negate=operators.is_not,
104
+ type_=result_type,
105
+ )
106
+ elif op in (operators.ne, operators.is_not):
107
+ return OperatorExpression._construct_for_op(
108
+ expr,
109
+ coercions.expect(roles.ConstExprRole, obj),
110
+ operators.is_not,
111
+ negate=operators.is_,
112
+ type_=result_type,
113
+ )
114
+ else:
115
+ raise exc.ArgumentError(
116
+ "Only '=', '!=', 'is_()', 'is_not()', "
117
+ "'is_distinct_from()', 'is_not_distinct_from()' "
118
+ "operators can be used with None/True/False"
119
+ )
120
+ else:
121
+ obj = coercions.expect(
122
+ roles.BinaryElementRole, element=obj, operator=op, expr=expr
123
+ )
124
+
125
+ if reverse:
126
+ return OperatorExpression._construct_for_op(
127
+ obj,
128
+ expr,
129
+ op,
130
+ type_=result_type,
131
+ negate=negate_op,
132
+ modifiers=kwargs,
133
+ )
134
+ else:
135
+ return OperatorExpression._construct_for_op(
136
+ expr,
137
+ obj,
138
+ op,
139
+ type_=result_type,
140
+ negate=negate_op,
141
+ modifiers=kwargs,
142
+ )
143
+
144
+
145
+ def _custom_op_operate(
146
+ expr: ColumnElement[Any],
147
+ op: custom_op[Any],
148
+ obj: Any,
149
+ reverse: bool = False,
150
+ result_type: Optional[TypeEngine[Any]] = None,
151
+ **kw: Any,
152
+ ) -> ColumnElement[Any]:
153
+ if result_type is None:
154
+ if op.return_type:
155
+ result_type = op.return_type
156
+ elif op.is_comparison:
157
+ result_type = type_api.BOOLEANTYPE
158
+
159
+ return _binary_operate(
160
+ expr, op, obj, reverse=reverse, result_type=result_type, **kw
161
+ )
162
+
163
+
164
+ def _binary_operate(
165
+ expr: ColumnElement[Any],
166
+ op: OperatorType,
167
+ obj: roles.BinaryElementRole[Any],
168
+ *,
169
+ reverse: bool = False,
170
+ result_type: Optional[TypeEngine[_T]] = None,
171
+ **kw: Any,
172
+ ) -> OperatorExpression[_T]:
173
+ coerced_obj = coercions.expect(
174
+ roles.BinaryElementRole, obj, expr=expr, operator=op
175
+ )
176
+
177
+ if reverse:
178
+ left, right = coerced_obj, expr
179
+ else:
180
+ left, right = expr, coerced_obj
181
+
182
+ if result_type is None:
183
+ op, result_type = left.comparator._adapt_expression(
184
+ op, right.comparator
185
+ )
186
+
187
+ return OperatorExpression._construct_for_op(
188
+ left, right, op, type_=result_type, modifiers=kw
189
+ )
190
+
191
+
192
+ def _conjunction_operate(
193
+ expr: ColumnElement[Any], op: OperatorType, other: Any, **kw: Any
194
+ ) -> ColumnElement[Any]:
195
+ if op is operators.and_:
196
+ return and_(expr, other)
197
+ elif op is operators.or_:
198
+ return or_(expr, other)
199
+ else:
200
+ raise NotImplementedError()
201
+
202
+
203
+ def _scalar(
204
+ expr: ColumnElement[Any],
205
+ op: OperatorType,
206
+ fn: Callable[[ColumnElement[Any]], ColumnElement[Any]],
207
+ **kw: Any,
208
+ ) -> ColumnElement[Any]:
209
+ return fn(expr)
210
+
211
+
212
+ def _in_impl(
213
+ expr: ColumnElement[Any],
214
+ op: OperatorType,
215
+ seq_or_selectable: ClauseElement,
216
+ negate_op: OperatorType,
217
+ **kw: Any,
218
+ ) -> ColumnElement[Any]:
219
+ seq_or_selectable = coercions.expect(
220
+ roles.InElementRole, seq_or_selectable, expr=expr, operator=op
221
+ )
222
+ if "in_ops" in seq_or_selectable._annotations:
223
+ op, negate_op = seq_or_selectable._annotations["in_ops"]
224
+
225
+ return _boolean_compare(
226
+ expr, op, seq_or_selectable, negate_op=negate_op, **kw
227
+ )
228
+
229
+
230
+ def _getitem_impl(
231
+ expr: ColumnElement[Any], op: OperatorType, other: Any, **kw: Any
232
+ ) -> ColumnElement[Any]:
233
+ if (
234
+ isinstance(expr.type, type_api.INDEXABLE)
235
+ or isinstance(expr.type, type_api.TypeDecorator)
236
+ and isinstance(expr.type.impl_instance, type_api.INDEXABLE)
237
+ ):
238
+ other = coercions.expect(
239
+ roles.BinaryElementRole, other, expr=expr, operator=op
240
+ )
241
+ return _binary_operate(expr, op, other, **kw)
242
+ else:
243
+ _unsupported_impl(expr, op, other, **kw)
244
+
245
+
246
+ def _unsupported_impl(
247
+ expr: ColumnElement[Any], op: OperatorType, *arg: Any, **kw: Any
248
+ ) -> NoReturn:
249
+ raise NotImplementedError(
250
+ "Operator '%s' is not supported on this expression" % op.__name__
251
+ )
252
+
253
+
254
+ def _inv_impl(
255
+ expr: ColumnElement[Any], op: OperatorType, **kw: Any
256
+ ) -> ColumnElement[Any]:
257
+ """See :meth:`.ColumnOperators.__inv__`."""
258
+
259
+ # undocumented element currently used by the ORM for
260
+ # relationship.contains()
261
+ if hasattr(expr, "negation_clause"):
262
+ return expr.negation_clause
263
+ else:
264
+ return expr._negate()
265
+
266
+
267
+ def _neg_impl(
268
+ expr: ColumnElement[Any], op: OperatorType, **kw: Any
269
+ ) -> ColumnElement[Any]:
270
+ """See :meth:`.ColumnOperators.__neg__`."""
271
+ return UnaryExpression(expr, operator=operators.neg, type_=expr.type)
272
+
273
+
274
+ def _bitwise_not_impl(
275
+ expr: ColumnElement[Any], op: OperatorType, **kw: Any
276
+ ) -> ColumnElement[Any]:
277
+ """See :meth:`.ColumnOperators.bitwise_not`."""
278
+
279
+ return UnaryExpression(
280
+ expr, operator=operators.bitwise_not_op, type_=expr.type
281
+ )
282
+
283
+
284
+ def _match_impl(
285
+ expr: ColumnElement[Any], op: OperatorType, other: Any, **kw: Any
286
+ ) -> ColumnElement[Any]:
287
+ """See :meth:`.ColumnOperators.match`."""
288
+
289
+ return _boolean_compare(
290
+ expr,
291
+ operators.match_op,
292
+ coercions.expect(
293
+ roles.BinaryElementRole,
294
+ other,
295
+ expr=expr,
296
+ operator=operators.match_op,
297
+ ),
298
+ result_type=type_api.MATCHTYPE,
299
+ negate_op=(
300
+ operators.not_match_op
301
+ if op is operators.match_op
302
+ else operators.match_op
303
+ ),
304
+ **kw,
305
+ )
306
+
307
+
308
+ def _distinct_impl(
309
+ expr: ColumnElement[Any], op: OperatorType, **kw: Any
310
+ ) -> ColumnElement[Any]:
311
+ """See :meth:`.ColumnOperators.distinct`."""
312
+ return UnaryExpression(
313
+ expr, operator=operators.distinct_op, type_=expr.type
314
+ )
315
+
316
+
317
+ def _between_impl(
318
+ expr: ColumnElement[Any],
319
+ op: OperatorType,
320
+ cleft: Any,
321
+ cright: Any,
322
+ **kw: Any,
323
+ ) -> ColumnElement[Any]:
324
+ """See :meth:`.ColumnOperators.between`."""
325
+ return BinaryExpression(
326
+ expr,
327
+ ExpressionClauseList._construct_for_list(
328
+ operators.and_,
329
+ type_api.NULLTYPE,
330
+ coercions.expect(
331
+ roles.BinaryElementRole,
332
+ cleft,
333
+ expr=expr,
334
+ operator=operators.and_,
335
+ ),
336
+ coercions.expect(
337
+ roles.BinaryElementRole,
338
+ cright,
339
+ expr=expr,
340
+ operator=operators.and_,
341
+ ),
342
+ group=False,
343
+ ),
344
+ op,
345
+ negate=(
346
+ operators.not_between_op
347
+ if op is operators.between_op
348
+ else operators.between_op
349
+ ),
350
+ modifiers=kw,
351
+ )
352
+
353
+
354
+ def _collate_impl(
355
+ expr: ColumnElement[str], op: OperatorType, collation: str, **kw: Any
356
+ ) -> ColumnElement[str]:
357
+ return CollationClause._create_collation_expression(expr, collation)
358
+
359
+
360
+ def _regexp_match_impl(
361
+ expr: ColumnElement[str],
362
+ op: OperatorType,
363
+ pattern: Any,
364
+ flags: Optional[str],
365
+ **kw: Any,
366
+ ) -> ColumnElement[Any]:
367
+ return BinaryExpression(
368
+ expr,
369
+ coercions.expect(
370
+ roles.BinaryElementRole,
371
+ pattern,
372
+ expr=expr,
373
+ operator=operators.comma_op,
374
+ ),
375
+ op,
376
+ negate=operators.not_regexp_match_op,
377
+ modifiers={"flags": flags},
378
+ )
379
+
380
+
381
+ def _regexp_replace_impl(
382
+ expr: ColumnElement[Any],
383
+ op: OperatorType,
384
+ pattern: Any,
385
+ replacement: Any,
386
+ flags: Optional[str],
387
+ **kw: Any,
388
+ ) -> ColumnElement[Any]:
389
+ return BinaryExpression(
390
+ expr,
391
+ ExpressionClauseList._construct_for_list(
392
+ operators.comma_op,
393
+ type_api.NULLTYPE,
394
+ coercions.expect(
395
+ roles.BinaryElementRole,
396
+ pattern,
397
+ expr=expr,
398
+ operator=operators.comma_op,
399
+ ),
400
+ coercions.expect(
401
+ roles.BinaryElementRole,
402
+ replacement,
403
+ expr=expr,
404
+ operator=operators.comma_op,
405
+ ),
406
+ group=False,
407
+ ),
408
+ op,
409
+ modifiers={"flags": flags},
410
+ )
411
+
412
+
413
+ # a mapping of operators with the method they use, along with
414
+ # additional keyword arguments to be passed
415
+ operator_lookup: Dict[
416
+ str,
417
+ Tuple[
418
+ Callable[..., ColumnElement[Any]],
419
+ util.immutabledict[
420
+ str, Union[OperatorType, Callable[..., ColumnElement[Any]]]
421
+ ],
422
+ ],
423
+ ] = {
424
+ "and_": (_conjunction_operate, util.EMPTY_DICT),
425
+ "or_": (_conjunction_operate, util.EMPTY_DICT),
426
+ "inv": (_inv_impl, util.EMPTY_DICT),
427
+ "add": (_binary_operate, util.EMPTY_DICT),
428
+ "mul": (_binary_operate, util.EMPTY_DICT),
429
+ "sub": (_binary_operate, util.EMPTY_DICT),
430
+ "div": (_binary_operate, util.EMPTY_DICT),
431
+ "mod": (_binary_operate, util.EMPTY_DICT),
432
+ "bitwise_xor_op": (_binary_operate, util.EMPTY_DICT),
433
+ "bitwise_or_op": (_binary_operate, util.EMPTY_DICT),
434
+ "bitwise_and_op": (_binary_operate, util.EMPTY_DICT),
435
+ "bitwise_not_op": (_bitwise_not_impl, util.EMPTY_DICT),
436
+ "bitwise_lshift_op": (_binary_operate, util.EMPTY_DICT),
437
+ "bitwise_rshift_op": (_binary_operate, util.EMPTY_DICT),
438
+ "truediv": (_binary_operate, util.EMPTY_DICT),
439
+ "floordiv": (_binary_operate, util.EMPTY_DICT),
440
+ "custom_op": (_custom_op_operate, util.EMPTY_DICT),
441
+ "json_path_getitem_op": (_binary_operate, util.EMPTY_DICT),
442
+ "json_getitem_op": (_binary_operate, util.EMPTY_DICT),
443
+ "concat_op": (_binary_operate, util.EMPTY_DICT),
444
+ "any_op": (
445
+ _scalar,
446
+ util.immutabledict({"fn": CollectionAggregate._create_any}),
447
+ ),
448
+ "all_op": (
449
+ _scalar,
450
+ util.immutabledict({"fn": CollectionAggregate._create_all}),
451
+ ),
452
+ "lt": (_boolean_compare, util.immutabledict({"negate_op": operators.ge})),
453
+ "le": (_boolean_compare, util.immutabledict({"negate_op": operators.gt})),
454
+ "ne": (_boolean_compare, util.immutabledict({"negate_op": operators.eq})),
455
+ "gt": (_boolean_compare, util.immutabledict({"negate_op": operators.le})),
456
+ "ge": (_boolean_compare, util.immutabledict({"negate_op": operators.lt})),
457
+ "eq": (_boolean_compare, util.immutabledict({"negate_op": operators.ne})),
458
+ "is_distinct_from": (
459
+ _boolean_compare,
460
+ util.immutabledict({"negate_op": operators.is_not_distinct_from}),
461
+ ),
462
+ "is_not_distinct_from": (
463
+ _boolean_compare,
464
+ util.immutabledict({"negate_op": operators.is_distinct_from}),
465
+ ),
466
+ "like_op": (
467
+ _boolean_compare,
468
+ util.immutabledict({"negate_op": operators.not_like_op}),
469
+ ),
470
+ "ilike_op": (
471
+ _boolean_compare,
472
+ util.immutabledict({"negate_op": operators.not_ilike_op}),
473
+ ),
474
+ "not_like_op": (
475
+ _boolean_compare,
476
+ util.immutabledict({"negate_op": operators.like_op}),
477
+ ),
478
+ "not_ilike_op": (
479
+ _boolean_compare,
480
+ util.immutabledict({"negate_op": operators.ilike_op}),
481
+ ),
482
+ "contains_op": (
483
+ _boolean_compare,
484
+ util.immutabledict({"negate_op": operators.not_contains_op}),
485
+ ),
486
+ "icontains_op": (
487
+ _boolean_compare,
488
+ util.immutabledict({"negate_op": operators.not_icontains_op}),
489
+ ),
490
+ "startswith_op": (
491
+ _boolean_compare,
492
+ util.immutabledict({"negate_op": operators.not_startswith_op}),
493
+ ),
494
+ "istartswith_op": (
495
+ _boolean_compare,
496
+ util.immutabledict({"negate_op": operators.not_istartswith_op}),
497
+ ),
498
+ "endswith_op": (
499
+ _boolean_compare,
500
+ util.immutabledict({"negate_op": operators.not_endswith_op}),
501
+ ),
502
+ "iendswith_op": (
503
+ _boolean_compare,
504
+ util.immutabledict({"negate_op": operators.not_iendswith_op}),
505
+ ),
506
+ "desc_op": (
507
+ _scalar,
508
+ util.immutabledict({"fn": UnaryExpression._create_desc}),
509
+ ),
510
+ "asc_op": (
511
+ _scalar,
512
+ util.immutabledict({"fn": UnaryExpression._create_asc}),
513
+ ),
514
+ "nulls_first_op": (
515
+ _scalar,
516
+ util.immutabledict({"fn": UnaryExpression._create_nulls_first}),
517
+ ),
518
+ "nulls_last_op": (
519
+ _scalar,
520
+ util.immutabledict({"fn": UnaryExpression._create_nulls_last}),
521
+ ),
522
+ "in_op": (
523
+ _in_impl,
524
+ util.immutabledict({"negate_op": operators.not_in_op}),
525
+ ),
526
+ "not_in_op": (
527
+ _in_impl,
528
+ util.immutabledict({"negate_op": operators.in_op}),
529
+ ),
530
+ "is_": (
531
+ _boolean_compare,
532
+ util.immutabledict({"negate_op": operators.is_}),
533
+ ),
534
+ "is_not": (
535
+ _boolean_compare,
536
+ util.immutabledict({"negate_op": operators.is_not}),
537
+ ),
538
+ "collate": (_collate_impl, util.EMPTY_DICT),
539
+ "match_op": (_match_impl, util.EMPTY_DICT),
540
+ "not_match_op": (_match_impl, util.EMPTY_DICT),
541
+ "distinct_op": (_distinct_impl, util.EMPTY_DICT),
542
+ "between_op": (_between_impl, util.EMPTY_DICT),
543
+ "not_between_op": (_between_impl, util.EMPTY_DICT),
544
+ "neg": (_neg_impl, util.EMPTY_DICT),
545
+ "getitem": (_getitem_impl, util.EMPTY_DICT),
546
+ "lshift": (_unsupported_impl, util.EMPTY_DICT),
547
+ "rshift": (_unsupported_impl, util.EMPTY_DICT),
548
+ "contains": (_unsupported_impl, util.EMPTY_DICT),
549
+ "regexp_match_op": (_regexp_match_impl, util.EMPTY_DICT),
550
+ "not_regexp_match_op": (_regexp_match_impl, util.EMPTY_DICT),
551
+ "regexp_replace_op": (_regexp_replace_impl, util.EMPTY_DICT),
552
+ }