1# sql/operators.py 
    2# Copyright (C) 2005-2021 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: http://www.opensource.org/licenses/mit-license.php 
    7 
    8# This module is part of SQLAlchemy and is released under 
    9# the MIT License: http://www.opensource.org/licenses/mit-license.php 
    10 
    11"""Defines operators used in SQL expressions.""" 
    12 
    13from operator import add 
    14from operator import and_ 
    15from operator import contains 
    16from operator import eq 
    17from operator import ge 
    18from operator import getitem 
    19from operator import gt 
    20from operator import inv 
    21from operator import le 
    22from operator import lshift 
    23from operator import lt 
    24from operator import mod 
    25from operator import mul 
    26from operator import ne 
    27from operator import neg 
    28from operator import or_ 
    29from operator import rshift 
    30from operator import sub 
    31from operator import truediv 
    32 
    33from .. import util 
    34 
    35 
    36if util.py2k: 
    37    from operator import div 
    38else: 
    39    div = truediv 
    40 
    41 
    42class Operators(object): 
    43    """Base of comparison and logical operators. 
    44 
    45    Implements base methods 
    46    :meth:`~sqlalchemy.sql.operators.Operators.operate` and 
    47    :meth:`~sqlalchemy.sql.operators.Operators.reverse_operate`, as well as 
    48    :meth:`~sqlalchemy.sql.operators.Operators.__and__`, 
    49    :meth:`~sqlalchemy.sql.operators.Operators.__or__`, 
    50    :meth:`~sqlalchemy.sql.operators.Operators.__invert__`. 
    51 
    52    Usually is used via its most common subclass 
    53    :class:`.ColumnOperators`. 
    54 
    55    """ 
    56 
    57    __slots__ = () 
    58 
    59    def __and__(self, other): 
    60        """Implement the ``&`` operator. 
    61 
    62        When used with SQL expressions, results in an 
    63        AND operation, equivalent to 
    64        :func:`_expression.and_`, that is:: 
    65 
    66            a & b 
    67 
    68        is equivalent to:: 
    69 
    70            from sqlalchemy import and_ 
    71            and_(a, b) 
    72 
    73        Care should be taken when using ``&`` regarding 
    74        operator precedence; the ``&`` operator has the highest precedence. 
    75        The operands should be enclosed in parenthesis if they contain 
    76        further sub expressions:: 
    77 
    78            (a == 2) & (b == 4) 
    79 
    80        """ 
    81        return self.operate(and_, other) 
    82 
    83    def __or__(self, other): 
    84        """Implement the ``|`` operator. 
    85 
    86        When used with SQL expressions, results in an 
    87        OR operation, equivalent to 
    88        :func:`_expression.or_`, that is:: 
    89 
    90            a | b 
    91 
    92        is equivalent to:: 
    93 
    94            from sqlalchemy import or_ 
    95            or_(a, b) 
    96 
    97        Care should be taken when using ``|`` regarding 
    98        operator precedence; the ``|`` operator has the highest precedence. 
    99        The operands should be enclosed in parenthesis if they contain 
    100        further sub expressions:: 
    101 
    102            (a == 2) | (b == 4) 
    103 
    104        """ 
    105        return self.operate(or_, other) 
    106 
    107    def __invert__(self): 
    108        """Implement the ``~`` operator. 
    109 
    110        When used with SQL expressions, results in a 
    111        NOT operation, equivalent to 
    112        :func:`_expression.not_`, that is:: 
    113 
    114            ~a 
    115 
    116        is equivalent to:: 
    117 
    118            from sqlalchemy import not_ 
    119            not_(a) 
    120 
    121        """ 
    122        return self.operate(inv) 
    123 
    124    def op( 
    125        self, opstring, precedence=0, is_comparison=False, return_type=None 
    126    ): 
    127        """Produce a generic operator function. 
    128 
    129        e.g.:: 
    130 
    131          somecolumn.op("*")(5) 
    132 
    133        produces:: 
    134 
    135          somecolumn * 5 
    136 
    137        This function can also be used to make bitwise operators explicit. For 
    138        example:: 
    139 
    140          somecolumn.op('&')(0xff) 
    141 
    142        is a bitwise AND of the value in ``somecolumn``. 
    143 
    144        :param operator: a string which will be output as the infix operator 
    145          between this element and the expression passed to the 
    146          generated function. 
    147 
    148        :param precedence: precedence to apply to the operator, when 
    149         parenthesizing expressions.  A lower number will cause the expression 
    150         to be parenthesized when applied against another operator with 
    151         higher precedence.  The default value of ``0`` is lower than all 
    152         operators except for the comma (``,``) and ``AS`` operators. 
    153         A value of 100 will be higher or equal to all operators, and -100 
    154         will be lower than or equal to all operators. 
    155 
    156        :param is_comparison: if True, the operator will be considered as a 
    157         "comparison" operator, that is which evaluates to a boolean 
    158         true/false value, like ``==``, ``>``, etc.  This flag should be set 
    159         so that ORM relationships can establish that the operator is a 
    160         comparison operator when used in a custom join condition. 
    161 
    162         .. versionadded:: 0.9.2 - added the 
    163            :paramref:`.Operators.op.is_comparison` flag. 
    164 
    165        :param return_type: a :class:`.TypeEngine` class or object that will 
    166          force the return type of an expression produced by this operator 
    167          to be of that type.   By default, operators that specify 
    168          :paramref:`.Operators.op.is_comparison` will resolve to 
    169          :class:`.Boolean`, and those that do not will be of the same 
    170          type as the left-hand operand. 
    171 
    172          .. versionadded:: 1.2.0b3 - added the 
    173             :paramref:`.Operators.op.return_type` argument. 
    174 
    175        .. seealso:: 
    176 
    177            :ref:`types_operators` 
    178 
    179            :ref:`relationship_custom_operator` 
    180 
    181        """ 
    182        operator = custom_op(opstring, precedence, is_comparison, return_type) 
    183 
    184        def against(other): 
    185            return operator(self, other) 
    186 
    187        return against 
    188 
    189    def bool_op(self, opstring, precedence=0): 
    190        """Return a custom boolean operator. 
    191 
    192        This method is shorthand for calling 
    193        :meth:`.Operators.op` and passing the 
    194        :paramref:`.Operators.op.is_comparison` 
    195        flag with True. 
    196 
    197        .. versionadded:: 1.2.0b3 
    198 
    199        .. seealso:: 
    200 
    201            :meth:`.Operators.op` 
    202 
    203        """ 
    204        return self.op(opstring, precedence=precedence, is_comparison=True) 
    205 
    206    def operate(self, op, *other, **kwargs): 
    207        r"""Operate on an argument. 
    208 
    209        This is the lowest level of operation, raises 
    210        :class:`NotImplementedError` by default. 
    211 
    212        Overriding this on a subclass can allow common 
    213        behavior to be applied to all operations. 
    214        For example, overriding :class:`.ColumnOperators` 
    215        to apply ``func.lower()`` to the left and right 
    216        side:: 
    217 
    218            class MyComparator(ColumnOperators): 
    219                def operate(self, op, other): 
    220                    return op(func.lower(self), func.lower(other)) 
    221 
    222        :param op:  Operator callable. 
    223        :param \*other: the 'other' side of the operation. Will 
    224         be a single scalar for most operations. 
    225        :param \**kwargs: modifiers.  These may be passed by special 
    226         operators such as :meth:`ColumnOperators.contains`. 
    227 
    228 
    229        """ 
    230        raise NotImplementedError(str(op)) 
    231 
    232    def reverse_operate(self, op, other, **kwargs): 
    233        """Reverse operate on an argument. 
    234 
    235        Usage is the same as :meth:`operate`. 
    236 
    237        """ 
    238        raise NotImplementedError(str(op)) 
    239 
    240 
    241class custom_op(object): 
    242    """Represent a 'custom' operator. 
    243 
    244    :class:`.custom_op` is normally instantiated when the 
    245    :meth:`.Operators.op` or :meth:`.Operators.bool_op` methods 
    246    are used to create a custom operator callable.  The class can also be 
    247    used directly when programmatically constructing expressions.   E.g. 
    248    to represent the "factorial" operation:: 
    249 
    250        from sqlalchemy.sql import UnaryExpression 
    251        from sqlalchemy.sql import operators 
    252        from sqlalchemy import Numeric 
    253 
    254        unary = UnaryExpression(table.c.somecolumn, 
    255                modifier=operators.custom_op("!"), 
    256                type_=Numeric) 
    257 
    258 
    259    .. seealso:: 
    260 
    261        :meth:`.Operators.op` 
    262 
    263        :meth:`.Operators.bool_op` 
    264 
    265    """ 
    266 
    267    __name__ = "custom_op" 
    268 
    269    def __init__( 
    270        self, 
    271        opstring, 
    272        precedence=0, 
    273        is_comparison=False, 
    274        return_type=None, 
    275        natural_self_precedent=False, 
    276        eager_grouping=False, 
    277    ): 
    278        self.opstring = opstring 
    279        self.precedence = precedence 
    280        self.is_comparison = is_comparison 
    281        self.natural_self_precedent = natural_self_precedent 
    282        self.eager_grouping = eager_grouping 
    283        self.return_type = ( 
    284            return_type._to_instance(return_type) if return_type else None 
    285        ) 
    286 
    287    def __eq__(self, other): 
    288        return isinstance(other, custom_op) and other.opstring == self.opstring 
    289 
    290    def __hash__(self): 
    291        return id(self) 
    292 
    293    def __call__(self, left, right, **kw): 
    294        return left.operate(self, right, **kw) 
    295 
    296 
    297class ColumnOperators(Operators): 
    298    """Defines boolean, comparison, and other operators for 
    299    :class:`_expression.ColumnElement` expressions. 
    300 
    301    By default, all methods call down to 
    302    :meth:`.operate` or :meth:`.reverse_operate`, 
    303    passing in the appropriate operator function from the 
    304    Python builtin ``operator`` module or 
    305    a SQLAlchemy-specific operator function from 
    306    :mod:`sqlalchemy.expression.operators`.   For example 
    307    the ``__eq__`` function:: 
    308 
    309        def __eq__(self, other): 
    310            return self.operate(operators.eq, other) 
    311 
    312    Where ``operators.eq`` is essentially:: 
    313 
    314        def eq(a, b): 
    315            return a == b 
    316 
    317    The core column expression unit :class:`_expression.ColumnElement` 
    318    overrides :meth:`.Operators.operate` and others 
    319    to return further :class:`_expression.ColumnElement` constructs, 
    320    so that the ``==`` operation above is replaced by a clause 
    321    construct. 
    322 
    323    .. seealso:: 
    324 
    325        :ref:`types_operators` 
    326 
    327        :attr:`.TypeEngine.comparator_factory` 
    328 
    329        :class:`.ColumnOperators` 
    330 
    331        :class:`.PropComparator` 
    332 
    333    """ 
    334 
    335    __slots__ = () 
    336 
    337    timetuple = None 
    338    """Hack, allows datetime objects to be compared on the LHS.""" 
    339 
    340    def __lt__(self, other): 
    341        """Implement the ``<`` operator. 
    342 
    343        In a column context, produces the clause ``a < b``. 
    344 
    345        """ 
    346        return self.operate(lt, other) 
    347 
    348    def __le__(self, other): 
    349        """Implement the ``<=`` operator. 
    350 
    351        In a column context, produces the clause ``a <= b``. 
    352 
    353        """ 
    354        return self.operate(le, other) 
    355 
    356    __hash__ = Operators.__hash__ 
    357 
    358    def __eq__(self, other): 
    359        """Implement the ``==`` operator. 
    360 
    361        In a column context, produces the clause ``a = b``. 
    362        If the target is ``None``, produces ``a IS NULL``. 
    363 
    364        """ 
    365        return self.operate(eq, other) 
    366 
    367    def __ne__(self, other): 
    368        """Implement the ``!=`` operator. 
    369 
    370        In a column context, produces the clause ``a != b``. 
    371        If the target is ``None``, produces ``a IS NOT NULL``. 
    372 
    373        """ 
    374        return self.operate(ne, other) 
    375 
    376    def is_distinct_from(self, other): 
    377        """Implement the ``IS DISTINCT FROM`` operator. 
    378 
    379        Renders "a IS DISTINCT FROM b" on most platforms; 
    380        on some such as SQLite may render "a IS NOT b". 
    381 
    382        .. versionadded:: 1.1 
    383 
    384        """ 
    385        return self.operate(is_distinct_from, other) 
    386 
    387    def isnot_distinct_from(self, other): 
    388        """Implement the ``IS NOT DISTINCT FROM`` operator. 
    389 
    390        Renders "a IS NOT DISTINCT FROM b" on most platforms; 
    391        on some such as SQLite may render "a IS b". 
    392 
    393        .. versionadded:: 1.1 
    394 
    395        """ 
    396        return self.operate(isnot_distinct_from, other) 
    397 
    398    def __gt__(self, other): 
    399        """Implement the ``>`` operator. 
    400 
    401        In a column context, produces the clause ``a > b``. 
    402 
    403        """ 
    404        return self.operate(gt, other) 
    405 
    406    def __ge__(self, other): 
    407        """Implement the ``>=`` operator. 
    408 
    409        In a column context, produces the clause ``a >= b``. 
    410 
    411        """ 
    412        return self.operate(ge, other) 
    413 
    414    def __neg__(self): 
    415        """Implement the ``-`` operator. 
    416 
    417        In a column context, produces the clause ``-a``. 
    418 
    419        """ 
    420        return self.operate(neg) 
    421 
    422    def __contains__(self, other): 
    423        return self.operate(contains, other) 
    424 
    425    def __getitem__(self, index): 
    426        """Implement the [] operator. 
    427 
    428        This can be used by some database-specific types 
    429        such as PostgreSQL ARRAY and HSTORE. 
    430 
    431        """ 
    432        return self.operate(getitem, index) 
    433 
    434    def __lshift__(self, other): 
    435        """implement the << operator. 
    436 
    437        Not used by SQLAlchemy core, this is provided 
    438        for custom operator systems which want to use 
    439        << as an extension point. 
    440        """ 
    441        return self.operate(lshift, other) 
    442 
    443    def __rshift__(self, other): 
    444        """implement the >> operator. 
    445 
    446        Not used by SQLAlchemy core, this is provided 
    447        for custom operator systems which want to use 
    448        >> as an extension point. 
    449        """ 
    450        return self.operate(rshift, other) 
    451 
    452    def concat(self, other): 
    453        """Implement the 'concat' operator. 
    454 
    455        In a column context, produces the clause ``a || b``, 
    456        or uses the ``concat()`` operator on MySQL. 
    457 
    458        """ 
    459        return self.operate(concat_op, other) 
    460 
    461    def like(self, other, escape=None): 
    462        r"""Implement the ``like`` operator. 
    463 
    464        In a column context, produces the expression:: 
    465 
    466            a LIKE other 
    467 
    468        E.g.:: 
    469 
    470            stmt = select([sometable]).\ 
    471                where(sometable.c.column.like("%foobar%")) 
    472 
    473        :param other: expression to be compared 
    474        :param escape: optional escape character, renders the ``ESCAPE`` 
    475          keyword, e.g.:: 
    476 
    477            somecolumn.like("foo/%bar", escape="/") 
    478 
    479        .. seealso:: 
    480 
    481            :meth:`.ColumnOperators.ilike` 
    482 
    483        """ 
    484        return self.operate(like_op, other, escape=escape) 
    485 
    486    def ilike(self, other, escape=None): 
    487        r"""Implement the ``ilike`` operator, e.g. case insensitive LIKE. 
    488 
    489        In a column context, produces an expression either of the form:: 
    490 
    491            lower(a) LIKE lower(other) 
    492 
    493        Or on backends that support the ILIKE operator:: 
    494 
    495            a ILIKE other 
    496 
    497        E.g.:: 
    498 
    499            stmt = select([sometable]).\ 
    500                where(sometable.c.column.ilike("%foobar%")) 
    501 
    502        :param other: expression to be compared 
    503        :param escape: optional escape character, renders the ``ESCAPE`` 
    504          keyword, e.g.:: 
    505 
    506            somecolumn.ilike("foo/%bar", escape="/") 
    507 
    508        .. seealso:: 
    509 
    510            :meth:`.ColumnOperators.like` 
    511 
    512        """ 
    513        return self.operate(ilike_op, other, escape=escape) 
    514 
    515    def in_(self, other): 
    516        """Implement the ``in`` operator. 
    517 
    518        In a column context, produces the clause ``column IN <other>``. 
    519 
    520        The given parameter ``other`` may be: 
    521 
    522        * A list of literal values, e.g.:: 
    523 
    524            stmt.where(column.in_([1, 2, 3])) 
    525 
    526          In this calling form, the list of items is converted to a set of 
    527          bound parameters the same length as the list given:: 
    528 
    529            WHERE COL IN (?, ?, ?) 
    530 
    531        * A list of tuples may be provided if the comparison is against a 
    532          :func:`.tuple_` containing multiple expressions:: 
    533 
    534            from sqlalchemy import tuple_ 
    535            stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)])) 
    536 
    537        * An empty list, e.g.:: 
    538 
    539            stmt.where(column.in_([])) 
    540 
    541          In this calling form, the expression renders a "false" expression, 
    542          e.g.:: 
    543 
    544            WHERE 1 != 1 
    545 
    546          This "false" expression has historically had different behaviors 
    547          in older SQLAlchemy versions, see 
    548          :paramref:`_sa.create_engine.empty_in_strategy` 
    549          for behavioral options. 
    550 
    551          .. versionchanged:: 1.2 simplified the behavior of "empty in" 
    552             expressions 
    553 
    554        * A bound parameter, e.g. :func:`.bindparam`, may be used if it 
    555          includes the :paramref:`.bindparam.expanding` flag:: 
    556 
    557            stmt.where(column.in_(bindparam('value', expanding=True))) 
    558 
    559          In this calling form, the expression renders a special non-SQL 
    560          placeholder expression that looks like:: 
    561 
    562            WHERE COL IN ([EXPANDING_value]) 
    563 
    564          This placeholder expression is intercepted at statement execution 
    565          time to be converted into the variable number of bound parameter 
    566          form illustrated earlier.   If the statement were executed as:: 
    567 
    568            connection.execute(stmt, {"value": [1, 2, 3]}) 
    569 
    570          The database would be passed a bound parameter for each value:: 
    571 
    572            WHERE COL IN (?, ?, ?) 
    573 
    574          .. versionadded:: 1.2 added "expanding" bound parameters 
    575 
    576          If an empty list is passed, a special "empty list" expression, 
    577          which is specific to the database in use, is rendered.  On 
    578          SQLite this would be:: 
    579 
    580            WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1) 
    581 
    582          .. versionadded:: 1.3 "expanding" bound parameters now support 
    583             empty lists 
    584 
    585        * a :func:`_expression.select` construct, 
    586          which is usually a correlated 
    587          scalar select:: 
    588 
    589            stmt.where( 
    590                column.in_( 
    591                    select([othertable.c.y]). 
    592                    where(table.c.x == othertable.c.x) 
    593                ) 
    594            ) 
    595 
    596          In this calling form, :meth:`.ColumnOperators.in_` renders as given:: 
    597 
    598            WHERE COL IN (SELECT othertable.y 
    599            FROM othertable WHERE othertable.x = table.x) 
    600 
    601        :param other: a list of literals, a :func:`_expression.select` 
    602         construct, 
    603         or a :func:`.bindparam` construct that includes the 
    604         :paramref:`.bindparam.expanding` flag set to True. 
    605 
    606        """ 
    607        return self.operate(in_op, other) 
    608 
    609    def notin_(self, other): 
    610        """implement the ``NOT IN`` operator. 
    611 
    612        This is equivalent to using negation with 
    613        :meth:`.ColumnOperators.in_`, i.e. ``~x.in_(y)``. 
    614 
    615        In the case that ``other`` is an empty sequence, the compiler 
    616        produces an "empty not in" expression.   This defaults to the 
    617        expression "1 = 1" to produce true in all cases.  The 
    618        :paramref:`_sa.create_engine.empty_in_strategy` may be used to 
    619        alter this behavior. 
    620 
    621        .. versionchanged:: 1.2  The :meth:`.ColumnOperators.in_` and 
    622           :meth:`.ColumnOperators.notin_` operators 
    623           now produce a "static" expression for an empty IN sequence 
    624           by default. 
    625 
    626        .. seealso:: 
    627 
    628            :meth:`.ColumnOperators.in_` 
    629 
    630        """ 
    631        return self.operate(notin_op, other) 
    632 
    633    def notlike(self, other, escape=None): 
    634        """implement the ``NOT LIKE`` operator. 
    635 
    636        This is equivalent to using negation with 
    637        :meth:`.ColumnOperators.like`, i.e. ``~x.like(y)``. 
    638 
    639        .. seealso:: 
    640 
    641            :meth:`.ColumnOperators.like` 
    642 
    643        """ 
    644        return self.operate(notlike_op, other, escape=escape) 
    645 
    646    def notilike(self, other, escape=None): 
    647        """implement the ``NOT ILIKE`` operator. 
    648 
    649        This is equivalent to using negation with 
    650        :meth:`.ColumnOperators.ilike`, i.e. ``~x.ilike(y)``. 
    651 
    652        .. seealso:: 
    653 
    654            :meth:`.ColumnOperators.ilike` 
    655 
    656        """ 
    657        return self.operate(notilike_op, other, escape=escape) 
    658 
    659    def is_(self, other): 
    660        """Implement the ``IS`` operator. 
    661 
    662        Normally, ``IS`` is generated automatically when comparing to a 
    663        value of ``None``, which resolves to ``NULL``.  However, explicit 
    664        usage of ``IS`` may be desirable if comparing to boolean values 
    665        on certain platforms. 
    666 
    667        .. seealso:: :meth:`.ColumnOperators.isnot` 
    668 
    669        """ 
    670        return self.operate(is_, other) 
    671 
    672    def isnot(self, other): 
    673        """Implement the ``IS NOT`` operator. 
    674 
    675        Normally, ``IS NOT`` is generated automatically when comparing to a 
    676        value of ``None``, which resolves to ``NULL``.  However, explicit 
    677        usage of ``IS NOT`` may be desirable if comparing to boolean values 
    678        on certain platforms. 
    679 
    680        .. seealso:: :meth:`.ColumnOperators.is_` 
    681 
    682        """ 
    683        return self.operate(isnot, other) 
    684 
    685    def startswith(self, other, **kwargs): 
    686        r"""Implement the ``startswith`` operator. 
    687 
    688        Produces a LIKE expression that tests against a match for the start 
    689        of a string value:: 
    690 
    691            column LIKE <other> || '%' 
    692 
    693        E.g.:: 
    694 
    695            stmt = select([sometable]).\ 
    696                where(sometable.c.column.startswith("foobar")) 
    697 
    698        Since the operator uses ``LIKE``, wildcard characters 
    699        ``"%"`` and ``"_"`` that are present inside the <other> expression 
    700        will behave like wildcards as well.   For literal string 
    701        values, the :paramref:`.ColumnOperators.startswith.autoescape` flag 
    702        may be set to ``True`` to apply escaping to occurrences of these 
    703        characters within the string value so that they match as themselves 
    704        and not as wildcard characters.  Alternatively, the 
    705        :paramref:`.ColumnOperators.startswith.escape` parameter will establish 
    706        a given character as an escape character which can be of use when 
    707        the target expression is not a literal string. 
    708 
    709        :param other: expression to be compared.   This is usually a plain 
    710          string value, but can also be an arbitrary SQL expression.  LIKE 
    711          wildcard characters ``%`` and ``_`` are not escaped by default unless 
    712          the :paramref:`.ColumnOperators.startswith.autoescape` flag is 
    713          set to True. 
    714 
    715        :param autoescape: boolean; when True, establishes an escape character 
    716          within the LIKE expression, then applies it to all occurrences of 
    717          ``"%"``, ``"_"`` and the escape character itself within the 
    718          comparison value, which is assumed to be a literal string and not a 
    719          SQL expression. 
    720 
    721          An expression such as:: 
    722 
    723            somecolumn.startswith("foo%bar", autoescape=True) 
    724 
    725          Will render as:: 
    726 
    727            somecolumn LIKE :param || '%' ESCAPE '/' 
    728 
    729          With the value of ``:param`` as ``"foo/%bar"``. 
    730 
    731          .. versionadded:: 1.2 
    732 
    733          .. versionchanged:: 1.2.0 The 
    734            :paramref:`.ColumnOperators.startswith.autoescape` parameter is 
    735             now a simple boolean rather than a character; the escape 
    736             character itself is also escaped, and defaults to a forwards 
    737             slash, which itself can be customized using the 
    738             :paramref:`.ColumnOperators.startswith.escape` parameter. 
    739 
    740        :param escape: a character which when given will render with the 
    741          ``ESCAPE`` keyword to establish that character as the escape 
    742          character.  This character can then be placed preceding occurrences 
    743          of ``%`` and ``_`` to allow them to act as themselves and not 
    744          wildcard characters. 
    745 
    746          An expression such as:: 
    747 
    748            somecolumn.startswith("foo/%bar", escape="^") 
    749 
    750          Will render as:: 
    751 
    752            somecolumn LIKE :param || '%' ESCAPE '^' 
    753 
    754          The parameter may also be combined with 
    755          :paramref:`.ColumnOperators.startswith.autoescape`:: 
    756 
    757            somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True) 
    758 
    759          Where above, the given literal parameter will be converted to 
    760          ``"foo^%bar^^bat"`` before being passed to the database. 
    761 
    762        .. seealso:: 
    763 
    764            :meth:`.ColumnOperators.endswith` 
    765 
    766            :meth:`.ColumnOperators.contains` 
    767 
    768            :meth:`.ColumnOperators.like` 
    769 
    770        """ 
    771        return self.operate(startswith_op, other, **kwargs) 
    772 
    773    def endswith(self, other, **kwargs): 
    774        r"""Implement the 'endswith' operator. 
    775 
    776        Produces a LIKE expression that tests against a match for the end 
    777        of a string value:: 
    778 
    779            column LIKE '%' || <other> 
    780 
    781        E.g.:: 
    782 
    783            stmt = select([sometable]).\ 
    784                where(sometable.c.column.endswith("foobar")) 
    785 
    786        Since the operator uses ``LIKE``, wildcard characters 
    787        ``"%"`` and ``"_"`` that are present inside the <other> expression 
    788        will behave like wildcards as well.   For literal string 
    789        values, the :paramref:`.ColumnOperators.endswith.autoescape` flag 
    790        may be set to ``True`` to apply escaping to occurrences of these 
    791        characters within the string value so that they match as themselves 
    792        and not as wildcard characters.  Alternatively, the 
    793        :paramref:`.ColumnOperators.endswith.escape` parameter will establish 
    794        a given character as an escape character which can be of use when 
    795        the target expression is not a literal string. 
    796 
    797        :param other: expression to be compared.   This is usually a plain 
    798          string value, but can also be an arbitrary SQL expression.  LIKE 
    799          wildcard characters ``%`` and ``_`` are not escaped by default unless 
    800          the :paramref:`.ColumnOperators.endswith.autoescape` flag is 
    801          set to True. 
    802 
    803        :param autoescape: boolean; when True, establishes an escape character 
    804          within the LIKE expression, then applies it to all occurrences of 
    805          ``"%"``, ``"_"`` and the escape character itself within the 
    806          comparison value, which is assumed to be a literal string and not a 
    807          SQL expression. 
    808 
    809          An expression such as:: 
    810 
    811            somecolumn.endswith("foo%bar", autoescape=True) 
    812 
    813          Will render as:: 
    814 
    815            somecolumn LIKE '%' || :param ESCAPE '/' 
    816 
    817          With the value of ``:param`` as ``"foo/%bar"``. 
    818 
    819          .. versionadded:: 1.2 
    820 
    821          .. versionchanged:: 1.2.0 The 
    822            :paramref:`.ColumnOperators.endswith.autoescape` parameter is 
    823             now a simple boolean rather than a character; the escape 
    824             character itself is also escaped, and defaults to a forwards 
    825             slash, which itself can be customized using the 
    826             :paramref:`.ColumnOperators.endswith.escape` parameter. 
    827 
    828        :param escape: a character which when given will render with the 
    829          ``ESCAPE`` keyword to establish that character as the escape 
    830          character.  This character can then be placed preceding occurrences 
    831          of ``%`` and ``_`` to allow them to act as themselves and not 
    832          wildcard characters. 
    833 
    834          An expression such as:: 
    835 
    836            somecolumn.endswith("foo/%bar", escape="^") 
    837 
    838          Will render as:: 
    839 
    840            somecolumn LIKE '%' || :param ESCAPE '^' 
    841 
    842          The parameter may also be combined with 
    843          :paramref:`.ColumnOperators.endswith.autoescape`:: 
    844 
    845            somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True) 
    846 
    847          Where above, the given literal parameter will be converted to 
    848          ``"foo^%bar^^bat"`` before being passed to the database. 
    849 
    850        .. seealso:: 
    851 
    852            :meth:`.ColumnOperators.startswith` 
    853 
    854            :meth:`.ColumnOperators.contains` 
    855 
    856            :meth:`.ColumnOperators.like` 
    857 
    858        """ 
    859        return self.operate(endswith_op, other, **kwargs) 
    860 
    861    def contains(self, other, **kwargs): 
    862        r"""Implement the 'contains' operator. 
    863 
    864        Produces a LIKE expression that tests against a match for the middle 
    865        of a string value:: 
    866 
    867            column LIKE '%' || <other> || '%' 
    868 
    869        E.g.:: 
    870 
    871            stmt = select([sometable]).\ 
    872                where(sometable.c.column.contains("foobar")) 
    873 
    874        Since the operator uses ``LIKE``, wildcard characters 
    875        ``"%"`` and ``"_"`` that are present inside the <other> expression 
    876        will behave like wildcards as well.   For literal string 
    877        values, the :paramref:`.ColumnOperators.contains.autoescape` flag 
    878        may be set to ``True`` to apply escaping to occurrences of these 
    879        characters within the string value so that they match as themselves 
    880        and not as wildcard characters.  Alternatively, the 
    881        :paramref:`.ColumnOperators.contains.escape` parameter will establish 
    882        a given character as an escape character which can be of use when 
    883        the target expression is not a literal string. 
    884 
    885        :param other: expression to be compared.   This is usually a plain 
    886          string value, but can also be an arbitrary SQL expression.  LIKE 
    887          wildcard characters ``%`` and ``_`` are not escaped by default unless 
    888          the :paramref:`.ColumnOperators.contains.autoescape` flag is 
    889          set to True. 
    890 
    891        :param autoescape: boolean; when True, establishes an escape character 
    892          within the LIKE expression, then applies it to all occurrences of 
    893          ``"%"``, ``"_"`` and the escape character itself within the 
    894          comparison value, which is assumed to be a literal string and not a 
    895          SQL expression. 
    896 
    897          An expression such as:: 
    898 
    899            somecolumn.contains("foo%bar", autoescape=True) 
    900 
    901          Will render as:: 
    902 
    903            somecolumn LIKE '%' || :param || '%' ESCAPE '/' 
    904 
    905          With the value of ``:param`` as ``"foo/%bar"``. 
    906 
    907          .. versionadded:: 1.2 
    908 
    909          .. versionchanged:: 1.2.0 The 
    910            :paramref:`.ColumnOperators.contains.autoescape` parameter is 
    911             now a simple boolean rather than a character; the escape 
    912             character itself is also escaped, and defaults to a forwards 
    913             slash, which itself can be customized using the 
    914             :paramref:`.ColumnOperators.contains.escape` parameter. 
    915 
    916        :param escape: a character which when given will render with the 
    917          ``ESCAPE`` keyword to establish that character as the escape 
    918          character.  This character can then be placed preceding occurrences 
    919          of ``%`` and ``_`` to allow them to act as themselves and not 
    920          wildcard characters. 
    921 
    922          An expression such as:: 
    923 
    924            somecolumn.contains("foo/%bar", escape="^") 
    925 
    926          Will render as:: 
    927 
    928            somecolumn LIKE '%' || :param || '%' ESCAPE '^' 
    929 
    930          The parameter may also be combined with 
    931          :paramref:`.ColumnOperators.contains.autoescape`:: 
    932 
    933            somecolumn.contains("foo%bar^bat", escape="^", autoescape=True) 
    934 
    935          Where above, the given literal parameter will be converted to 
    936          ``"foo^%bar^^bat"`` before being passed to the database. 
    937 
    938        .. seealso:: 
    939 
    940            :meth:`.ColumnOperators.startswith` 
    941 
    942            :meth:`.ColumnOperators.endswith` 
    943 
    944            :meth:`.ColumnOperators.like` 
    945 
    946 
    947        """ 
    948        return self.operate(contains_op, other, **kwargs) 
    949 
    950    def match(self, other, **kwargs): 
    951        """Implements a database-specific 'match' operator. 
    952 
    953        :meth:`~.ColumnOperators.match` attempts to resolve to 
    954        a MATCH-like function or operator provided by the backend. 
    955        Examples include: 
    956 
    957        * PostgreSQL - renders ``x @@ to_tsquery(y)`` 
    958        * MySQL - renders ``MATCH (x) AGAINST (y IN BOOLEAN MODE)`` 
    959        * Oracle - renders ``CONTAINS(x, y)`` 
    960        * other backends may provide special implementations. 
    961        * Backends without any special implementation will emit 
    962          the operator as "MATCH".  This is compatible with SQLite, for 
    963          example. 
    964 
    965        """ 
    966        return self.operate(match_op, other, **kwargs) 
    967 
    968    def desc(self): 
    969        """Produce a :func:`_expression.desc` clause against the 
    970        parent object.""" 
    971        return self.operate(desc_op) 
    972 
    973    def asc(self): 
    974        """Produce a :func:`_expression.asc` clause against the 
    975        parent object.""" 
    976        return self.operate(asc_op) 
    977 
    978    def nullsfirst(self): 
    979        """Produce a :func:`_expression.nullsfirst` clause against the 
    980        parent object.""" 
    981        return self.operate(nullsfirst_op) 
    982 
    983    def nullslast(self): 
    984        """Produce a :func:`_expression.nullslast` clause against the 
    985        parent object.""" 
    986        return self.operate(nullslast_op) 
    987 
    988    def collate(self, collation): 
    989        """Produce a :func:`_expression.collate` clause against 
    990        the parent object, given the collation string. 
    991 
    992        .. seealso:: 
    993 
    994            :func:`_expression.collate` 
    995 
    996        """ 
    997        return self.operate(collate, collation) 
    998 
    999    def __radd__(self, other): 
    1000        """Implement the ``+`` operator in reverse. 
    1001 
    1002        See :meth:`.ColumnOperators.__add__`. 
    1003 
    1004        """ 
    1005        return self.reverse_operate(add, other) 
    1006 
    1007    def __rsub__(self, other): 
    1008        """Implement the ``-`` operator in reverse. 
    1009 
    1010        See :meth:`.ColumnOperators.__sub__`. 
    1011 
    1012        """ 
    1013        return self.reverse_operate(sub, other) 
    1014 
    1015    def __rmul__(self, other): 
    1016        """Implement the ``*`` operator in reverse. 
    1017 
    1018        See :meth:`.ColumnOperators.__mul__`. 
    1019 
    1020        """ 
    1021        return self.reverse_operate(mul, other) 
    1022 
    1023    def __rdiv__(self, other): 
    1024        """Implement the ``/`` operator in reverse. 
    1025 
    1026        See :meth:`.ColumnOperators.__div__`. 
    1027 
    1028        """ 
    1029        return self.reverse_operate(div, other) 
    1030 
    1031    def __rmod__(self, other): 
    1032        """Implement the ``%`` operator in reverse. 
    1033 
    1034        See :meth:`.ColumnOperators.__mod__`. 
    1035 
    1036        """ 
    1037        return self.reverse_operate(mod, other) 
    1038 
    1039    def between(self, cleft, cright, symmetric=False): 
    1040        """Produce a :func:`_expression.between` clause against 
    1041        the parent object, given the lower and upper range. 
    1042 
    1043        """ 
    1044        return self.operate(between_op, cleft, cright, symmetric=symmetric) 
    1045 
    1046    def distinct(self): 
    1047        """Produce a :func:`_expression.distinct` clause against the 
    1048        parent object. 
    1049 
    1050        """ 
    1051        return self.operate(distinct_op) 
    1052 
    1053    def any_(self): 
    1054        """Produce a :func:`_expression.any_` clause against the 
    1055        parent object. 
    1056 
    1057        This operator is only appropriate against a scalar subquery 
    1058        object, or for some backends an column expression that is 
    1059        against the ARRAY type, e.g.:: 
    1060 
    1061            # postgresql '5 = ANY (somearray)' 
    1062            expr = 5 == mytable.c.somearray.any_() 
    1063 
    1064            # mysql '5 = ANY (SELECT value FROM table)' 
    1065            expr = 5 == select([table.c.value]).as_scalar().any_() 
    1066 
    1067        .. seealso:: 
    1068 
    1069            :func:`_expression.any_` - standalone version 
    1070 
    1071            :func:`_expression.all_` - ALL operator 
    1072 
    1073        .. versionadded:: 1.1 
    1074 
    1075        """ 
    1076        return self.operate(any_op) 
    1077 
    1078    def all_(self): 
    1079        """Produce a :func:`_expression.all_` clause against the 
    1080        parent object. 
    1081 
    1082        This operator is only appropriate against a scalar subquery 
    1083        object, or for some backends an column expression that is 
    1084        against the ARRAY type, e.g.:: 
    1085 
    1086            # postgresql '5 = ALL (somearray)' 
    1087            expr = 5 == mytable.c.somearray.all_() 
    1088 
    1089            # mysql '5 = ALL (SELECT value FROM table)' 
    1090            expr = 5 == select([table.c.value]).as_scalar().all_() 
    1091 
    1092        .. seealso:: 
    1093 
    1094            :func:`_expression.all_` - standalone version 
    1095 
    1096            :func:`_expression.any_` - ANY operator 
    1097 
    1098        .. versionadded:: 1.1 
    1099 
    1100        """ 
    1101        return self.operate(all_op) 
    1102 
    1103    def __add__(self, other): 
    1104        """Implement the ``+`` operator. 
    1105 
    1106        In a column context, produces the clause ``a + b`` 
    1107        if the parent object has non-string affinity. 
    1108        If the parent object has a string affinity, 
    1109        produces the concatenation operator, ``a || b`` - 
    1110        see :meth:`.ColumnOperators.concat`. 
    1111 
    1112        """ 
    1113        return self.operate(add, other) 
    1114 
    1115    def __sub__(self, other): 
    1116        """Implement the ``-`` operator. 
    1117 
    1118        In a column context, produces the clause ``a - b``. 
    1119 
    1120        """ 
    1121        return self.operate(sub, other) 
    1122 
    1123    def __mul__(self, other): 
    1124        """Implement the ``*`` operator. 
    1125 
    1126        In a column context, produces the clause ``a * b``. 
    1127 
    1128        """ 
    1129        return self.operate(mul, other) 
    1130 
    1131    def __div__(self, other): 
    1132        """Implement the ``/`` operator. 
    1133 
    1134        In a column context, produces the clause ``a / b``. 
    1135 
    1136        """ 
    1137        return self.operate(div, other) 
    1138 
    1139    def __mod__(self, other): 
    1140        """Implement the ``%`` operator. 
    1141 
    1142        In a column context, produces the clause ``a % b``. 
    1143 
    1144        """ 
    1145        return self.operate(mod, other) 
    1146 
    1147    def __truediv__(self, other): 
    1148        """Implement the ``//`` operator. 
    1149 
    1150        In a column context, produces the clause ``a / b``. 
    1151 
    1152        """ 
    1153        return self.operate(truediv, other) 
    1154 
    1155    def __rtruediv__(self, other): 
    1156        """Implement the ``//`` operator in reverse. 
    1157 
    1158        See :meth:`.ColumnOperators.__truediv__`. 
    1159 
    1160        """ 
    1161        return self.reverse_operate(truediv, other) 
    1162 
    1163 
    1164_commutative = {eq, ne, add, mul} 
    1165_comparison = {eq, ne, lt, gt, ge, le} 
    1166 
    1167 
    1168def commutative_op(fn): 
    1169    _commutative.add(fn) 
    1170    return fn 
    1171 
    1172 
    1173def comparison_op(fn): 
    1174    _comparison.add(fn) 
    1175    return fn 
    1176 
    1177 
    1178def from_(): 
    1179    raise NotImplementedError() 
    1180 
    1181 
    1182@comparison_op 
    1183def function_as_comparison_op(): 
    1184    raise NotImplementedError() 
    1185 
    1186 
    1187def as_(): 
    1188    raise NotImplementedError() 
    1189 
    1190 
    1191def exists(): 
    1192    raise NotImplementedError() 
    1193 
    1194 
    1195def istrue(a): 
    1196    raise NotImplementedError() 
    1197 
    1198 
    1199def isfalse(a): 
    1200    raise NotImplementedError() 
    1201 
    1202 
    1203@comparison_op 
    1204def is_distinct_from(a, b): 
    1205    return a.is_distinct_from(b) 
    1206 
    1207 
    1208@comparison_op 
    1209def isnot_distinct_from(a, b): 
    1210    return a.isnot_distinct_from(b) 
    1211 
    1212 
    1213@comparison_op 
    1214def is_(a, b): 
    1215    return a.is_(b) 
    1216 
    1217 
    1218@comparison_op 
    1219def isnot(a, b): 
    1220    return a.isnot(b) 
    1221 
    1222 
    1223def collate(a, b): 
    1224    return a.collate(b) 
    1225 
    1226 
    1227def op(a, opstring, b): 
    1228    return a.op(opstring)(b) 
    1229 
    1230 
    1231@comparison_op 
    1232def like_op(a, b, escape=None): 
    1233    return a.like(b, escape=escape) 
    1234 
    1235 
    1236@comparison_op 
    1237def notlike_op(a, b, escape=None): 
    1238    return a.notlike(b, escape=escape) 
    1239 
    1240 
    1241@comparison_op 
    1242def ilike_op(a, b, escape=None): 
    1243    return a.ilike(b, escape=escape) 
    1244 
    1245 
    1246@comparison_op 
    1247def notilike_op(a, b, escape=None): 
    1248    return a.notilike(b, escape=escape) 
    1249 
    1250 
    1251@comparison_op 
    1252def between_op(a, b, c, symmetric=False): 
    1253    return a.between(b, c, symmetric=symmetric) 
    1254 
    1255 
    1256@comparison_op 
    1257def notbetween_op(a, b, c, symmetric=False): 
    1258    return a.notbetween(b, c, symmetric=symmetric) 
    1259 
    1260 
    1261@comparison_op 
    1262def in_op(a, b): 
    1263    return a.in_(b) 
    1264 
    1265 
    1266@comparison_op 
    1267def notin_op(a, b): 
    1268    return a.notin_(b) 
    1269 
    1270 
    1271def distinct_op(a): 
    1272    return a.distinct() 
    1273 
    1274 
    1275def any_op(a): 
    1276    return a.any_() 
    1277 
    1278 
    1279def all_op(a): 
    1280    return a.all_() 
    1281 
    1282 
    1283def _escaped_like_impl(fn, other, escape, autoescape): 
    1284    if autoescape: 
    1285        if autoescape is not True: 
    1286            util.warn( 
    1287                "The autoescape parameter is now a simple boolean True/False" 
    1288            ) 
    1289        if escape is None: 
    1290            escape = "/" 
    1291 
    1292        if not isinstance(other, util.compat.string_types): 
    1293            raise TypeError("String value expected when autoescape=True") 
    1294 
    1295        if escape not in ("%", "_"): 
    1296            other = other.replace(escape, escape + escape) 
    1297 
    1298        other = other.replace("%", escape + "%").replace("_", escape + "_") 
    1299 
    1300    return fn(other, escape=escape) 
    1301 
    1302 
    1303@comparison_op 
    1304def startswith_op(a, b, escape=None, autoescape=False): 
    1305    return _escaped_like_impl(a.startswith, b, escape, autoescape) 
    1306 
    1307 
    1308@comparison_op 
    1309def notstartswith_op(a, b, escape=None, autoescape=False): 
    1310    return ~_escaped_like_impl(a.startswith, b, escape, autoescape) 
    1311 
    1312 
    1313@comparison_op 
    1314def endswith_op(a, b, escape=None, autoescape=False): 
    1315    return _escaped_like_impl(a.endswith, b, escape, autoescape) 
    1316 
    1317 
    1318@comparison_op 
    1319def notendswith_op(a, b, escape=None, autoescape=False): 
    1320    return ~_escaped_like_impl(a.endswith, b, escape, autoescape) 
    1321 
    1322 
    1323@comparison_op 
    1324def contains_op(a, b, escape=None, autoescape=False): 
    1325    return _escaped_like_impl(a.contains, b, escape, autoescape) 
    1326 
    1327 
    1328@comparison_op 
    1329def notcontains_op(a, b, escape=None, autoescape=False): 
    1330    return ~_escaped_like_impl(a.contains, b, escape, autoescape) 
    1331 
    1332 
    1333@comparison_op 
    1334def match_op(a, b, **kw): 
    1335    return a.match(b, **kw) 
    1336 
    1337 
    1338@comparison_op 
    1339def notmatch_op(a, b, **kw): 
    1340    return a.notmatch(b, **kw) 
    1341 
    1342 
    1343def comma_op(a, b): 
    1344    raise NotImplementedError() 
    1345 
    1346 
    1347@comparison_op 
    1348def empty_in_op(a, b): 
    1349    raise NotImplementedError() 
    1350 
    1351 
    1352@comparison_op 
    1353def empty_notin_op(a, b): 
    1354    raise NotImplementedError() 
    1355 
    1356 
    1357def filter_op(a, b): 
    1358    raise NotImplementedError() 
    1359 
    1360 
    1361def concat_op(a, b): 
    1362    return a.concat(b) 
    1363 
    1364 
    1365def desc_op(a): 
    1366    return a.desc() 
    1367 
    1368 
    1369def asc_op(a): 
    1370    return a.asc() 
    1371 
    1372 
    1373def nullsfirst_op(a): 
    1374    return a.nullsfirst() 
    1375 
    1376 
    1377def nullslast_op(a): 
    1378    return a.nullslast() 
    1379 
    1380 
    1381def json_getitem_op(a, b): 
    1382    raise NotImplementedError() 
    1383 
    1384 
    1385def json_path_getitem_op(a, b): 
    1386    raise NotImplementedError() 
    1387 
    1388 
    1389def is_comparison(op): 
    1390    return op in _comparison or isinstance(op, custom_op) and op.is_comparison 
    1391 
    1392 
    1393def is_commutative(op): 
    1394    return op in _commutative 
    1395 
    1396 
    1397def is_ordering_modifier(op): 
    1398    return op in (asc_op, desc_op, nullsfirst_op, nullslast_op) 
    1399 
    1400 
    1401def is_natural_self_precedent(op): 
    1402    return ( 
    1403        op in _natural_self_precedent 
    1404        or isinstance(op, custom_op) 
    1405        and op.natural_self_precedent 
    1406    ) 
    1407 
    1408 
    1409_booleans = (inv, istrue, isfalse, and_, or_) 
    1410 
    1411 
    1412def is_boolean(op): 
    1413    return is_comparison(op) or op in _booleans 
    1414 
    1415 
    1416_mirror = {gt: lt, ge: le, lt: gt, le: ge} 
    1417 
    1418 
    1419def mirror(op): 
    1420    """rotate a comparison operator 180 degrees. 
    1421 
    1422    Note this is not the same as negation. 
    1423 
    1424    """ 
    1425    return _mirror.get(op, op) 
    1426 
    1427 
    1428_associative = _commutative.union([concat_op, and_, or_]).difference([eq, ne]) 
    1429 
    1430_natural_self_precedent = _associative.union( 
    1431    [getitem, json_getitem_op, json_path_getitem_op] 
    1432) 
    1433"""Operators where if we have (a op b) op c, we don't want to 
    1434parenthesize (a op b). 
    1435 
    1436""" 
    1437 
    1438 
    1439_asbool = util.symbol("_asbool", canonical=-10) 
    1440_smallest = util.symbol("_smallest", canonical=-100) 
    1441_largest = util.symbol("_largest", canonical=100) 
    1442 
    1443_PRECEDENCE = { 
    1444    from_: 15, 
    1445    function_as_comparison_op: 15, 
    1446    any_op: 15, 
    1447    all_op: 15, 
    1448    getitem: 15, 
    1449    json_getitem_op: 15, 
    1450    json_path_getitem_op: 15, 
    1451    mul: 8, 
    1452    truediv: 8, 
    1453    div: 8, 
    1454    mod: 8, 
    1455    neg: 8, 
    1456    add: 7, 
    1457    sub: 7, 
    1458    concat_op: 6, 
    1459    filter_op: 6, 
    1460    match_op: 5, 
    1461    notmatch_op: 5, 
    1462    ilike_op: 5, 
    1463    notilike_op: 5, 
    1464    like_op: 5, 
    1465    notlike_op: 5, 
    1466    in_op: 5, 
    1467    notin_op: 5, 
    1468    is_: 5, 
    1469    isnot: 5, 
    1470    eq: 5, 
    1471    ne: 5, 
    1472    is_distinct_from: 5, 
    1473    isnot_distinct_from: 5, 
    1474    empty_in_op: 5, 
    1475    empty_notin_op: 5, 
    1476    gt: 5, 
    1477    lt: 5, 
    1478    ge: 5, 
    1479    le: 5, 
    1480    between_op: 5, 
    1481    notbetween_op: 5, 
    1482    distinct_op: 5, 
    1483    inv: 5, 
    1484    istrue: 5, 
    1485    isfalse: 5, 
    1486    and_: 3, 
    1487    or_: 2, 
    1488    comma_op: -1, 
    1489    desc_op: 3, 
    1490    asc_op: 3, 
    1491    collate: 4, 
    1492    as_: -1, 
    1493    exists: 0, 
    1494    _asbool: -10, 
    1495    _smallest: _smallest, 
    1496    _largest: _largest, 
    1497} 
    1498 
    1499 
    1500def is_precedent(operator, against): 
    1501    if operator is against and is_natural_self_precedent(operator): 
    1502        return False 
    1503    else: 
    1504        return _PRECEDENCE.get( 
    1505            operator, getattr(operator, "precedence", _smallest) 
    1506        ) <= _PRECEDENCE.get(against, getattr(against, "precedence", _largest))