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.
- sqlalchemy/__init__.py +283 -0
- sqlalchemy/connectors/__init__.py +18 -0
- sqlalchemy/connectors/aioodbc.py +184 -0
- sqlalchemy/connectors/asyncio.py +429 -0
- sqlalchemy/connectors/pyodbc.py +250 -0
- sqlalchemy/cyextension/__init__.py +6 -0
- sqlalchemy/cyextension/collections.cp313t-win_amd64.pyd +0 -0
- sqlalchemy/cyextension/collections.pyx +409 -0
- sqlalchemy/cyextension/immutabledict.cp313t-win_amd64.pyd +0 -0
- sqlalchemy/cyextension/immutabledict.pxd +8 -0
- sqlalchemy/cyextension/immutabledict.pyx +133 -0
- sqlalchemy/cyextension/processors.cp313t-win_amd64.pyd +0 -0
- sqlalchemy/cyextension/processors.pyx +68 -0
- sqlalchemy/cyextension/resultproxy.cp313t-win_amd64.pyd +0 -0
- sqlalchemy/cyextension/resultproxy.pyx +102 -0
- sqlalchemy/cyextension/util.cp313t-win_amd64.pyd +0 -0
- sqlalchemy/cyextension/util.pyx +90 -0
- sqlalchemy/dialects/__init__.py +62 -0
- sqlalchemy/dialects/_typing.py +30 -0
- sqlalchemy/dialects/mssql/__init__.py +88 -0
- sqlalchemy/dialects/mssql/aioodbc.py +63 -0
- sqlalchemy/dialects/mssql/base.py +4093 -0
- sqlalchemy/dialects/mssql/information_schema.py +285 -0
- sqlalchemy/dialects/mssql/json.py +129 -0
- sqlalchemy/dialects/mssql/provision.py +185 -0
- sqlalchemy/dialects/mssql/pymssql.py +126 -0
- sqlalchemy/dialects/mssql/pyodbc.py +760 -0
- sqlalchemy/dialects/mysql/__init__.py +104 -0
- sqlalchemy/dialects/mysql/aiomysql.py +250 -0
- sqlalchemy/dialects/mysql/asyncmy.py +231 -0
- sqlalchemy/dialects/mysql/base.py +3949 -0
- sqlalchemy/dialects/mysql/cymysql.py +106 -0
- sqlalchemy/dialects/mysql/dml.py +225 -0
- sqlalchemy/dialects/mysql/enumerated.py +282 -0
- sqlalchemy/dialects/mysql/expression.py +146 -0
- sqlalchemy/dialects/mysql/json.py +91 -0
- sqlalchemy/dialects/mysql/mariadb.py +72 -0
- sqlalchemy/dialects/mysql/mariadbconnector.py +322 -0
- sqlalchemy/dialects/mysql/mysqlconnector.py +302 -0
- sqlalchemy/dialects/mysql/mysqldb.py +314 -0
- sqlalchemy/dialects/mysql/provision.py +153 -0
- sqlalchemy/dialects/mysql/pymysql.py +158 -0
- sqlalchemy/dialects/mysql/pyodbc.py +157 -0
- sqlalchemy/dialects/mysql/reflection.py +727 -0
- sqlalchemy/dialects/mysql/reserved_words.py +570 -0
- sqlalchemy/dialects/mysql/types.py +835 -0
- sqlalchemy/dialects/oracle/__init__.py +81 -0
- sqlalchemy/dialects/oracle/base.py +3802 -0
- sqlalchemy/dialects/oracle/cx_oracle.py +1555 -0
- sqlalchemy/dialects/oracle/dictionary.py +507 -0
- sqlalchemy/dialects/oracle/oracledb.py +941 -0
- sqlalchemy/dialects/oracle/provision.py +297 -0
- sqlalchemy/dialects/oracle/types.py +316 -0
- sqlalchemy/dialects/oracle/vector.py +365 -0
- sqlalchemy/dialects/postgresql/__init__.py +167 -0
- sqlalchemy/dialects/postgresql/_psycopg_common.py +189 -0
- sqlalchemy/dialects/postgresql/array.py +519 -0
- sqlalchemy/dialects/postgresql/asyncpg.py +1284 -0
- sqlalchemy/dialects/postgresql/base.py +5378 -0
- sqlalchemy/dialects/postgresql/dml.py +339 -0
- sqlalchemy/dialects/postgresql/ext.py +540 -0
- sqlalchemy/dialects/postgresql/hstore.py +406 -0
- sqlalchemy/dialects/postgresql/json.py +404 -0
- sqlalchemy/dialects/postgresql/named_types.py +524 -0
- sqlalchemy/dialects/postgresql/operators.py +129 -0
- sqlalchemy/dialects/postgresql/pg8000.py +669 -0
- sqlalchemy/dialects/postgresql/pg_catalog.py +326 -0
- sqlalchemy/dialects/postgresql/provision.py +183 -0
- sqlalchemy/dialects/postgresql/psycopg.py +862 -0
- sqlalchemy/dialects/postgresql/psycopg2.py +892 -0
- sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
- sqlalchemy/dialects/postgresql/ranges.py +1031 -0
- sqlalchemy/dialects/postgresql/types.py +313 -0
- sqlalchemy/dialects/sqlite/__init__.py +57 -0
- sqlalchemy/dialects/sqlite/aiosqlite.py +482 -0
- sqlalchemy/dialects/sqlite/base.py +3056 -0
- sqlalchemy/dialects/sqlite/dml.py +263 -0
- sqlalchemy/dialects/sqlite/json.py +92 -0
- sqlalchemy/dialects/sqlite/provision.py +229 -0
- sqlalchemy/dialects/sqlite/pysqlcipher.py +157 -0
- sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
- sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
- sqlalchemy/engine/__init__.py +62 -0
- sqlalchemy/engine/_py_processors.py +136 -0
- sqlalchemy/engine/_py_row.py +128 -0
- sqlalchemy/engine/_py_util.py +74 -0
- sqlalchemy/engine/base.py +3390 -0
- sqlalchemy/engine/characteristics.py +155 -0
- sqlalchemy/engine/create.py +893 -0
- sqlalchemy/engine/cursor.py +2298 -0
- sqlalchemy/engine/default.py +2394 -0
- sqlalchemy/engine/events.py +965 -0
- sqlalchemy/engine/interfaces.py +3471 -0
- sqlalchemy/engine/mock.py +134 -0
- sqlalchemy/engine/processors.py +61 -0
- sqlalchemy/engine/reflection.py +2102 -0
- sqlalchemy/engine/result.py +2399 -0
- sqlalchemy/engine/row.py +400 -0
- sqlalchemy/engine/strategies.py +16 -0
- sqlalchemy/engine/url.py +924 -0
- sqlalchemy/engine/util.py +167 -0
- sqlalchemy/event/__init__.py +26 -0
- sqlalchemy/event/api.py +220 -0
- sqlalchemy/event/attr.py +676 -0
- sqlalchemy/event/base.py +472 -0
- sqlalchemy/event/legacy.py +258 -0
- sqlalchemy/event/registry.py +390 -0
- sqlalchemy/events.py +17 -0
- sqlalchemy/exc.py +832 -0
- sqlalchemy/ext/__init__.py +11 -0
- sqlalchemy/ext/associationproxy.py +2027 -0
- sqlalchemy/ext/asyncio/__init__.py +25 -0
- sqlalchemy/ext/asyncio/base.py +281 -0
- sqlalchemy/ext/asyncio/engine.py +1471 -0
- sqlalchemy/ext/asyncio/exc.py +21 -0
- sqlalchemy/ext/asyncio/result.py +965 -0
- sqlalchemy/ext/asyncio/scoping.py +1599 -0
- sqlalchemy/ext/asyncio/session.py +1947 -0
- sqlalchemy/ext/automap.py +1701 -0
- sqlalchemy/ext/baked.py +570 -0
- sqlalchemy/ext/compiler.py +600 -0
- sqlalchemy/ext/declarative/__init__.py +65 -0
- sqlalchemy/ext/declarative/extensions.py +564 -0
- sqlalchemy/ext/horizontal_shard.py +478 -0
- sqlalchemy/ext/hybrid.py +1535 -0
- sqlalchemy/ext/indexable.py +364 -0
- sqlalchemy/ext/instrumentation.py +450 -0
- sqlalchemy/ext/mutable.py +1085 -0
- sqlalchemy/ext/mypy/__init__.py +6 -0
- sqlalchemy/ext/mypy/apply.py +324 -0
- sqlalchemy/ext/mypy/decl_class.py +515 -0
- sqlalchemy/ext/mypy/infer.py +590 -0
- sqlalchemy/ext/mypy/names.py +335 -0
- sqlalchemy/ext/mypy/plugin.py +303 -0
- sqlalchemy/ext/mypy/util.py +357 -0
- sqlalchemy/ext/orderinglist.py +439 -0
- sqlalchemy/ext/serializer.py +185 -0
- sqlalchemy/future/__init__.py +16 -0
- sqlalchemy/future/engine.py +15 -0
- sqlalchemy/inspection.py +174 -0
- sqlalchemy/log.py +288 -0
- sqlalchemy/orm/__init__.py +171 -0
- sqlalchemy/orm/_orm_constructors.py +2661 -0
- sqlalchemy/orm/_typing.py +179 -0
- sqlalchemy/orm/attributes.py +2845 -0
- sqlalchemy/orm/base.py +971 -0
- sqlalchemy/orm/bulk_persistence.py +2135 -0
- sqlalchemy/orm/clsregistry.py +571 -0
- sqlalchemy/orm/collections.py +1627 -0
- sqlalchemy/orm/context.py +3334 -0
- sqlalchemy/orm/decl_api.py +2004 -0
- sqlalchemy/orm/decl_base.py +2192 -0
- sqlalchemy/orm/dependency.py +1302 -0
- sqlalchemy/orm/descriptor_props.py +1092 -0
- sqlalchemy/orm/dynamic.py +300 -0
- sqlalchemy/orm/evaluator.py +379 -0
- sqlalchemy/orm/events.py +3252 -0
- sqlalchemy/orm/exc.py +237 -0
- sqlalchemy/orm/identity.py +302 -0
- sqlalchemy/orm/instrumentation.py +754 -0
- sqlalchemy/orm/interfaces.py +1496 -0
- sqlalchemy/orm/loading.py +1686 -0
- sqlalchemy/orm/mapped_collection.py +557 -0
- sqlalchemy/orm/mapper.py +4444 -0
- sqlalchemy/orm/path_registry.py +809 -0
- sqlalchemy/orm/persistence.py +1788 -0
- sqlalchemy/orm/properties.py +935 -0
- sqlalchemy/orm/query.py +3459 -0
- sqlalchemy/orm/relationships.py +3508 -0
- sqlalchemy/orm/scoping.py +2148 -0
- sqlalchemy/orm/session.py +5280 -0
- sqlalchemy/orm/state.py +1168 -0
- sqlalchemy/orm/state_changes.py +196 -0
- sqlalchemy/orm/strategies.py +3470 -0
- sqlalchemy/orm/strategy_options.py +2568 -0
- sqlalchemy/orm/sync.py +164 -0
- sqlalchemy/orm/unitofwork.py +796 -0
- sqlalchemy/orm/util.py +2403 -0
- sqlalchemy/orm/writeonly.py +674 -0
- sqlalchemy/pool/__init__.py +44 -0
- sqlalchemy/pool/base.py +1524 -0
- sqlalchemy/pool/events.py +375 -0
- sqlalchemy/pool/impl.py +588 -0
- sqlalchemy/py.typed +0 -0
- sqlalchemy/schema.py +69 -0
- sqlalchemy/sql/__init__.py +145 -0
- sqlalchemy/sql/_dml_constructors.py +132 -0
- sqlalchemy/sql/_elements_constructors.py +1872 -0
- sqlalchemy/sql/_orm_types.py +20 -0
- sqlalchemy/sql/_py_util.py +75 -0
- sqlalchemy/sql/_selectable_constructors.py +763 -0
- sqlalchemy/sql/_typing.py +482 -0
- sqlalchemy/sql/annotation.py +587 -0
- sqlalchemy/sql/base.py +2293 -0
- sqlalchemy/sql/cache_key.py +1057 -0
- sqlalchemy/sql/coercions.py +1404 -0
- sqlalchemy/sql/compiler.py +8081 -0
- sqlalchemy/sql/crud.py +1752 -0
- sqlalchemy/sql/ddl.py +1444 -0
- sqlalchemy/sql/default_comparator.py +551 -0
- sqlalchemy/sql/dml.py +1850 -0
- sqlalchemy/sql/elements.py +5589 -0
- sqlalchemy/sql/events.py +458 -0
- sqlalchemy/sql/expression.py +159 -0
- sqlalchemy/sql/functions.py +2158 -0
- sqlalchemy/sql/lambdas.py +1442 -0
- sqlalchemy/sql/naming.py +209 -0
- sqlalchemy/sql/operators.py +2623 -0
- sqlalchemy/sql/roles.py +323 -0
- sqlalchemy/sql/schema.py +6222 -0
- sqlalchemy/sql/selectable.py +7265 -0
- sqlalchemy/sql/sqltypes.py +3930 -0
- sqlalchemy/sql/traversals.py +1024 -0
- sqlalchemy/sql/type_api.py +2368 -0
- sqlalchemy/sql/util.py +1485 -0
- sqlalchemy/sql/visitors.py +1164 -0
- sqlalchemy/testing/__init__.py +96 -0
- sqlalchemy/testing/assertions.py +994 -0
- sqlalchemy/testing/assertsql.py +520 -0
- sqlalchemy/testing/asyncio.py +135 -0
- sqlalchemy/testing/config.py +434 -0
- sqlalchemy/testing/engines.py +483 -0
- sqlalchemy/testing/entities.py +117 -0
- sqlalchemy/testing/exclusions.py +476 -0
- sqlalchemy/testing/fixtures/__init__.py +28 -0
- sqlalchemy/testing/fixtures/base.py +384 -0
- sqlalchemy/testing/fixtures/mypy.py +332 -0
- sqlalchemy/testing/fixtures/orm.py +227 -0
- sqlalchemy/testing/fixtures/sql.py +482 -0
- sqlalchemy/testing/pickleable.py +155 -0
- sqlalchemy/testing/plugin/__init__.py +6 -0
- sqlalchemy/testing/plugin/bootstrap.py +51 -0
- sqlalchemy/testing/plugin/plugin_base.py +828 -0
- sqlalchemy/testing/plugin/pytestplugin.py +892 -0
- sqlalchemy/testing/profiling.py +329 -0
- sqlalchemy/testing/provision.py +603 -0
- sqlalchemy/testing/requirements.py +1945 -0
- sqlalchemy/testing/schema.py +198 -0
- sqlalchemy/testing/suite/__init__.py +19 -0
- sqlalchemy/testing/suite/test_cte.py +237 -0
- sqlalchemy/testing/suite/test_ddl.py +389 -0
- sqlalchemy/testing/suite/test_deprecations.py +153 -0
- sqlalchemy/testing/suite/test_dialect.py +776 -0
- sqlalchemy/testing/suite/test_insert.py +630 -0
- sqlalchemy/testing/suite/test_reflection.py +3557 -0
- sqlalchemy/testing/suite/test_results.py +504 -0
- sqlalchemy/testing/suite/test_rowcount.py +258 -0
- sqlalchemy/testing/suite/test_select.py +2010 -0
- sqlalchemy/testing/suite/test_sequence.py +317 -0
- sqlalchemy/testing/suite/test_types.py +2147 -0
- sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
- sqlalchemy/testing/suite/test_update_delete.py +139 -0
- sqlalchemy/testing/util.py +535 -0
- sqlalchemy/testing/warnings.py +52 -0
- sqlalchemy/types.py +74 -0
- sqlalchemy/util/__init__.py +162 -0
- sqlalchemy/util/_collections.py +712 -0
- sqlalchemy/util/_concurrency_py3k.py +288 -0
- sqlalchemy/util/_has_cy.py +40 -0
- sqlalchemy/util/_py_collections.py +541 -0
- sqlalchemy/util/compat.py +421 -0
- sqlalchemy/util/concurrency.py +110 -0
- sqlalchemy/util/deprecations.py +401 -0
- sqlalchemy/util/langhelpers.py +2203 -0
- sqlalchemy/util/preloaded.py +150 -0
- sqlalchemy/util/queue.py +322 -0
- sqlalchemy/util/tool_support.py +201 -0
- sqlalchemy/util/topological.py +120 -0
- sqlalchemy/util/typing.py +734 -0
- sqlalchemy-2.0.47.dist-info/METADATA +243 -0
- sqlalchemy-2.0.47.dist-info/RECORD +274 -0
- sqlalchemy-2.0.47.dist-info/WHEEL +5 -0
- sqlalchemy-2.0.47.dist-info/licenses/LICENSE +19 -0
- 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
|
+
)
|