1# sql/operators.py
2# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
7
8# 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 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 which the database is expected to apply
149 to the operator in SQL expressions. This integer value acts as a hint
150 for the SQL compiler to know when explicit parenthesis should be
151 rendered around a particular operation. A lower number will cause the
152 expression to be parenthesized when applied against another operator
153 with higher precedence. The default value of ``0`` is lower than all
154 operators except for the comma (``,``) and ``AS`` operators. A value
155 of 100 will be higher or equal to all operators, and -100 will be
156 lower than or equal to all operators.
157
158 .. seealso::
159
160 :ref:`faq_sql_expression_op_parenthesis` - detailed description
161 of how the SQLAlchemy SQL compiler renders parenthesis
162
163 :param is_comparison: legacy; if True, the operator will be considered
164 as a "comparison" operator, that is which evaluates to a boolean
165 true/false value, like ``==``, ``>``, etc. This flag is provided
166 so that ORM relationships can establish that the operator is a
167 comparison operator when used in a custom join condition.
168
169 Using the ``is_comparison`` parameter is superseded by using the
170 :meth:`.Operators.bool_op` method instead; this more succinct
171 operator sets this parameter automatically. In SQLAlchemy 2.0 it
172 will also provide for improved typing support.
173
174 :param return_type: a :class:`.TypeEngine` class or object that will
175 force the return type of an expression produced by this operator
176 to be of that type. By default, operators that specify
177 :paramref:`.Operators.op.is_comparison` will resolve to
178 :class:`.Boolean`, and those that do not will be of the same
179 type as the left-hand operand.
180
181 .. seealso::
182
183 :meth:`.Operators.bool_op`
184
185 :ref:`types_operators`
186
187 :ref:`relationship_custom_operator`
188
189 """
190 operator = custom_op(opstring, precedence, is_comparison, return_type)
191
192 def against(other):
193 return operator(self, other)
194
195 return against
196
197 def bool_op(self, opstring, precedence=0):
198 """Return a custom boolean operator.
199
200 This method is shorthand for calling
201 :meth:`.Operators.op` and passing the
202 :paramref:`.Operators.op.is_comparison`
203 flag with True. A key advantage to using :meth:`.Operators.bool_op`
204 is that when using column constructs, the "boolean" nature of the
205 returned expression will be present for :pep:`484` purposes.
206
207 .. seealso::
208
209 :meth:`.Operators.op`
210
211 """
212 return self.op(opstring, precedence=precedence, is_comparison=True)
213
214 def operate(self, op, *other, **kwargs):
215 r"""Operate on an argument.
216
217 This is the lowest level of operation, raises
218 :class:`NotImplementedError` by default.
219
220 Overriding this on a subclass can allow common
221 behavior to be applied to all operations.
222 For example, overriding :class:`.ColumnOperators`
223 to apply ``func.lower()`` to the left and right
224 side::
225
226 class MyComparator(ColumnOperators):
227 def operate(self, op, other, **kwargs):
228 return op(func.lower(self), func.lower(other), **kwargs)
229
230 :param op: Operator callable.
231 :param \*other: the 'other' side of the operation. Will
232 be a single scalar for most operations.
233 :param \**kwargs: modifiers. These may be passed by special
234 operators such as :meth:`ColumnOperators.contains`.
235
236
237 """
238 raise NotImplementedError(str(op))
239
240 def reverse_operate(self, op, other, **kwargs):
241 """Reverse operate on an argument.
242
243 Usage is the same as :meth:`operate`.
244
245 """
246 raise NotImplementedError(str(op))
247
248
249class custom_op(object):
250 """Represent a 'custom' operator.
251
252 :class:`.custom_op` is normally instantiated when the
253 :meth:`.Operators.op` or :meth:`.Operators.bool_op` methods
254 are used to create a custom operator callable. The class can also be
255 used directly when programmatically constructing expressions. E.g.
256 to represent the "factorial" operation::
257
258 from sqlalchemy.sql import UnaryExpression
259 from sqlalchemy.sql import operators
260 from sqlalchemy import Numeric
261
262 unary = UnaryExpression(table.c.somecolumn,
263 modifier=operators.custom_op("!"),
264 type_=Numeric)
265
266
267 .. seealso::
268
269 :meth:`.Operators.op`
270
271 :meth:`.Operators.bool_op`
272
273 """
274
275 __name__ = "custom_op"
276
277 def __init__(
278 self,
279 opstring,
280 precedence=0,
281 is_comparison=False,
282 return_type=None,
283 natural_self_precedent=False,
284 eager_grouping=False,
285 ):
286 self.opstring = opstring
287 self.precedence = precedence
288 self.is_comparison = is_comparison
289 self.natural_self_precedent = natural_self_precedent
290 self.eager_grouping = eager_grouping
291 self.return_type = (
292 return_type._to_instance(return_type) if return_type else None
293 )
294
295 def __eq__(self, other):
296 return (
297 isinstance(other, custom_op)
298 and other._hash_key() == self._hash_key()
299 )
300
301 def __hash__(self):
302 return hash(self._hash_key())
303
304 def _hash_key(self):
305 return (
306 self.__class__,
307 self.opstring,
308 self.precedence,
309 self.is_comparison,
310 self.natural_self_precedent,
311 self.eager_grouping,
312 self.return_type._static_cache_key if self.return_type else None,
313 )
314
315 def __call__(self, left, right, **kw):
316 return left.operate(self, right, **kw)
317
318
319class ColumnOperators(Operators):
320 """Defines boolean, comparison, and other operators for
321 :class:`_expression.ColumnElement` expressions.
322
323 By default, all methods call down to
324 :meth:`.operate` or :meth:`.reverse_operate`,
325 passing in the appropriate operator function from the
326 Python builtin ``operator`` module or
327 a SQLAlchemy-specific operator function from
328 :mod:`sqlalchemy.expression.operators`. For example
329 the ``__eq__`` function::
330
331 def __eq__(self, other):
332 return self.operate(operators.eq, other)
333
334 Where ``operators.eq`` is essentially::
335
336 def eq(a, b):
337 return a == b
338
339 The core column expression unit :class:`_expression.ColumnElement`
340 overrides :meth:`.Operators.operate` and others
341 to return further :class:`_expression.ColumnElement` constructs,
342 so that the ``==`` operation above is replaced by a clause
343 construct.
344
345 .. seealso::
346
347 :ref:`types_operators`
348
349 :attr:`.TypeEngine.comparator_factory`
350
351 :class:`.ColumnOperators`
352
353 :class:`.PropComparator`
354
355 """
356
357 __slots__ = ()
358
359 timetuple = None
360 """Hack, allows datetime objects to be compared on the LHS."""
361
362 def __lt__(self, other):
363 """Implement the ``<`` operator.
364
365 In a column context, produces the clause ``a < b``.
366
367 """
368 return self.operate(lt, other)
369
370 def __le__(self, other):
371 """Implement the ``<=`` operator.
372
373 In a column context, produces the clause ``a <= b``.
374
375 """
376 return self.operate(le, other)
377
378 __hash__ = Operators.__hash__
379
380 def __eq__(self, other):
381 """Implement the ``==`` operator.
382
383 In a column context, produces the clause ``a = b``.
384 If the target is ``None``, produces ``a IS NULL``.
385
386 """
387 return self.operate(eq, other)
388
389 def __ne__(self, other):
390 """Implement the ``!=`` operator.
391
392 In a column context, produces the clause ``a != b``.
393 If the target is ``None``, produces ``a IS NOT NULL``.
394
395 """
396 return self.operate(ne, other)
397
398 def is_distinct_from(self, other):
399 """Implement the ``IS DISTINCT FROM`` operator.
400
401 Renders "a IS DISTINCT FROM b" on most platforms;
402 on some such as SQLite may render "a IS NOT b".
403
404 .. versionadded:: 1.1
405
406 """
407 return self.operate(is_distinct_from, other)
408
409 def is_not_distinct_from(self, other):
410 """Implement the ``IS NOT DISTINCT FROM`` operator.
411
412 Renders "a IS NOT DISTINCT FROM b" on most platforms;
413 on some such as SQLite may render "a IS b".
414
415 .. versionchanged:: 1.4 The ``is_not_distinct_from()`` operator is
416 renamed from ``isnot_distinct_from()`` in previous releases.
417 The previous name remains available for backwards compatibility.
418
419 .. versionadded:: 1.1
420
421 """
422 return self.operate(is_not_distinct_from, other)
423
424 # deprecated 1.4; see #5435
425 isnot_distinct_from = is_not_distinct_from
426
427 def __gt__(self, other):
428 """Implement the ``>`` operator.
429
430 In a column context, produces the clause ``a > b``.
431
432 """
433 return self.operate(gt, other)
434
435 def __ge__(self, other):
436 """Implement the ``>=`` operator.
437
438 In a column context, produces the clause ``a >= b``.
439
440 """
441 return self.operate(ge, other)
442
443 def __neg__(self):
444 """Implement the ``-`` operator.
445
446 In a column context, produces the clause ``-a``.
447
448 """
449 return self.operate(neg)
450
451 def __contains__(self, other):
452 return self.operate(contains, other)
453
454 def __getitem__(self, index):
455 """Implement the [] operator.
456
457 This can be used by some database-specific types
458 such as PostgreSQL ARRAY and HSTORE.
459
460 """
461 return self.operate(getitem, index)
462
463 def __lshift__(self, other):
464 """implement the << operator.
465
466 Not used by SQLAlchemy core, this is provided
467 for custom operator systems which want to use
468 << as an extension point.
469 """
470 return self.operate(lshift, other)
471
472 def __rshift__(self, other):
473 """implement the >> operator.
474
475 Not used by SQLAlchemy core, this is provided
476 for custom operator systems which want to use
477 >> as an extension point.
478 """
479 return self.operate(rshift, other)
480
481 def concat(self, other):
482 """Implement the 'concat' operator.
483
484 In a column context, produces the clause ``a || b``,
485 or uses the ``concat()`` operator on MySQL.
486
487 """
488 return self.operate(concat_op, other)
489
490 def _rconcat(self, other):
491 """Implement an 'rconcat' operator.
492
493 this is for internal use at the moment
494
495 .. versionadded:: 1.4.40
496
497 """
498 return self.reverse_operate(concat_op, other)
499
500 def like(self, other, escape=None):
501 r"""Implement the ``like`` operator.
502
503 In a column context, produces the expression::
504
505 a LIKE other
506
507 E.g.::
508
509 stmt = select(sometable).\
510 where(sometable.c.column.like("%foobar%"))
511
512 :param other: expression to be compared
513 :param escape: optional escape character, renders the ``ESCAPE``
514 keyword, e.g.::
515
516 somecolumn.like("foo/%bar", escape="/")
517
518 .. seealso::
519
520 :meth:`.ColumnOperators.ilike`
521
522 """
523 return self.operate(like_op, other, escape=escape)
524
525 def ilike(self, other, escape=None):
526 r"""Implement the ``ilike`` operator, e.g. case insensitive LIKE.
527
528 In a column context, produces an expression either of the form::
529
530 lower(a) LIKE lower(other)
531
532 Or on backends that support the ILIKE operator::
533
534 a ILIKE other
535
536 E.g.::
537
538 stmt = select(sometable).\
539 where(sometable.c.column.ilike("%foobar%"))
540
541 :param other: expression to be compared
542 :param escape: optional escape character, renders the ``ESCAPE``
543 keyword, e.g.::
544
545 somecolumn.ilike("foo/%bar", escape="/")
546
547 .. seealso::
548
549 :meth:`.ColumnOperators.like`
550
551 """
552 return self.operate(ilike_op, other, escape=escape)
553
554 def in_(self, other):
555 """Implement the ``in`` operator.
556
557 In a column context, produces the clause ``column IN <other>``.
558
559 The given parameter ``other`` may be:
560
561 * A list of literal values, e.g.::
562
563 stmt.where(column.in_([1, 2, 3]))
564
565 In this calling form, the list of items is converted to a set of
566 bound parameters the same length as the list given::
567
568 WHERE COL IN (?, ?, ?)
569
570 * A list of tuples may be provided if the comparison is against a
571 :func:`.tuple_` containing multiple expressions::
572
573 from sqlalchemy import tuple_
574 stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)]))
575
576 * An empty list, e.g.::
577
578 stmt.where(column.in_([]))
579
580 In this calling form, the expression renders an "empty set"
581 expression. These expressions are tailored to individual backends
582 and are generally trying to get an empty SELECT statement as a
583 subquery. Such as on SQLite, the expression is::
584
585 WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)
586
587 .. versionchanged:: 1.4 empty IN expressions now use an
588 execution-time generated SELECT subquery in all cases.
589
590 * A bound parameter, e.g. :func:`.bindparam`, may be used if it
591 includes the :paramref:`.bindparam.expanding` flag::
592
593 stmt.where(column.in_(bindparam('value', expanding=True)))
594
595 In this calling form, the expression renders a special non-SQL
596 placeholder expression that looks like::
597
598 WHERE COL IN ([EXPANDING_value])
599
600 This placeholder expression is intercepted at statement execution
601 time to be converted into the variable number of bound parameter
602 form illustrated earlier. If the statement were executed as::
603
604 connection.execute(stmt, {"value": [1, 2, 3]})
605
606 The database would be passed a bound parameter for each value::
607
608 WHERE COL IN (?, ?, ?)
609
610 .. versionadded:: 1.2 added "expanding" bound parameters
611
612 If an empty list is passed, a special "empty list" expression,
613 which is specific to the database in use, is rendered. On
614 SQLite this would be::
615
616 WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)
617
618 .. versionadded:: 1.3 "expanding" bound parameters now support
619 empty lists
620
621 * a :func:`_expression.select` construct, which is usually a
622 correlated scalar select::
623
624 stmt.where(
625 column.in_(
626 select(othertable.c.y).
627 where(table.c.x == othertable.c.x)
628 )
629 )
630
631 In this calling form, :meth:`.ColumnOperators.in_` renders as given::
632
633 WHERE COL IN (SELECT othertable.y
634 FROM othertable WHERE othertable.x = table.x)
635
636 :param other: a list of literals, a :func:`_expression.select`
637 construct, or a :func:`.bindparam` construct that includes the
638 :paramref:`.bindparam.expanding` flag set to True.
639
640 """
641 return self.operate(in_op, other)
642
643 def not_in(self, other):
644 """implement the ``NOT IN`` operator.
645
646 This is equivalent to using negation with
647 :meth:`.ColumnOperators.in_`, i.e. ``~x.in_(y)``.
648
649 In the case that ``other`` is an empty sequence, the compiler
650 produces an "empty not in" expression. This defaults to the
651 expression "1 = 1" to produce true in all cases. The
652 :paramref:`_sa.create_engine.empty_in_strategy` may be used to
653 alter this behavior.
654
655 .. versionchanged:: 1.4 The ``not_in()`` operator is renamed from
656 ``notin_()`` in previous releases. The previous name remains
657 available for backwards compatibility.
658
659 .. versionchanged:: 1.2 The :meth:`.ColumnOperators.in_` and
660 :meth:`.ColumnOperators.not_in` operators
661 now produce a "static" expression for an empty IN sequence
662 by default.
663
664 .. seealso::
665
666 :meth:`.ColumnOperators.in_`
667
668 """
669 return self.operate(not_in_op, other)
670
671 # deprecated 1.4; see #5429
672 notin_ = not_in
673
674 def not_like(self, other, escape=None):
675 """implement the ``NOT LIKE`` operator.
676
677 This is equivalent to using negation with
678 :meth:`.ColumnOperators.like`, i.e. ``~x.like(y)``.
679
680 .. versionchanged:: 1.4 The ``not_like()`` operator is renamed from
681 ``notlike()`` in previous releases. The previous name remains
682 available for backwards compatibility.
683
684 .. seealso::
685
686 :meth:`.ColumnOperators.like`
687
688 """
689 return self.operate(notlike_op, other, escape=escape)
690
691 # deprecated 1.4; see #5435
692 notlike = not_like
693
694 def not_ilike(self, other, escape=None):
695 """implement the ``NOT ILIKE`` operator.
696
697 This is equivalent to using negation with
698 :meth:`.ColumnOperators.ilike`, i.e. ``~x.ilike(y)``.
699
700 .. versionchanged:: 1.4 The ``not_ilike()`` operator is renamed from
701 ``notilike()`` in previous releases. The previous name remains
702 available for backwards compatibility.
703
704 .. seealso::
705
706 :meth:`.ColumnOperators.ilike`
707
708 """
709 return self.operate(notilike_op, other, escape=escape)
710
711 # deprecated 1.4; see #5435
712 notilike = not_ilike
713
714 def is_(self, other):
715 """Implement the ``IS`` operator.
716
717 Normally, ``IS`` is generated automatically when comparing to a
718 value of ``None``, which resolves to ``NULL``. However, explicit
719 usage of ``IS`` may be desirable if comparing to boolean values
720 on certain platforms.
721
722 .. seealso:: :meth:`.ColumnOperators.is_not`
723
724 """
725 return self.operate(is_, other)
726
727 def is_not(self, other):
728 """Implement the ``IS NOT`` operator.
729
730 Normally, ``IS NOT`` is generated automatically when comparing to a
731 value of ``None``, which resolves to ``NULL``. However, explicit
732 usage of ``IS NOT`` may be desirable if comparing to boolean values
733 on certain platforms.
734
735 .. versionchanged:: 1.4 The ``is_not()`` operator is renamed from
736 ``isnot()`` in previous releases. The previous name remains
737 available for backwards compatibility.
738
739 .. seealso:: :meth:`.ColumnOperators.is_`
740
741 """
742 return self.operate(is_not, other)
743
744 # deprecated 1.4; see #5429
745 isnot = is_not
746
747 def startswith(self, other, **kwargs):
748 r"""Implement the ``startswith`` operator.
749
750 Produces a LIKE expression that tests against a match for the start
751 of a string value::
752
753 column LIKE <other> || '%'
754
755 E.g.::
756
757 stmt = select(sometable).\
758 where(sometable.c.column.startswith("foobar"))
759
760 Since the operator uses ``LIKE``, wildcard characters
761 ``"%"`` and ``"_"`` that are present inside the <other> expression
762 will behave like wildcards as well. For literal string
763 values, the :paramref:`.ColumnOperators.startswith.autoescape` flag
764 may be set to ``True`` to apply escaping to occurrences of these
765 characters within the string value so that they match as themselves
766 and not as wildcard characters. Alternatively, the
767 :paramref:`.ColumnOperators.startswith.escape` parameter will establish
768 a given character as an escape character which can be of use when
769 the target expression is not a literal string.
770
771 :param other: expression to be compared. This is usually a plain
772 string value, but can also be an arbitrary SQL expression. LIKE
773 wildcard characters ``%`` and ``_`` are not escaped by default unless
774 the :paramref:`.ColumnOperators.startswith.autoescape` flag is
775 set to True.
776
777 :param autoescape: boolean; when True, establishes an escape character
778 within the LIKE expression, then applies it to all occurrences of
779 ``"%"``, ``"_"`` and the escape character itself within the
780 comparison value, which is assumed to be a literal string and not a
781 SQL expression.
782
783 An expression such as::
784
785 somecolumn.startswith("foo%bar", autoescape=True)
786
787 Will render as::
788
789 somecolumn LIKE :param || '%' ESCAPE '/'
790
791 With the value of ``:param`` as ``"foo/%bar"``.
792
793 :param escape: a character which when given will render with the
794 ``ESCAPE`` keyword to establish that character as the escape
795 character. This character can then be placed preceding occurrences
796 of ``%`` and ``_`` to allow them to act as themselves and not
797 wildcard characters.
798
799 An expression such as::
800
801 somecolumn.startswith("foo/%bar", escape="^")
802
803 Will render as::
804
805 somecolumn LIKE :param || '%' ESCAPE '^'
806
807 The parameter may also be combined with
808 :paramref:`.ColumnOperators.startswith.autoescape`::
809
810 somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True)
811
812 Where above, the given literal parameter will be converted to
813 ``"foo^%bar^^bat"`` before being passed to the database.
814
815 .. seealso::
816
817 :meth:`.ColumnOperators.endswith`
818
819 :meth:`.ColumnOperators.contains`
820
821 :meth:`.ColumnOperators.like`
822
823 """
824 return self.operate(startswith_op, other, **kwargs)
825
826 def endswith(self, other, **kwargs):
827 r"""Implement the 'endswith' operator.
828
829 Produces a LIKE expression that tests against a match for the end
830 of a string value::
831
832 column LIKE '%' || <other>
833
834 E.g.::
835
836 stmt = select(sometable).\
837 where(sometable.c.column.endswith("foobar"))
838
839 Since the operator uses ``LIKE``, wildcard characters
840 ``"%"`` and ``"_"`` that are present inside the <other> expression
841 will behave like wildcards as well. For literal string
842 values, the :paramref:`.ColumnOperators.endswith.autoescape` flag
843 may be set to ``True`` to apply escaping to occurrences of these
844 characters within the string value so that they match as themselves
845 and not as wildcard characters. Alternatively, the
846 :paramref:`.ColumnOperators.endswith.escape` parameter will establish
847 a given character as an escape character which can be of use when
848 the target expression is not a literal string.
849
850 :param other: expression to be compared. This is usually a plain
851 string value, but can also be an arbitrary SQL expression. LIKE
852 wildcard characters ``%`` and ``_`` are not escaped by default unless
853 the :paramref:`.ColumnOperators.endswith.autoescape` flag is
854 set to True.
855
856 :param autoescape: boolean; when True, establishes an escape character
857 within the LIKE expression, then applies it to all occurrences of
858 ``"%"``, ``"_"`` and the escape character itself within the
859 comparison value, which is assumed to be a literal string and not a
860 SQL expression.
861
862 An expression such as::
863
864 somecolumn.endswith("foo%bar", autoescape=True)
865
866 Will render as::
867
868 somecolumn LIKE '%' || :param ESCAPE '/'
869
870 With the value of ``:param`` as ``"foo/%bar"``.
871
872 :param escape: a character which when given will render with the
873 ``ESCAPE`` keyword to establish that character as the escape
874 character. This character can then be placed preceding occurrences
875 of ``%`` and ``_`` to allow them to act as themselves and not
876 wildcard characters.
877
878 An expression such as::
879
880 somecolumn.endswith("foo/%bar", escape="^")
881
882 Will render as::
883
884 somecolumn LIKE '%' || :param ESCAPE '^'
885
886 The parameter may also be combined with
887 :paramref:`.ColumnOperators.endswith.autoescape`::
888
889 somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)
890
891 Where above, the given literal parameter will be converted to
892 ``"foo^%bar^^bat"`` before being passed to the database.
893
894 .. seealso::
895
896 :meth:`.ColumnOperators.startswith`
897
898 :meth:`.ColumnOperators.contains`
899
900 :meth:`.ColumnOperators.like`
901
902 """
903 return self.operate(endswith_op, other, **kwargs)
904
905 def contains(self, other, **kwargs):
906 r"""Implement the 'contains' operator.
907
908 Produces a LIKE expression that tests against a match for the middle
909 of a string value::
910
911 column LIKE '%' || <other> || '%'
912
913 E.g.::
914
915 stmt = select(sometable).\
916 where(sometable.c.column.contains("foobar"))
917
918 Since the operator uses ``LIKE``, wildcard characters
919 ``"%"`` and ``"_"`` that are present inside the <other> expression
920 will behave like wildcards as well. For literal string
921 values, the :paramref:`.ColumnOperators.contains.autoescape` flag
922 may be set to ``True`` to apply escaping to occurrences of these
923 characters within the string value so that they match as themselves
924 and not as wildcard characters. Alternatively, the
925 :paramref:`.ColumnOperators.contains.escape` parameter will establish
926 a given character as an escape character which can be of use when
927 the target expression is not a literal string.
928
929 :param other: expression to be compared. This is usually a plain
930 string value, but can also be an arbitrary SQL expression. LIKE
931 wildcard characters ``%`` and ``_`` are not escaped by default unless
932 the :paramref:`.ColumnOperators.contains.autoescape` flag is
933 set to True.
934
935 :param autoescape: boolean; when True, establishes an escape character
936 within the LIKE expression, then applies it to all occurrences of
937 ``"%"``, ``"_"`` and the escape character itself within the
938 comparison value, which is assumed to be a literal string and not a
939 SQL expression.
940
941 An expression such as::
942
943 somecolumn.contains("foo%bar", autoescape=True)
944
945 Will render as::
946
947 somecolumn LIKE '%' || :param || '%' ESCAPE '/'
948
949 With the value of ``:param`` as ``"foo/%bar"``.
950
951 :param escape: a character which when given will render with the
952 ``ESCAPE`` keyword to establish that character as the escape
953 character. This character can then be placed preceding occurrences
954 of ``%`` and ``_`` to allow them to act as themselves and not
955 wildcard characters.
956
957 An expression such as::
958
959 somecolumn.contains("foo/%bar", escape="^")
960
961 Will render as::
962
963 somecolumn LIKE '%' || :param || '%' ESCAPE '^'
964
965 The parameter may also be combined with
966 :paramref:`.ColumnOperators.contains.autoescape`::
967
968 somecolumn.contains("foo%bar^bat", escape="^", autoescape=True)
969
970 Where above, the given literal parameter will be converted to
971 ``"foo^%bar^^bat"`` before being passed to the database.
972
973 .. seealso::
974
975 :meth:`.ColumnOperators.startswith`
976
977 :meth:`.ColumnOperators.endswith`
978
979 :meth:`.ColumnOperators.like`
980
981
982 """
983 return self.operate(contains_op, other, **kwargs)
984
985 def match(self, other, **kwargs):
986 """Implements a database-specific 'match' operator.
987
988 :meth:`_sql.ColumnOperators.match` attempts to resolve to
989 a MATCH-like function or operator provided by the backend.
990 Examples include:
991
992 * PostgreSQL - renders ``x @@ to_tsquery(y)``
993 * MySQL - renders ``MATCH (x) AGAINST (y IN BOOLEAN MODE)``
994
995 .. seealso::
996
997 :class:`_mysql.match` - MySQL specific construct with
998 additional features.
999
1000 * Oracle - renders ``CONTAINS(x, y)``
1001 * other backends may provide special implementations.
1002 * Backends without any special implementation will emit
1003 the operator as "MATCH". This is compatible with SQLite, for
1004 example.
1005
1006 """
1007 return self.operate(match_op, other, **kwargs)
1008
1009 def regexp_match(self, pattern, flags=None):
1010 """Implements a database-specific 'regexp match' operator.
1011
1012 E.g.::
1013
1014 stmt = select(table.c.some_column).where(
1015 table.c.some_column.regexp_match('^(b|c)')
1016 )
1017
1018 :meth:`_sql.ColumnOperators.regexp_match` attempts to resolve to
1019 a REGEXP-like function or operator provided by the backend, however
1020 the specific regular expression syntax and flags available are
1021 **not backend agnostic**.
1022
1023 Examples include:
1024
1025 * PostgreSQL - renders ``x ~ y`` or ``x !~ y`` when negated.
1026 * Oracle - renders ``REGEXP_LIKE(x, y)``
1027 * SQLite - uses SQLite's ``REGEXP`` placeholder operator and calls into
1028 the Python ``re.match()`` builtin.
1029 * other backends may provide special implementations.
1030 * Backends without any special implementation will emit
1031 the operator as "REGEXP" or "NOT REGEXP". This is compatible with
1032 SQLite and MySQL, for example.
1033
1034 Regular expression support is currently implemented for Oracle,
1035 PostgreSQL, MySQL and MariaDB. Partial support is available for
1036 SQLite. Support among third-party dialects may vary.
1037
1038 :param pattern: The regular expression pattern string or column
1039 clause.
1040 :param flags: Any regular expression string flags to apply, passed as
1041 plain Python string only. These flags are backend specific.
1042 Some backends, like PostgreSQL and MariaDB, may alternatively
1043 specify the flags as part of the pattern.
1044 When using the ignore case flag 'i' in PostgreSQL, the ignore case
1045 regexp match operator ``~*`` or ``!~*`` will be used.
1046
1047 .. versionadded:: 1.4
1048
1049 .. versionchanged:: 1.4.48, 2.0.18 Note that due to an implementation
1050 error, the "flags" parameter previously accepted SQL expression
1051 objects such as column expressions in addition to plain Python
1052 strings. This implementation did not work correctly with caching
1053 and was removed; strings only should be passed for the "flags"
1054 parameter, as these flags are rendered as literal inline values
1055 within SQL expressions.
1056
1057 .. seealso::
1058
1059 :meth:`_sql.ColumnOperators.regexp_replace`
1060
1061
1062 """
1063 return self.operate(regexp_match_op, pattern, flags=flags)
1064
1065 def regexp_replace(self, pattern, replacement, flags=None):
1066 """Implements a database-specific 'regexp replace' operator.
1067
1068 E.g.::
1069
1070 stmt = select(
1071 table.c.some_column.regexp_replace(
1072 'b(..)',
1073 'X\1Y',
1074 flags='g'
1075 )
1076 )
1077
1078 :meth:`_sql.ColumnOperators.regexp_replace` attempts to resolve to
1079 a REGEXP_REPLACE-like function provided by the backend, that
1080 usually emit the function ``REGEXP_REPLACE()``. However,
1081 the specific regular expression syntax and flags available are
1082 **not backend agnostic**.
1083
1084 Regular expression replacement support is currently implemented for
1085 Oracle, PostgreSQL, MySQL 8 or greater and MariaDB. Support among
1086 third-party dialects may vary.
1087
1088 :param pattern: The regular expression pattern string or column
1089 clause.
1090 :param pattern: The replacement string or column clause.
1091 :param flags: Any regular expression string flags to apply, passed as
1092 plain Python string only. These flags are backend specific.
1093 Some backends, like PostgreSQL and MariaDB, may alternatively
1094 specify the flags as part of the pattern.
1095
1096 .. versionadded:: 1.4
1097
1098 .. versionchanged:: 1.4.48, 2.0.18 Note that due to an implementation
1099 error, the "flags" parameter previously accepted SQL expression
1100 objects such as column expressions in addition to plain Python
1101 strings. This implementation did not work correctly with caching
1102 and was removed; strings only should be passed for the "flags"
1103 parameter, as these flags are rendered as literal inline values
1104 within SQL expressions.
1105
1106
1107 .. seealso::
1108
1109 :meth:`_sql.ColumnOperators.regexp_match`
1110
1111 """
1112 return self.operate(
1113 regexp_replace_op, pattern, replacement=replacement, flags=flags
1114 )
1115
1116 def desc(self):
1117 """Produce a :func:`_expression.desc` clause against the
1118 parent object."""
1119 return self.operate(desc_op)
1120
1121 def asc(self):
1122 """Produce a :func:`_expression.asc` clause against the
1123 parent object."""
1124 return self.operate(asc_op)
1125
1126 def nulls_first(self):
1127 """Produce a :func:`_expression.nulls_first` clause against the
1128 parent object.
1129
1130 .. versionchanged:: 1.4 The ``nulls_first()`` operator is
1131 renamed from ``nullsfirst()`` in previous releases.
1132 The previous name remains available for backwards compatibility.
1133 """
1134 return self.operate(nulls_first_op)
1135
1136 # deprecated 1.4; see #5435
1137 nullsfirst = nulls_first
1138
1139 def nulls_last(self):
1140 """Produce a :func:`_expression.nulls_last` clause against the
1141 parent object.
1142
1143 .. versionchanged:: 1.4 The ``nulls_last()`` operator is
1144 renamed from ``nullslast()`` in previous releases.
1145 The previous name remains available for backwards compatibility.
1146 """
1147 return self.operate(nulls_last_op)
1148
1149 # deprecated 1.4; see #5429
1150 nullslast = nulls_last
1151
1152 def collate(self, collation):
1153 """Produce a :func:`_expression.collate` clause against
1154 the parent object, given the collation string.
1155
1156 .. seealso::
1157
1158 :func:`_expression.collate`
1159
1160 """
1161 return self.operate(collate, collation)
1162
1163 def __radd__(self, other):
1164 """Implement the ``+`` operator in reverse.
1165
1166 See :meth:`.ColumnOperators.__add__`.
1167
1168 """
1169 return self.reverse_operate(add, other)
1170
1171 def __rsub__(self, other):
1172 """Implement the ``-`` operator in reverse.
1173
1174 See :meth:`.ColumnOperators.__sub__`.
1175
1176 """
1177 return self.reverse_operate(sub, other)
1178
1179 def __rmul__(self, other):
1180 """Implement the ``*`` operator in reverse.
1181
1182 See :meth:`.ColumnOperators.__mul__`.
1183
1184 """
1185 return self.reverse_operate(mul, other)
1186
1187 def __rdiv__(self, other):
1188 """Implement the ``/`` operator in reverse.
1189
1190 See :meth:`.ColumnOperators.__div__`.
1191
1192 """
1193 return self.reverse_operate(div, other)
1194
1195 def __rmod__(self, other):
1196 """Implement the ``%`` operator in reverse.
1197
1198 See :meth:`.ColumnOperators.__mod__`.
1199
1200 """
1201 return self.reverse_operate(mod, other)
1202
1203 def between(self, cleft, cright, symmetric=False):
1204 """Produce a :func:`_expression.between` clause against
1205 the parent object, given the lower and upper range.
1206
1207 """
1208 return self.operate(between_op, cleft, cright, symmetric=symmetric)
1209
1210 def distinct(self):
1211 """Produce a :func:`_expression.distinct` clause against the
1212 parent object.
1213
1214 """
1215 return self.operate(distinct_op)
1216
1217 def any_(self):
1218 """Produce an :func:`_expression.any_` clause against the
1219 parent object.
1220
1221 See the documentation for :func:`_sql.any_` for examples.
1222
1223 .. note:: be sure to not confuse the newer
1224 :meth:`_sql.ColumnOperators.any_` method with its older
1225 :class:`_types.ARRAY`-specific counterpart, the
1226 :meth:`_types.ARRAY.Comparator.any` method, which a different
1227 calling syntax and usage pattern.
1228
1229 .. versionadded:: 1.1
1230
1231 """
1232 return self.operate(any_op)
1233
1234 def all_(self):
1235 """Produce an :func:`_expression.all_` clause against the
1236 parent object.
1237
1238 See the documentation for :func:`_sql.all_` for examples.
1239
1240 .. note:: be sure to not confuse the newer
1241 :meth:`_sql.ColumnOperators.all_` method with its older
1242 :class:`_types.ARRAY`-specific counterpart, the
1243 :meth:`_types.ARRAY.Comparator.all` method, which a different
1244 calling syntax and usage pattern.
1245
1246
1247 .. versionadded:: 1.1
1248
1249 """
1250 return self.operate(all_op)
1251
1252 def __add__(self, other):
1253 """Implement the ``+`` operator.
1254
1255 In a column context, produces the clause ``a + b``
1256 if the parent object has non-string affinity.
1257 If the parent object has a string affinity,
1258 produces the concatenation operator, ``a || b`` -
1259 see :meth:`.ColumnOperators.concat`.
1260
1261 """
1262 return self.operate(add, other)
1263
1264 def __sub__(self, other):
1265 """Implement the ``-`` operator.
1266
1267 In a column context, produces the clause ``a - b``.
1268
1269 """
1270 return self.operate(sub, other)
1271
1272 def __mul__(self, other):
1273 """Implement the ``*`` operator.
1274
1275 In a column context, produces the clause ``a * b``.
1276
1277 """
1278 return self.operate(mul, other)
1279
1280 def __div__(self, other):
1281 """Implement the ``/`` operator.
1282
1283 In a column context, produces the clause ``a / b``.
1284
1285 """
1286 return self.operate(div, other)
1287
1288 def __mod__(self, other):
1289 """Implement the ``%`` operator.
1290
1291 In a column context, produces the clause ``a % b``.
1292
1293 """
1294 return self.operate(mod, other)
1295
1296 def __truediv__(self, other):
1297 """Implement the ``//`` operator.
1298
1299 In a column context, produces the clause ``a / b``.
1300
1301 """
1302 return self.operate(truediv, other)
1303
1304 def __rtruediv__(self, other):
1305 """Implement the ``//`` operator in reverse.
1306
1307 See :meth:`.ColumnOperators.__truediv__`.
1308
1309 """
1310 return self.reverse_operate(truediv, other)
1311
1312
1313_commutative = {eq, ne, add, mul}
1314_comparison = {eq, ne, lt, gt, ge, le}
1315
1316
1317def commutative_op(fn):
1318 _commutative.add(fn)
1319 return fn
1320
1321
1322def comparison_op(fn):
1323 _comparison.add(fn)
1324 return fn
1325
1326
1327def from_():
1328 raise NotImplementedError()
1329
1330
1331@comparison_op
1332def function_as_comparison_op():
1333 raise NotImplementedError()
1334
1335
1336def as_():
1337 raise NotImplementedError()
1338
1339
1340def exists():
1341 raise NotImplementedError()
1342
1343
1344def is_true(a):
1345 raise NotImplementedError()
1346
1347
1348# 1.4 deprecated; see #5435
1349istrue = is_true
1350
1351
1352def is_false(a):
1353 raise NotImplementedError()
1354
1355
1356# 1.4 deprecated; see #5435
1357isfalse = is_false
1358
1359
1360@comparison_op
1361def is_distinct_from(a, b):
1362 return a.is_distinct_from(b)
1363
1364
1365@comparison_op
1366def is_not_distinct_from(a, b):
1367 return a.is_not_distinct_from(b)
1368
1369
1370# deprecated 1.4; see #5435
1371isnot_distinct_from = is_not_distinct_from
1372
1373
1374@comparison_op
1375def is_(a, b):
1376 return a.is_(b)
1377
1378
1379@comparison_op
1380def is_not(a, b):
1381 return a.is_not(b)
1382
1383
1384# 1.4 deprecated; see #5429
1385isnot = is_not
1386
1387
1388def collate(a, b):
1389 return a.collate(b)
1390
1391
1392def op(a, opstring, b):
1393 return a.op(opstring)(b)
1394
1395
1396@comparison_op
1397def like_op(a, b, escape=None):
1398 return a.like(b, escape=escape)
1399
1400
1401@comparison_op
1402def not_like_op(a, b, escape=None):
1403 return a.notlike(b, escape=escape)
1404
1405
1406# 1.4 deprecated; see #5435
1407notlike_op = not_like_op
1408
1409
1410@comparison_op
1411def ilike_op(a, b, escape=None):
1412 return a.ilike(b, escape=escape)
1413
1414
1415@comparison_op
1416def not_ilike_op(a, b, escape=None):
1417 return a.not_ilike(b, escape=escape)
1418
1419
1420# 1.4 deprecated; see #5435
1421notilike_op = not_ilike_op
1422
1423
1424@comparison_op
1425def between_op(a, b, c, symmetric=False):
1426 return a.between(b, c, symmetric=symmetric)
1427
1428
1429@comparison_op
1430def not_between_op(a, b, c, symmetric=False):
1431 return ~a.between(b, c, symmetric=symmetric)
1432
1433
1434# 1.4 deprecated; see #5435
1435notbetween_op = not_between_op
1436
1437
1438@comparison_op
1439def in_op(a, b):
1440 return a.in_(b)
1441
1442
1443@comparison_op
1444def not_in_op(a, b):
1445 return a.not_in(b)
1446
1447
1448# 1.4 deprecated; see #5429
1449notin_op = not_in_op
1450
1451
1452def distinct_op(a):
1453 return a.distinct()
1454
1455
1456def any_op(a):
1457 return a.any_()
1458
1459
1460def all_op(a):
1461 return a.all_()
1462
1463
1464def _escaped_like_impl(fn, other, escape, autoescape):
1465 if autoescape:
1466 if autoescape is not True:
1467 util.warn(
1468 "The autoescape parameter is now a simple boolean True/False"
1469 )
1470 if escape is None:
1471 escape = "/"
1472
1473 if not isinstance(other, util.compat.string_types):
1474 raise TypeError("String value expected when autoescape=True")
1475
1476 if escape not in ("%", "_"):
1477 other = other.replace(escape, escape + escape)
1478
1479 other = other.replace("%", escape + "%").replace("_", escape + "_")
1480
1481 return fn(other, escape=escape)
1482
1483
1484@comparison_op
1485def startswith_op(a, b, escape=None, autoescape=False):
1486 return _escaped_like_impl(a.startswith, b, escape, autoescape)
1487
1488
1489@comparison_op
1490def not_startswith_op(a, b, escape=None, autoescape=False):
1491 return ~_escaped_like_impl(a.startswith, b, escape, autoescape)
1492
1493
1494# 1.4 deprecated; see #5435
1495notstartswith_op = not_startswith_op
1496
1497
1498@comparison_op
1499def endswith_op(a, b, escape=None, autoescape=False):
1500 return _escaped_like_impl(a.endswith, b, escape, autoescape)
1501
1502
1503@comparison_op
1504def not_endswith_op(a, b, escape=None, autoescape=False):
1505 return ~_escaped_like_impl(a.endswith, b, escape, autoescape)
1506
1507
1508# 1.4 deprecated; see #5435
1509notendswith_op = not_endswith_op
1510
1511
1512@comparison_op
1513def contains_op(a, b, escape=None, autoescape=False):
1514 return _escaped_like_impl(a.contains, b, escape, autoescape)
1515
1516
1517@comparison_op
1518def not_contains_op(a, b, escape=None, autoescape=False):
1519 return ~_escaped_like_impl(a.contains, b, escape, autoescape)
1520
1521
1522# 1.4 deprecated; see #5435
1523notcontains_op = not_contains_op
1524
1525
1526@comparison_op
1527def match_op(a, b, **kw):
1528 return a.match(b, **kw)
1529
1530
1531@comparison_op
1532def regexp_match_op(a, b, flags=None):
1533 return a.regexp_match(b, flags=flags)
1534
1535
1536@comparison_op
1537def not_regexp_match_op(a, b, flags=None):
1538 return ~a.regexp_match(b, flags=flags)
1539
1540
1541def regexp_replace_op(a, b, replacement, flags=None):
1542 return a.regexp_replace(b, replacement=replacement, flags=flags)
1543
1544
1545@comparison_op
1546def not_match_op(a, b, **kw):
1547 return ~a.match(b, **kw)
1548
1549
1550# 1.4 deprecated; see #5429
1551notmatch_op = not_match_op
1552
1553
1554def comma_op(a, b):
1555 raise NotImplementedError()
1556
1557
1558def filter_op(a, b):
1559 raise NotImplementedError()
1560
1561
1562def concat_op(a, b):
1563 try:
1564 concat = a.concat
1565 except AttributeError:
1566 return b._rconcat(a)
1567 else:
1568 return concat(b)
1569
1570
1571def desc_op(a):
1572 return a.desc()
1573
1574
1575def asc_op(a):
1576 return a.asc()
1577
1578
1579def nulls_first_op(a):
1580 return a.nulls_first()
1581
1582
1583# 1.4 deprecated; see #5435
1584nullsfirst_op = nulls_first_op
1585
1586
1587def nulls_last_op(a):
1588 return a.nulls_last()
1589
1590
1591# 1.4 deprecated; see #5435
1592nullslast_op = nulls_last_op
1593
1594
1595def json_getitem_op(a, b):
1596 raise NotImplementedError()
1597
1598
1599def json_path_getitem_op(a, b):
1600 raise NotImplementedError()
1601
1602
1603def is_comparison(op):
1604 return op in _comparison or isinstance(op, custom_op) and op.is_comparison
1605
1606
1607def is_commutative(op):
1608 return op in _commutative
1609
1610
1611def is_ordering_modifier(op):
1612 return op in (asc_op, desc_op, nulls_first_op, nulls_last_op)
1613
1614
1615def is_natural_self_precedent(op):
1616 return (
1617 op in _natural_self_precedent
1618 or isinstance(op, custom_op)
1619 and op.natural_self_precedent
1620 )
1621
1622
1623_booleans = (inv, is_true, is_false, and_, or_)
1624
1625
1626def is_boolean(op):
1627 return is_comparison(op) or op in _booleans
1628
1629
1630_mirror = {gt: lt, ge: le, lt: gt, le: ge}
1631
1632
1633def mirror(op):
1634 """rotate a comparison operator 180 degrees.
1635
1636 Note this is not the same as negation.
1637
1638 """
1639 return _mirror.get(op, op)
1640
1641
1642_associative = _commutative.union([concat_op, and_, or_]).difference([eq, ne])
1643
1644
1645def is_associative(op):
1646 return op in _associative
1647
1648
1649_natural_self_precedent = _associative.union(
1650 [getitem, json_getitem_op, json_path_getitem_op]
1651)
1652"""Operators where if we have (a op b) op c, we don't want to
1653parenthesize (a op b).
1654
1655"""
1656
1657
1658_asbool = util.symbol("_asbool", canonical=-10)
1659_smallest = util.symbol("_smallest", canonical=-100)
1660_largest = util.symbol("_largest", canonical=100)
1661
1662_PRECEDENCE = {
1663 from_: 15,
1664 function_as_comparison_op: 15,
1665 any_op: 15,
1666 all_op: 15,
1667 getitem: 15,
1668 json_getitem_op: 15,
1669 json_path_getitem_op: 15,
1670 mul: 8,
1671 truediv: 8,
1672 div: 8,
1673 mod: 8,
1674 neg: 8,
1675 add: 7,
1676 sub: 7,
1677 concat_op: 6,
1678 filter_op: 6,
1679 match_op: 5,
1680 not_match_op: 5,
1681 regexp_match_op: 5,
1682 not_regexp_match_op: 5,
1683 regexp_replace_op: 5,
1684 ilike_op: 5,
1685 not_ilike_op: 5,
1686 like_op: 5,
1687 not_like_op: 5,
1688 in_op: 5,
1689 not_in_op: 5,
1690 is_: 5,
1691 is_not: 5,
1692 eq: 5,
1693 ne: 5,
1694 is_distinct_from: 5,
1695 is_not_distinct_from: 5,
1696 gt: 5,
1697 lt: 5,
1698 ge: 5,
1699 le: 5,
1700 between_op: 5,
1701 not_between_op: 5,
1702 distinct_op: 5,
1703 inv: 5,
1704 is_true: 5,
1705 is_false: 5,
1706 and_: 3,
1707 or_: 2,
1708 comma_op: -1,
1709 desc_op: 3,
1710 asc_op: 3,
1711 collate: 4,
1712 as_: -1,
1713 exists: 0,
1714 _asbool: -10,
1715 _smallest: _smallest,
1716 _largest: _largest,
1717}
1718
1719
1720def is_precedent(operator, against):
1721 if operator is against and is_natural_self_precedent(operator):
1722 return False
1723 else:
1724 return _PRECEDENCE.get(
1725 operator, getattr(operator, "precedence", _smallest)
1726 ) <= _PRECEDENCE.get(against, getattr(against, "precedence", _largest))