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