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