Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/operators.py: 63%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

605 statements  

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 matmul as _uncast_matmul 

29from operator import mod as _uncast_mod 

30from operator import mul as _uncast_mul 

31from operator import ne as _uncast_ne 

32from operator import neg as _uncast_neg 

33from operator import or_ as _uncast_or_ 

34from operator import pow as _uncast_pow 

35from operator import rshift as _uncast_rshift 

36from operator import sub as _uncast_sub 

37from operator import truediv as _uncast_truediv 

38import typing 

39from typing import Any 

40from typing import Callable 

41from typing import cast 

42from typing import Dict 

43from typing import Generic 

44from typing import Literal 

45from typing import Optional 

46from typing import overload 

47from typing import Protocol 

48from typing import Set 

49from typing import Tuple 

50from typing import Type 

51from typing import TYPE_CHECKING 

52from typing import TypeVar 

53from typing import Union 

54 

55from .. import exc 

56from .. import util 

57 

58if typing.TYPE_CHECKING: 

59 from ._typing import ColumnExpressionArgument 

60 from .cache_key import CacheConst 

61 from .elements import ColumnElement 

62 from .type_api import TypeEngine 

63 

64_T = TypeVar("_T", bound=Any) 

65_FN = TypeVar("_FN", bound=Callable[..., Any]) 

66 

67 

68class OperatorType(Protocol): 

69 """describe an op() function.""" 

70 

71 __slots__ = () 

72 

73 __name__: str 

74 

75 @overload 

76 def __call__( 

77 self, 

78 left: ColumnExpressionArgument[Any], 

79 right: Optional[Any] = None, 

80 *other: Any, 

81 **kwargs: Any, 

82 ) -> ColumnElement[Any]: ... 

83 

84 @overload 

85 def __call__( 

86 self, 

87 left: Operators, 

88 right: Optional[Any] = None, 

89 *other: Any, 

90 **kwargs: Any, 

91 ) -> Operators: ... 

92 

93 def __call__( 

94 self, 

95 left: Any, 

96 right: Optional[Any] = None, 

97 *other: Any, 

98 **kwargs: Any, 

99 ) -> Operators: ... 

100 

101 

102add = cast(OperatorType, _uncast_add) 

103and_ = cast(OperatorType, _uncast_and_) 

104contains = cast(OperatorType, _uncast_contains) 

105eq = cast(OperatorType, _uncast_eq) 

106floordiv = cast(OperatorType, _uncast_floordiv) 

107ge = cast(OperatorType, _uncast_ge) 

108getitem = cast(OperatorType, _uncast_getitem) 

109gt = cast(OperatorType, _uncast_gt) 

110inv = cast(OperatorType, _uncast_inv) 

111le = cast(OperatorType, _uncast_le) 

112lshift = cast(OperatorType, _uncast_lshift) 

113lt = cast(OperatorType, _uncast_lt) 

114matmul = cast(OperatorType, _uncast_matmul) 

115mod = cast(OperatorType, _uncast_mod) 

116mul = cast(OperatorType, _uncast_mul) 

117ne = cast(OperatorType, _uncast_ne) 

118neg = cast(OperatorType, _uncast_neg) 

119or_ = cast(OperatorType, _uncast_or_) 

120pow_ = cast(OperatorType, _uncast_pow) 

121rshift = cast(OperatorType, _uncast_rshift) 

122sub = cast(OperatorType, _uncast_sub) 

123truediv = cast(OperatorType, _uncast_truediv) 

124 

125 

126class Operators: 

127 """Base of comparison and logical operators. 

128 

129 Implements base methods 

130 :meth:`~sqlalchemy.sql.operators.Operators.operate` and 

131 :meth:`~sqlalchemy.sql.operators.Operators.reverse_operate`, as well as 

132 :meth:`~sqlalchemy.sql.operators.Operators.__and__`, 

133 :meth:`~sqlalchemy.sql.operators.Operators.__or__`, 

134 :meth:`~sqlalchemy.sql.operators.Operators.__invert__`. 

135 

136 Usually is used via its most common subclass 

137 :class:`.ColumnOperators`. 

138 

139 """ 

140 

141 __slots__ = () 

142 

143 def __and__(self, other: Any) -> Operators: 

144 """Implement the ``&`` operator. 

145 

146 When used with SQL expressions, results in an 

147 AND operation, equivalent to 

148 :func:`_expression.and_`, that is:: 

149 

150 a & b 

151 

152 is equivalent to:: 

153 

154 from sqlalchemy import and_ 

155 

156 and_(a, b) 

157 

158 Care should be taken when using ``&`` regarding 

159 operator precedence; the ``&`` operator has the highest precedence. 

160 The operands should be enclosed in parenthesis if they contain 

161 further sub expressions:: 

162 

163 (a == 2) & (b == 4) 

164 

165 """ 

166 return self.operate(and_, other) 

167 

168 def __or__(self, other: Any) -> Operators: 

169 """Implement the ``|`` operator. 

170 

171 When used with SQL expressions, results in an 

172 OR operation, equivalent to 

173 :func:`_expression.or_`, that is:: 

174 

175 a | b 

176 

177 is equivalent to:: 

178 

179 from sqlalchemy import or_ 

180 

181 or_(a, b) 

182 

183 Care should be taken when using ``|`` regarding 

184 operator precedence; the ``|`` operator has the highest precedence. 

185 The operands should be enclosed in parenthesis if they contain 

186 further sub expressions:: 

187 

188 (a == 2) | (b == 4) 

189 

190 """ 

191 return self.operate(or_, other) 

192 

193 def __invert__(self) -> Operators: 

194 """Implement the ``~`` operator. 

195 

196 When used with SQL expressions, results in a 

197 NOT operation, equivalent to 

198 :func:`_expression.not_`, that is:: 

199 

200 ~a 

201 

202 is equivalent to:: 

203 

204 from sqlalchemy import not_ 

205 

206 not_(a) 

207 

208 """ 

209 return self.operate(inv) 

210 

211 def op( 

212 self, 

213 opstring: str, 

214 precedence: int = 0, 

215 is_comparison: bool = False, 

216 return_type: Optional[ 

217 Union[Type[TypeEngine[Any]], TypeEngine[Any]] 

218 ] = None, 

219 python_impl: Optional[Callable[..., Any]] = None, 

220 ) -> Callable[[Any], Operators]: 

221 """Produce a generic operator function. 

222 

223 e.g.:: 

224 

225 somecolumn.op("*")(5) 

226 

227 produces:: 

228 

229 somecolumn * 5 

230 

231 This function can also be used to make bitwise operators explicit. For 

232 example:: 

233 

234 somecolumn.op("&")(0xFF) 

235 

236 is a bitwise AND of the value in ``somecolumn``. 

237 

238 :param opstring: a string which will be output as the infix operator 

239 between this element and the expression passed to the 

240 generated function. 

241 

242 :param precedence: precedence which the database is expected to apply 

243 to the operator in SQL expressions. This integer value acts as a hint 

244 for the SQL compiler to know when explicit parenthesis should be 

245 rendered around a particular operation. A lower number will cause the 

246 expression to be parenthesized when applied against another operator 

247 with higher precedence. The default value of ``0`` is lower than all 

248 operators except for the comma (``,``) and ``AS`` operators. A value 

249 of 100 will be higher or equal to all operators, and -100 will be 

250 lower than or equal to all operators. 

251 

252 .. seealso:: 

253 

254 :ref:`faq_sql_expression_op_parenthesis` - detailed description 

255 of how the SQLAlchemy SQL compiler renders parenthesis 

256 

257 :param is_comparison: legacy; if True, the operator will be considered 

258 as a "comparison" operator, that is which evaluates to a boolean 

259 true/false value, like ``==``, ``>``, etc. This flag is provided 

260 so that ORM relationships can establish that the operator is a 

261 comparison operator when used in a custom join condition. 

262 

263 Using the ``is_comparison`` parameter is superseded by using the 

264 :meth:`.Operators.bool_op` method instead; this more succinct 

265 operator sets this parameter automatically, but also provides 

266 correct :pep:`484` typing support as the returned object will 

267 express a "boolean" datatype, i.e. ``BinaryExpression[bool]``. 

268 

269 :param return_type: a :class:`.TypeEngine` class or object that will 

270 force the return type of an expression produced by this operator 

271 to be of that type. By default, operators that specify 

272 :paramref:`.Operators.op.is_comparison` will resolve to 

273 :class:`.Boolean`, and those that do not will be of the same 

274 type as the left-hand operand. 

275 

276 :param python_impl: an optional Python function that can evaluate 

277 two Python values in the same way as this operator works when 

278 run on the database server. Useful for in-Python SQL expression 

279 evaluation functions, such as for ORM hybrid attributes, and the 

280 ORM "evaluator" used to match objects in a session after a multi-row 

281 update or delete. 

282 

283 e.g.:: 

284 

285 >>> expr = column("x").op("+", python_impl=lambda a, b: a + b)("y") 

286 

287 The operator for the above expression will also work for non-SQL 

288 left and right objects:: 

289 

290 >>> expr.operator(5, 10) 

291 15 

292 

293 .. versionadded:: 2.0 

294 

295 

296 .. seealso:: 

297 

298 :meth:`.Operators.bool_op` 

299 

300 :ref:`types_operators` 

301 

302 :ref:`relationship_custom_operator` 

303 

304 """ 

305 operator = custom_op( 

306 opstring, 

307 precedence, 

308 is_comparison, 

309 return_type, 

310 python_impl=python_impl, 

311 ) 

312 

313 def against(other: Any) -> Operators: 

314 return operator(self, other) 

315 

316 return against 

317 

318 def bool_op( 

319 self, 

320 opstring: str, 

321 precedence: int = 0, 

322 python_impl: Optional[Callable[..., Any]] = None, 

323 ) -> Callable[[Any], Operators]: 

324 """Return a custom boolean operator. 

325 

326 This method is shorthand for calling 

327 :meth:`.Operators.op` and passing the 

328 :paramref:`.Operators.op.is_comparison` 

329 flag with True. A key advantage to using :meth:`.Operators.bool_op` 

330 is that when using column constructs, the "boolean" nature of the 

331 returned expression will be present for :pep:`484` purposes. 

332 

333 .. seealso:: 

334 

335 :meth:`.Operators.op` 

336 

337 """ 

338 return self.op( 

339 opstring, 

340 precedence=precedence, 

341 is_comparison=True, 

342 python_impl=python_impl, 

343 ) 

344 

345 def operate( 

346 self, op: OperatorType, *other: Any, **kwargs: Any 

347 ) -> Operators: 

348 r"""Operate on an argument. 

349 

350 This is the lowest level of operation, raises 

351 :class:`NotImplementedError` by default. 

352 

353 Overriding this on a subclass can allow common 

354 behavior to be applied to all operations. 

355 For example, overriding :class:`.ColumnOperators` 

356 to apply ``func.lower()`` to the left and right 

357 side:: 

358 

359 class MyComparator(ColumnOperators): 

360 def operate(self, op, other, **kwargs): 

361 return op(func.lower(self), func.lower(other), **kwargs) 

362 

363 :param op: Operator callable. 

364 :param \*other: the 'other' side of the operation. Will 

365 be a single scalar for most operations. 

366 :param \**kwargs: modifiers. These may be passed by special 

367 operators such as :meth:`ColumnOperators.contains`. 

368 

369 

370 """ 

371 raise NotImplementedError(str(op)) 

372 

373 __sa_operate__ = operate 

374 

375 def reverse_operate( 

376 self, op: OperatorType, other: Any, **kwargs: Any 

377 ) -> Operators: 

378 """Reverse operate on an argument. 

379 

380 Usage is the same as :meth:`operate`. 

381 

382 """ 

383 raise NotImplementedError(str(op)) 

384 

385 

386class custom_op(OperatorType, Generic[_T]): 

387 """Represent a 'custom' operator. 

388 

389 :class:`.custom_op` is normally instantiated when the 

390 :meth:`.Operators.op` or :meth:`.Operators.bool_op` methods 

391 are used to create a custom operator callable. The class can also be 

392 used directly when programmatically constructing expressions. E.g. 

393 to represent the "factorial" operation:: 

394 

395 from sqlalchemy.sql import UnaryExpression 

396 from sqlalchemy.sql import operators 

397 from sqlalchemy import Numeric 

398 

399 unary = UnaryExpression( 

400 table.c.somecolumn, modifier=operators.custom_op("!"), type_=Numeric 

401 ) 

402 

403 .. seealso:: 

404 

405 :meth:`.Operators.op` 

406 

407 :meth:`.Operators.bool_op` 

408 

409 """ # noqa: E501 

410 

411 __name__ = "custom_op" 

412 

413 __slots__ = ( 

414 "opstring", 

415 "precedence", 

416 "is_comparison", 

417 "natural_self_precedent", 

418 "eager_grouping", 

419 "return_type", 

420 "python_impl", 

421 ) 

422 

423 def __init__( 

424 self, 

425 opstring: str, 

426 precedence: int = 0, 

427 is_comparison: bool = False, 

428 return_type: Optional[ 

429 Union[Type[TypeEngine[_T]], TypeEngine[_T]] 

430 ] = None, 

431 natural_self_precedent: bool = False, 

432 eager_grouping: bool = False, 

433 python_impl: Optional[Callable[..., Any]] = None, 

434 ): 

435 self.opstring = opstring 

436 self.precedence = precedence 

437 self.is_comparison = is_comparison 

438 self.natural_self_precedent = natural_self_precedent 

439 self.eager_grouping = eager_grouping 

440 self.return_type = ( 

441 return_type._to_instance(return_type) if return_type else None 

442 ) 

443 self.python_impl = python_impl 

444 

445 def __eq__(self, other: Any) -> bool: 

446 return ( 

447 isinstance(other, custom_op) 

448 and other._hash_key() == self._hash_key() 

449 ) 

450 

451 def __hash__(self) -> int: 

452 return hash(self._hash_key()) 

453 

454 def _hash_key(self) -> Union[CacheConst, Tuple[Any, ...]]: 

455 return ( 

456 self.__class__, 

457 self.opstring, 

458 self.precedence, 

459 self.is_comparison, 

460 self.natural_self_precedent, 

461 self.eager_grouping, 

462 self.return_type._static_cache_key if self.return_type else None, 

463 ) 

464 

465 @overload 

466 def __call__( 

467 self, 

468 left: ColumnExpressionArgument[Any], 

469 right: Optional[Any] = None, 

470 *other: Any, 

471 **kwargs: Any, 

472 ) -> ColumnElement[Any]: ... 

473 

474 @overload 

475 def __call__( 

476 self, 

477 left: Operators, 

478 right: Optional[Any] = None, 

479 *other: Any, 

480 **kwargs: Any, 

481 ) -> Operators: ... 

482 

483 def __call__( 

484 self, 

485 left: Any, 

486 right: Optional[Any] = None, 

487 *other: Any, 

488 **kwargs: Any, 

489 ) -> Operators: 

490 if hasattr(left, "__sa_operate__"): 

491 return left.operate(self, right, *other, **kwargs) # type: ignore 

492 elif self.python_impl: 

493 return self.python_impl(left, right, *other, **kwargs) # type: ignore # noqa: E501 

494 else: 

495 raise exc.InvalidRequestError( 

496 f"Custom operator {self.opstring!r} can't be used with " 

497 "plain Python objects unless it includes the " 

498 "'python_impl' parameter." 

499 ) 

500 

501 

502class OrderingOperators(Operators): 

503 """defines ORDER BY operators, which can operate as single expressions 

504 or comma-separated lists 

505 

506 """ 

507 

508 __slots__ = () 

509 

510 if typing.TYPE_CHECKING: 

511 

512 def operate( 

513 self, op: OperatorType, *other: Any, **kwargs: Any 

514 ) -> OrderingOperators: ... 

515 

516 def reverse_operate( 

517 self, op: OperatorType, other: Any, **kwargs: Any 

518 ) -> OrderingOperators: ... 

519 

520 def desc(self) -> OrderingOperators: 

521 """Produce a :func:`_expression.desc` clause against the 

522 parent object.""" 

523 return self.operate(desc_op) 

524 

525 def asc(self) -> OrderingOperators: 

526 """Produce a :func:`_expression.asc` clause against the 

527 parent object.""" 

528 return self.operate(asc_op) 

529 

530 def nulls_first(self) -> OrderingOperators: 

531 """Produce a :func:`_expression.nulls_first` clause against the 

532 parent object. 

533 

534 .. versionchanged:: 1.4 The ``nulls_first()`` operator is 

535 renamed from ``nullsfirst()`` in previous releases. 

536 The previous name remains available for backwards compatibility. 

537 """ 

538 return self.operate(nulls_first_op) 

539 

540 # deprecated 1.4; see #5435 

541 if TYPE_CHECKING: 

542 

543 def nullsfirst(self) -> OrderingOperators: ... 

544 

545 else: 

546 nullsfirst = nulls_first 

547 

548 def nulls_last(self) -> OrderingOperators: 

549 """Produce a :func:`_expression.nulls_last` clause against the 

550 parent object. 

551 

552 .. versionchanged:: 1.4 The ``nulls_last()`` operator is 

553 renamed from ``nullslast()`` in previous releases. 

554 The previous name remains available for backwards compatibility. 

555 """ 

556 return self.operate(nulls_last_op) 

557 

558 # deprecated 1.4; see #5429 

559 if TYPE_CHECKING: 

560 

561 def nullslast(self) -> OrderingOperators: ... 

562 

563 else: 

564 nullslast = nulls_last 

565 

566 

567class ColumnOperators(OrderingOperators): 

568 """Defines boolean, comparison, and other operators for 

569 :class:`_expression.ColumnElement` expressions. 

570 

571 By default, all methods call down to 

572 :meth:`.operate` or :meth:`.reverse_operate`, 

573 passing in the appropriate operator function from the 

574 Python builtin ``operator`` module or 

575 a SQLAlchemy-specific operator function from 

576 :mod:`sqlalchemy.expression.operators`. For example 

577 the ``__eq__`` function:: 

578 

579 def __eq__(self, other): 

580 return self.operate(operators.eq, other) 

581 

582 Where ``operators.eq`` is essentially:: 

583 

584 def eq(a, b): 

585 return a == b 

586 

587 The core column expression unit :class:`_expression.ColumnElement` 

588 overrides :meth:`.Operators.operate` and others 

589 to return further :class:`_expression.ColumnElement` constructs, 

590 so that the ``==`` operation above is replaced by a clause 

591 construct. 

592 

593 .. seealso:: 

594 

595 :ref:`types_operators` 

596 

597 :attr:`.TypeEngine.comparator_factory` 

598 

599 :class:`.ColumnOperators` 

600 

601 :class:`.PropComparator` 

602 

603 """ 

604 

605 __slots__ = () 

606 

607 timetuple: Literal[None] = None 

608 """Hack, allows datetime objects to be compared on the LHS.""" 

609 

610 if typing.TYPE_CHECKING: 

611 

612 def operate( 

613 self, op: OperatorType, *other: Any, **kwargs: Any 

614 ) -> ColumnOperators: ... 

615 

616 def reverse_operate( 

617 self, op: OperatorType, other: Any, **kwargs: Any 

618 ) -> ColumnOperators: ... 

619 

620 def __lt__(self, other: Any) -> ColumnOperators: 

621 """Implement the ``<`` operator. 

622 

623 In a column context, produces the clause ``a < b``. 

624 

625 """ 

626 return self.operate(lt, other) 

627 

628 def __le__(self, other: Any) -> ColumnOperators: 

629 """Implement the ``<=`` operator. 

630 

631 In a column context, produces the clause ``a <= b``. 

632 

633 """ 

634 return self.operate(le, other) 

635 

636 # ColumnOperators defines an __eq__ so it must explicitly declare also 

637 # an hash or it's set to None by python: 

638 # https://docs.python.org/3/reference/datamodel.html#object.__hash__ 

639 if TYPE_CHECKING: 

640 

641 def __hash__(self) -> int: ... 

642 

643 else: 

644 __hash__ = Operators.__hash__ 

645 

646 def __eq__(self, other: Any) -> ColumnOperators: # type: ignore[override] 

647 """Implement the ``==`` operator. 

648 

649 In a column context, produces the clause ``a = b``. 

650 If the target is ``None``, produces ``a IS NULL``. 

651 

652 """ 

653 return self.operate(eq, other) 

654 

655 def __ne__(self, other: Any) -> ColumnOperators: # type: ignore[override] 

656 """Implement the ``!=`` operator. 

657 

658 In a column context, produces the clause ``a != b``. 

659 If the target is ``None``, produces ``a IS NOT NULL``. 

660 

661 """ 

662 return self.operate(ne, other) 

663 

664 def is_distinct_from(self, other: Any) -> ColumnOperators: 

665 """Implement the ``IS DISTINCT FROM`` operator. 

666 

667 Renders "a IS DISTINCT FROM b" on most platforms; 

668 on some such as SQLite may render "a IS NOT b". 

669 

670 """ 

671 return self.operate(is_distinct_from, other) 

672 

673 def is_not_distinct_from(self, other: Any) -> ColumnOperators: 

674 """Implement the ``IS NOT DISTINCT FROM`` operator. 

675 

676 Renders "a IS NOT DISTINCT FROM b" on most platforms; 

677 on some such as SQLite may render "a IS b". 

678 

679 .. versionchanged:: 1.4 The ``is_not_distinct_from()`` operator is 

680 renamed from ``isnot_distinct_from()`` in previous releases. 

681 The previous name remains available for backwards compatibility. 

682 

683 """ 

684 return self.operate(is_not_distinct_from, other) 

685 

686 # deprecated 1.4; see #5435 

687 if TYPE_CHECKING: 

688 

689 def isnot_distinct_from(self, other: Any) -> ColumnOperators: ... 

690 

691 else: 

692 isnot_distinct_from = is_not_distinct_from 

693 

694 def __gt__(self, other: Any) -> ColumnOperators: 

695 """Implement the ``>`` operator. 

696 

697 In a column context, produces the clause ``a > b``. 

698 

699 """ 

700 return self.operate(gt, other) 

701 

702 def __ge__(self, other: Any) -> ColumnOperators: 

703 """Implement the ``>=`` operator. 

704 

705 In a column context, produces the clause ``a >= b``. 

706 

707 """ 

708 return self.operate(ge, other) 

709 

710 def __neg__(self) -> ColumnOperators: 

711 """Implement the ``-`` operator. 

712 

713 In a column context, produces the clause ``-a``. 

714 

715 """ 

716 return self.operate(neg) 

717 

718 def __contains__(self, other: Any) -> ColumnOperators: 

719 return self.operate(contains, other) 

720 

721 def __getitem__(self, index: Any) -> ColumnOperators: 

722 """Implement the [] operator. 

723 

724 This can be used by some database-specific types 

725 such as PostgreSQL ARRAY and HSTORE. 

726 

727 """ 

728 return self.operate(getitem, index) 

729 

730 def __lshift__(self, other: Any) -> ColumnOperators: 

731 """Implement the ``<<`` operator. 

732 

733 Not used by SQLAlchemy core, this is provided 

734 for custom operator systems which want to use 

735 << as an extension point. 

736 """ 

737 return self.operate(lshift, other) 

738 

739 def __rlshift__(self, other: Any) -> ColumnOperators: 

740 """Implement the ``<<`` operator in reverse. 

741 

742 Not used by SQLAlchemy core, this is provided 

743 for custom operator systems which want to use 

744 << as an extension point. 

745 """ 

746 return self.reverse_operate(lshift, other) 

747 

748 def __rshift__(self, other: Any) -> ColumnOperators: 

749 """Implement the ``>>`` operator. 

750 

751 Not used by SQLAlchemy core, this is provided 

752 for custom operator systems which want to use 

753 >> as an extension point. 

754 """ 

755 return self.operate(rshift, other) 

756 

757 def __rrshift__(self, other: Any) -> ColumnOperators: 

758 """Implement the ``>>`` operator in reverse. 

759 

760 Not used by SQLAlchemy core, this is provided 

761 for custom operator systems which want to use 

762 >> as an extension point. 

763 """ 

764 return self.reverse_operate(rshift, other) 

765 

766 def __matmul__(self, other: Any) -> ColumnOperators: 

767 """Implement the ``@`` operator. 

768 

769 Not used by SQLAlchemy core, this is provided 

770 for custom operator systems which want to use 

771 @ as an extension point. 

772 """ 

773 return self.operate(matmul, other) 

774 

775 def __rmatmul__(self, other: Any) -> ColumnOperators: 

776 """Implement the ``@`` operator in reverse. 

777 

778 Not used by SQLAlchemy core, this is provided 

779 for custom operator systems which want to use 

780 @ as an extension point. 

781 """ 

782 return self.reverse_operate(matmul, other) 

783 

784 def concat(self, other: Any) -> ColumnOperators: 

785 """Implement the 'concat' operator. 

786 

787 In a column context, produces the clause ``a || b``, 

788 or uses the ``concat()`` operator on MySQL. 

789 

790 """ 

791 return self.operate(concat_op, other) 

792 

793 def _rconcat(self, other: Any) -> ColumnOperators: 

794 """Implement an 'rconcat' operator. 

795 

796 this is for internal use at the moment 

797 

798 .. versionadded:: 1.4.40 

799 

800 """ 

801 return self.reverse_operate(concat_op, other) 

802 

803 def like( 

804 self, other: Any, escape: Optional[str] = None 

805 ) -> ColumnOperators: 

806 r"""Implement the ``like`` operator. 

807 

808 In a column context, produces the expression: 

809 

810 .. sourcecode:: sql 

811 

812 a LIKE other 

813 

814 E.g.:: 

815 

816 stmt = select(sometable).where(sometable.c.column.like("%foobar%")) 

817 

818 :param other: expression to be compared 

819 :param escape: optional escape character, renders the ``ESCAPE`` 

820 keyword, e.g.:: 

821 

822 somecolumn.like("foo/%bar", escape="/") 

823 

824 .. seealso:: 

825 

826 :meth:`.ColumnOperators.ilike` 

827 

828 """ 

829 return self.operate(like_op, other, escape=escape) 

830 

831 def ilike( 

832 self, other: Any, escape: Optional[str] = None 

833 ) -> ColumnOperators: 

834 r"""Implement the ``ilike`` operator, e.g. case insensitive LIKE. 

835 

836 In a column context, produces an expression either of the form: 

837 

838 .. sourcecode:: sql 

839 

840 lower(a) LIKE lower(other) 

841 

842 Or on backends that support the ILIKE operator: 

843 

844 .. sourcecode:: sql 

845 

846 a ILIKE other 

847 

848 E.g.:: 

849 

850 stmt = select(sometable).where(sometable.c.column.ilike("%foobar%")) 

851 

852 :param other: expression to be compared 

853 :param escape: optional escape character, renders the ``ESCAPE`` 

854 keyword, e.g.:: 

855 

856 somecolumn.ilike("foo/%bar", escape="/") 

857 

858 .. seealso:: 

859 

860 :meth:`.ColumnOperators.like` 

861 

862 """ # noqa: E501 

863 return self.operate(ilike_op, other, escape=escape) 

864 

865 def bitwise_xor(self, other: Any) -> ColumnOperators: 

866 """Produce a bitwise XOR operation, typically via the ``^`` 

867 operator, or ``#`` for PostgreSQL. 

868 

869 .. versionadded:: 2.0.2 

870 

871 .. seealso:: 

872 

873 :ref:`operators_bitwise` 

874 

875 """ 

876 

877 return self.operate(bitwise_xor_op, other) 

878 

879 def bitwise_or(self, other: Any) -> ColumnOperators: 

880 """Produce a bitwise OR operation, typically via the ``|`` 

881 operator. 

882 

883 .. versionadded:: 2.0.2 

884 

885 .. seealso:: 

886 

887 :ref:`operators_bitwise` 

888 

889 """ 

890 

891 return self.operate(bitwise_or_op, other) 

892 

893 def bitwise_and(self, other: Any) -> ColumnOperators: 

894 """Produce a bitwise AND operation, typically via the ``&`` 

895 operator. 

896 

897 .. versionadded:: 2.0.2 

898 

899 .. seealso:: 

900 

901 :ref:`operators_bitwise` 

902 

903 """ 

904 

905 return self.operate(bitwise_and_op, other) 

906 

907 def bitwise_not(self) -> ColumnOperators: 

908 """Produce a bitwise NOT operation, typically via the ``~`` 

909 operator. 

910 

911 .. versionadded:: 2.0.2 

912 

913 .. seealso:: 

914 

915 :ref:`operators_bitwise` 

916 

917 """ 

918 

919 return self.operate(bitwise_not_op) 

920 

921 def bitwise_lshift(self, other: Any) -> ColumnOperators: 

922 """Produce a bitwise LSHIFT operation, typically via the ``<<`` 

923 operator. 

924 

925 .. versionadded:: 2.0.2 

926 

927 .. seealso:: 

928 

929 :ref:`operators_bitwise` 

930 

931 """ 

932 

933 return self.operate(bitwise_lshift_op, other) 

934 

935 def bitwise_rshift(self, other: Any) -> ColumnOperators: 

936 """Produce a bitwise RSHIFT operation, typically via the ``>>`` 

937 operator. 

938 

939 .. versionadded:: 2.0.2 

940 

941 .. seealso:: 

942 

943 :ref:`operators_bitwise` 

944 

945 """ 

946 

947 return self.operate(bitwise_rshift_op, other) 

948 

949 def in_(self, other: Any) -> ColumnOperators: 

950 """Implement the ``in`` operator. 

951 

952 In a column context, produces the clause ``column IN <other>``. 

953 

954 The given parameter ``other`` may be: 

955 

956 * A list of literal values, 

957 e.g.:: 

958 

959 stmt.where(column.in_([1, 2, 3])) 

960 

961 In this calling form, the list of items is converted to a set of 

962 bound parameters the same length as the list given: 

963 

964 .. sourcecode:: sql 

965 

966 WHERE COL IN (?, ?, ?) 

967 

968 * A list of tuples may be provided if the comparison is against a 

969 :func:`.tuple_` containing multiple expressions:: 

970 

971 from sqlalchemy import tuple_ 

972 

973 stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)])) 

974 

975 * An empty list, 

976 e.g.:: 

977 

978 stmt.where(column.in_([])) 

979 

980 In this calling form, the expression renders an "empty set" 

981 expression. These expressions are tailored to individual backends 

982 and are generally trying to get an empty SELECT statement as a 

983 subquery. Such as on SQLite, the expression is: 

984 

985 .. sourcecode:: sql 

986 

987 WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1) 

988 

989 .. versionchanged:: 1.4 empty IN expressions now use an 

990 execution-time generated SELECT subquery in all cases. 

991 

992 * A bound parameter, e.g. :func:`.bindparam`, may be used if it 

993 includes the :paramref:`.bindparam.expanding` flag:: 

994 

995 stmt.where(column.in_(bindparam("value", expanding=True))) 

996 

997 In this calling form, the expression renders a special non-SQL 

998 placeholder expression that looks like: 

999 

1000 .. sourcecode:: sql 

1001 

1002 WHERE COL IN ([EXPANDING_value]) 

1003 

1004 This placeholder expression is intercepted at statement execution 

1005 time to be converted into the variable number of bound parameter 

1006 form illustrated earlier. If the statement were executed as:: 

1007 

1008 connection.execute(stmt, {"value": [1, 2, 3]}) 

1009 

1010 The database would be passed a bound parameter for each value: 

1011 

1012 .. sourcecode:: sql 

1013 

1014 WHERE COL IN (?, ?, ?) 

1015 

1016 If an empty list is passed, a special "empty list" expression, 

1017 which is specific to the database in use, is rendered. On 

1018 SQLite this would be: 

1019 

1020 .. sourcecode:: sql 

1021 

1022 WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1) 

1023 

1024 * a :func:`_expression.select` construct, which is usually a 

1025 correlated scalar select:: 

1026 

1027 stmt.where( 

1028 column.in_(select(othertable.c.y).where(table.c.x == othertable.c.x)) 

1029 ) 

1030 

1031 In this calling form, :meth:`.ColumnOperators.in_` renders as given: 

1032 

1033 .. sourcecode:: sql 

1034 

1035 WHERE COL IN (SELECT othertable.y 

1036 FROM othertable WHERE othertable.x = table.x) 

1037 

1038 :param other: a list of literals, a :func:`_expression.select` 

1039 construct, or a :func:`.bindparam` construct that includes the 

1040 :paramref:`.bindparam.expanding` flag set to True. 

1041 

1042 """ # noqa: E501 

1043 return self.operate(in_op, other) 

1044 

1045 def not_in(self, other: Any) -> ColumnOperators: 

1046 """implement the ``NOT IN`` operator. 

1047 

1048 This is equivalent to using negation with 

1049 :meth:`.ColumnOperators.in_`, i.e. ``~x.in_(y)``. 

1050 

1051 In the case that ``other`` is an empty sequence, the compiler 

1052 produces an "empty not in" expression. This defaults to the 

1053 expression "1 = 1" to produce true in all cases. The 

1054 :paramref:`_sa.create_engine.empty_in_strategy` may be used to 

1055 alter this behavior. 

1056 

1057 .. versionchanged:: 1.4 The ``not_in()`` operator is renamed from 

1058 ``notin_()`` in previous releases. The previous name remains 

1059 available for backwards compatibility. 

1060 

1061 .. seealso:: 

1062 

1063 :meth:`.ColumnOperators.in_` 

1064 

1065 """ 

1066 return self.operate(not_in_op, other) 

1067 

1068 # deprecated 1.4; see #5429 

1069 if TYPE_CHECKING: 

1070 

1071 def notin_(self, other: Any) -> ColumnOperators: ... 

1072 

1073 else: 

1074 notin_ = not_in 

1075 

1076 def not_like( 

1077 self, other: Any, escape: Optional[str] = None 

1078 ) -> ColumnOperators: 

1079 """implement the ``NOT LIKE`` operator. 

1080 

1081 This is equivalent to using negation with 

1082 :meth:`.ColumnOperators.like`, i.e. ``~x.like(y)``. 

1083 

1084 .. versionchanged:: 1.4 The ``not_like()`` operator is renamed from 

1085 ``notlike()`` in previous releases. The previous name remains 

1086 available for backwards compatibility. 

1087 

1088 .. seealso:: 

1089 

1090 :meth:`.ColumnOperators.like` 

1091 

1092 """ 

1093 return self.operate(not_like_op, other, escape=escape) 

1094 

1095 # deprecated 1.4; see #5435 

1096 if TYPE_CHECKING: 

1097 

1098 def notlike( 

1099 self, other: Any, escape: Optional[str] = None 

1100 ) -> ColumnOperators: ... 

1101 

1102 else: 

1103 notlike = not_like 

1104 

1105 def not_ilike( 

1106 self, other: Any, escape: Optional[str] = None 

1107 ) -> ColumnOperators: 

1108 """implement the ``NOT ILIKE`` operator. 

1109 

1110 This is equivalent to using negation with 

1111 :meth:`.ColumnOperators.ilike`, i.e. ``~x.ilike(y)``. 

1112 

1113 .. versionchanged:: 1.4 The ``not_ilike()`` operator is renamed from 

1114 ``notilike()`` in previous releases. The previous name remains 

1115 available for backwards compatibility. 

1116 

1117 .. seealso:: 

1118 

1119 :meth:`.ColumnOperators.ilike` 

1120 

1121 """ 

1122 return self.operate(not_ilike_op, other, escape=escape) 

1123 

1124 # deprecated 1.4; see #5435 

1125 if TYPE_CHECKING: 

1126 

1127 def notilike( 

1128 self, other: Any, escape: Optional[str] = None 

1129 ) -> ColumnOperators: ... 

1130 

1131 else: 

1132 notilike = not_ilike 

1133 

1134 def is_(self, other: Any) -> ColumnOperators: 

1135 """Implement the ``IS`` operator. 

1136 

1137 Normally, ``IS`` is generated automatically when comparing to a 

1138 value of ``None``, which resolves to ``NULL``. However, explicit 

1139 usage of ``IS`` may be desirable if comparing to boolean values 

1140 on certain platforms. 

1141 

1142 .. seealso:: :meth:`.ColumnOperators.is_not` 

1143 

1144 """ 

1145 return self.operate(is_, other) 

1146 

1147 def is_not(self, other: Any) -> ColumnOperators: 

1148 """Implement the ``IS NOT`` operator. 

1149 

1150 Normally, ``IS NOT`` is generated automatically when comparing to a 

1151 value of ``None``, which resolves to ``NULL``. However, explicit 

1152 usage of ``IS NOT`` may be desirable if comparing to boolean values 

1153 on certain platforms. 

1154 

1155 .. versionchanged:: 1.4 The ``is_not()`` operator is renamed from 

1156 ``isnot()`` in previous releases. The previous name remains 

1157 available for backwards compatibility. 

1158 

1159 .. seealso:: :meth:`.ColumnOperators.is_` 

1160 

1161 """ 

1162 return self.operate(is_not, other) 

1163 

1164 # deprecated 1.4; see #5429 

1165 if TYPE_CHECKING: 

1166 

1167 def isnot(self, other: Any) -> ColumnOperators: ... 

1168 

1169 else: 

1170 isnot = is_not 

1171 

1172 def startswith( 

1173 self, 

1174 other: Any, 

1175 escape: Optional[str] = None, 

1176 autoescape: bool = False, 

1177 ) -> ColumnOperators: 

1178 r"""Implement the ``startswith`` operator. 

1179 

1180 Produces a LIKE expression that tests against a match for the start 

1181 of a string value: 

1182 

1183 .. sourcecode:: sql 

1184 

1185 column LIKE <other> || '%' 

1186 

1187 E.g.:: 

1188 

1189 stmt = select(sometable).where(sometable.c.column.startswith("foobar")) 

1190 

1191 Since the operator uses ``LIKE``, wildcard characters 

1192 ``"%"`` and ``"_"`` that are present inside the <other> expression 

1193 will behave like wildcards as well. For literal string 

1194 values, the :paramref:`.ColumnOperators.startswith.autoescape` flag 

1195 may be set to ``True`` to apply escaping to occurrences of these 

1196 characters within the string value so that they match as themselves 

1197 and not as wildcard characters. Alternatively, the 

1198 :paramref:`.ColumnOperators.startswith.escape` parameter will establish 

1199 a given character as an escape character which can be of use when 

1200 the target expression is not a literal string. 

1201 

1202 :param other: expression to be compared. This is usually a plain 

1203 string value, but can also be an arbitrary SQL expression. LIKE 

1204 wildcard characters ``%`` and ``_`` are not escaped by default unless 

1205 the :paramref:`.ColumnOperators.startswith.autoescape` flag is 

1206 set to True. 

1207 

1208 :param autoescape: boolean; when True, establishes an escape character 

1209 within the LIKE expression, then applies it to all occurrences of 

1210 ``"%"``, ``"_"`` and the escape character itself within the 

1211 comparison value, which is assumed to be a literal string and not a 

1212 SQL expression. 

1213 

1214 An expression such as:: 

1215 

1216 somecolumn.startswith("foo%bar", autoescape=True) 

1217 

1218 Will render as: 

1219 

1220 .. sourcecode:: sql 

1221 

1222 somecolumn LIKE :param || '%' ESCAPE '/' 

1223 

1224 With the value of ``:param`` as ``"foo/%bar"``. 

1225 

1226 :param escape: a character which when given will render with the 

1227 ``ESCAPE`` keyword to establish that character as the escape 

1228 character. This character can then be placed preceding occurrences 

1229 of ``%`` and ``_`` to allow them to act as themselves and not 

1230 wildcard characters. 

1231 

1232 An expression such as:: 

1233 

1234 somecolumn.startswith("foo/%bar", escape="^") 

1235 

1236 Will render as: 

1237 

1238 .. sourcecode:: sql 

1239 

1240 somecolumn LIKE :param || '%' ESCAPE '^' 

1241 

1242 The parameter may also be combined with 

1243 :paramref:`.ColumnOperators.startswith.autoescape`:: 

1244 

1245 somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True) 

1246 

1247 Where above, the given literal parameter will be converted to 

1248 ``"foo^%bar^^bat"`` before being passed to the database. 

1249 

1250 .. seealso:: 

1251 

1252 :meth:`.ColumnOperators.endswith` 

1253 

1254 :meth:`.ColumnOperators.contains` 

1255 

1256 :meth:`.ColumnOperators.like` 

1257 

1258 """ # noqa: E501 

1259 return self.operate( 

1260 startswith_op, other, escape=escape, autoescape=autoescape 

1261 ) 

1262 

1263 def istartswith( 

1264 self, 

1265 other: Any, 

1266 escape: Optional[str] = None, 

1267 autoescape: bool = False, 

1268 ) -> ColumnOperators: 

1269 r"""Implement the ``istartswith`` operator, e.g. case insensitive 

1270 version of :meth:`.ColumnOperators.startswith`. 

1271 

1272 Produces a LIKE expression that tests against an insensitive 

1273 match for the start of a string value: 

1274 

1275 .. sourcecode:: sql 

1276 

1277 lower(column) LIKE lower(<other>) || '%' 

1278 

1279 E.g.:: 

1280 

1281 stmt = select(sometable).where(sometable.c.column.istartswith("foobar")) 

1282 

1283 Since the operator uses ``LIKE``, wildcard characters 

1284 ``"%"`` and ``"_"`` that are present inside the <other> expression 

1285 will behave like wildcards as well. For literal string 

1286 values, the :paramref:`.ColumnOperators.istartswith.autoescape` flag 

1287 may be set to ``True`` to apply escaping to occurrences of these 

1288 characters within the string value so that they match as themselves 

1289 and not as wildcard characters. Alternatively, the 

1290 :paramref:`.ColumnOperators.istartswith.escape` parameter will 

1291 establish a given character as an escape character which can be of 

1292 use when the target expression is not a literal string. 

1293 

1294 :param other: expression to be compared. This is usually a plain 

1295 string value, but can also be an arbitrary SQL expression. LIKE 

1296 wildcard characters ``%`` and ``_`` are not escaped by default unless 

1297 the :paramref:`.ColumnOperators.istartswith.autoescape` flag is 

1298 set to True. 

1299 

1300 :param autoescape: boolean; when True, establishes an escape character 

1301 within the LIKE expression, then applies it to all occurrences of 

1302 ``"%"``, ``"_"`` and the escape character itself within the 

1303 comparison value, which is assumed to be a literal string and not a 

1304 SQL expression. 

1305 

1306 An expression such as:: 

1307 

1308 somecolumn.istartswith("foo%bar", autoescape=True) 

1309 

1310 Will render as: 

1311 

1312 .. sourcecode:: sql 

1313 

1314 lower(somecolumn) LIKE lower(:param) || '%' ESCAPE '/' 

1315 

1316 With the value of ``:param`` as ``"foo/%bar"``. 

1317 

1318 :param escape: a character which when given will render with the 

1319 ``ESCAPE`` keyword to establish that character as the escape 

1320 character. This character can then be placed preceding occurrences 

1321 of ``%`` and ``_`` to allow them to act as themselves and not 

1322 wildcard characters. 

1323 

1324 An expression such as:: 

1325 

1326 somecolumn.istartswith("foo/%bar", escape="^") 

1327 

1328 Will render as: 

1329 

1330 .. sourcecode:: sql 

1331 

1332 lower(somecolumn) LIKE lower(:param) || '%' ESCAPE '^' 

1333 

1334 The parameter may also be combined with 

1335 :paramref:`.ColumnOperators.istartswith.autoescape`:: 

1336 

1337 somecolumn.istartswith("foo%bar^bat", escape="^", autoescape=True) 

1338 

1339 Where above, the given literal parameter will be converted to 

1340 ``"foo^%bar^^bat"`` before being passed to the database. 

1341 

1342 .. seealso:: 

1343 

1344 :meth:`.ColumnOperators.startswith` 

1345 """ # noqa: E501 

1346 return self.operate( 

1347 istartswith_op, other, escape=escape, autoescape=autoescape 

1348 ) 

1349 

1350 def endswith( 

1351 self, 

1352 other: Any, 

1353 escape: Optional[str] = None, 

1354 autoescape: bool = False, 

1355 ) -> ColumnOperators: 

1356 r"""Implement the 'endswith' operator. 

1357 

1358 Produces a LIKE expression that tests against a match for the end 

1359 of a string value: 

1360 

1361 .. sourcecode:: sql 

1362 

1363 column LIKE '%' || <other> 

1364 

1365 E.g.:: 

1366 

1367 stmt = select(sometable).where(sometable.c.column.endswith("foobar")) 

1368 

1369 Since the operator uses ``LIKE``, wildcard characters 

1370 ``"%"`` and ``"_"`` that are present inside the <other> expression 

1371 will behave like wildcards as well. For literal string 

1372 values, the :paramref:`.ColumnOperators.endswith.autoescape` flag 

1373 may be set to ``True`` to apply escaping to occurrences of these 

1374 characters within the string value so that they match as themselves 

1375 and not as wildcard characters. Alternatively, the 

1376 :paramref:`.ColumnOperators.endswith.escape` parameter will establish 

1377 a given character as an escape character which can be of use when 

1378 the target expression is not a literal string. 

1379 

1380 :param other: expression to be compared. This is usually a plain 

1381 string value, but can also be an arbitrary SQL expression. LIKE 

1382 wildcard characters ``%`` and ``_`` are not escaped by default unless 

1383 the :paramref:`.ColumnOperators.endswith.autoescape` flag is 

1384 set to True. 

1385 

1386 :param autoescape: boolean; when True, establishes an escape character 

1387 within the LIKE expression, then applies it to all occurrences of 

1388 ``"%"``, ``"_"`` and the escape character itself within the 

1389 comparison value, which is assumed to be a literal string and not a 

1390 SQL expression. 

1391 

1392 An expression such as:: 

1393 

1394 somecolumn.endswith("foo%bar", autoescape=True) 

1395 

1396 Will render as: 

1397 

1398 .. sourcecode:: sql 

1399 

1400 somecolumn LIKE '%' || :param ESCAPE '/' 

1401 

1402 With the value of ``:param`` as ``"foo/%bar"``. 

1403 

1404 :param escape: a character which when given will render with the 

1405 ``ESCAPE`` keyword to establish that character as the escape 

1406 character. This character can then be placed preceding occurrences 

1407 of ``%`` and ``_`` to allow them to act as themselves and not 

1408 wildcard characters. 

1409 

1410 An expression such as:: 

1411 

1412 somecolumn.endswith("foo/%bar", escape="^") 

1413 

1414 Will render as: 

1415 

1416 .. sourcecode:: sql 

1417 

1418 somecolumn LIKE '%' || :param ESCAPE '^' 

1419 

1420 The parameter may also be combined with 

1421 :paramref:`.ColumnOperators.endswith.autoescape`:: 

1422 

1423 somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True) 

1424 

1425 Where above, the given literal parameter will be converted to 

1426 ``"foo^%bar^^bat"`` before being passed to the database. 

1427 

1428 .. seealso:: 

1429 

1430 :meth:`.ColumnOperators.startswith` 

1431 

1432 :meth:`.ColumnOperators.contains` 

1433 

1434 :meth:`.ColumnOperators.like` 

1435 

1436 """ # noqa: E501 

1437 return self.operate( 

1438 endswith_op, other, escape=escape, autoescape=autoescape 

1439 ) 

1440 

1441 def iendswith( 

1442 self, 

1443 other: Any, 

1444 escape: Optional[str] = None, 

1445 autoescape: bool = False, 

1446 ) -> ColumnOperators: 

1447 r"""Implement the ``iendswith`` operator, e.g. case insensitive 

1448 version of :meth:`.ColumnOperators.endswith`. 

1449 

1450 Produces a LIKE expression that tests against an insensitive match 

1451 for the end of a string value: 

1452 

1453 .. sourcecode:: sql 

1454 

1455 lower(column) LIKE '%' || lower(<other>) 

1456 

1457 E.g.:: 

1458 

1459 stmt = select(sometable).where(sometable.c.column.iendswith("foobar")) 

1460 

1461 Since the operator uses ``LIKE``, wildcard characters 

1462 ``"%"`` and ``"_"`` that are present inside the <other> expression 

1463 will behave like wildcards as well. For literal string 

1464 values, the :paramref:`.ColumnOperators.iendswith.autoescape` flag 

1465 may be set to ``True`` to apply escaping to occurrences of these 

1466 characters within the string value so that they match as themselves 

1467 and not as wildcard characters. Alternatively, the 

1468 :paramref:`.ColumnOperators.iendswith.escape` parameter will establish 

1469 a given character as an escape character which can be of use when 

1470 the target expression is not a literal string. 

1471 

1472 :param other: expression to be compared. This is usually a plain 

1473 string value, but can also be an arbitrary SQL expression. LIKE 

1474 wildcard characters ``%`` and ``_`` are not escaped by default unless 

1475 the :paramref:`.ColumnOperators.iendswith.autoescape` flag is 

1476 set to True. 

1477 

1478 :param autoescape: boolean; when True, establishes an escape character 

1479 within the LIKE expression, then applies it to all occurrences of 

1480 ``"%"``, ``"_"`` and the escape character itself within the 

1481 comparison value, which is assumed to be a literal string and not a 

1482 SQL expression. 

1483 

1484 An expression such as:: 

1485 

1486 somecolumn.iendswith("foo%bar", autoescape=True) 

1487 

1488 Will render as: 

1489 

1490 .. sourcecode:: sql 

1491 

1492 lower(somecolumn) LIKE '%' || lower(:param) ESCAPE '/' 

1493 

1494 With the value of ``:param`` as ``"foo/%bar"``. 

1495 

1496 :param escape: a character which when given will render with the 

1497 ``ESCAPE`` keyword to establish that character as the escape 

1498 character. This character can then be placed preceding occurrences 

1499 of ``%`` and ``_`` to allow them to act as themselves and not 

1500 wildcard characters. 

1501 

1502 An expression such as:: 

1503 

1504 somecolumn.iendswith("foo/%bar", escape="^") 

1505 

1506 Will render as: 

1507 

1508 .. sourcecode:: sql 

1509 

1510 lower(somecolumn) LIKE '%' || lower(:param) ESCAPE '^' 

1511 

1512 The parameter may also be combined with 

1513 :paramref:`.ColumnOperators.iendswith.autoescape`:: 

1514 

1515 somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True) 

1516 

1517 Where above, the given literal parameter will be converted to 

1518 ``"foo^%bar^^bat"`` before being passed to the database. 

1519 

1520 .. seealso:: 

1521 

1522 :meth:`.ColumnOperators.endswith` 

1523 """ # noqa: E501 

1524 return self.operate( 

1525 iendswith_op, other, escape=escape, autoescape=autoescape 

1526 ) 

1527 

1528 def contains(self, other: Any, **kw: Any) -> ColumnOperators: 

1529 r"""Implement the 'contains' operator. 

1530 

1531 Produces a LIKE expression that tests against a match for the middle 

1532 of a string value: 

1533 

1534 .. sourcecode:: sql 

1535 

1536 column LIKE '%' || <other> || '%' 

1537 

1538 E.g.:: 

1539 

1540 stmt = select(sometable).where(sometable.c.column.contains("foobar")) 

1541 

1542 Since the operator uses ``LIKE``, wildcard characters 

1543 ``"%"`` and ``"_"`` that are present inside the <other> expression 

1544 will behave like wildcards as well. For literal string 

1545 values, the :paramref:`.ColumnOperators.contains.autoescape` flag 

1546 may be set to ``True`` to apply escaping to occurrences of these 

1547 characters within the string value so that they match as themselves 

1548 and not as wildcard characters. Alternatively, the 

1549 :paramref:`.ColumnOperators.contains.escape` parameter will establish 

1550 a given character as an escape character which can be of use when 

1551 the target expression is not a literal string. 

1552 

1553 :param other: expression to be compared. This is usually a plain 

1554 string value, but can also be an arbitrary SQL expression. LIKE 

1555 wildcard characters ``%`` and ``_`` are not escaped by default unless 

1556 the :paramref:`.ColumnOperators.contains.autoescape` flag is 

1557 set to True. 

1558 

1559 :param autoescape: boolean; when True, establishes an escape character 

1560 within the LIKE expression, then applies it to all occurrences of 

1561 ``"%"``, ``"_"`` and the escape character itself within the 

1562 comparison value, which is assumed to be a literal string and not a 

1563 SQL expression. 

1564 

1565 An expression such as:: 

1566 

1567 somecolumn.contains("foo%bar", autoescape=True) 

1568 

1569 Will render as: 

1570 

1571 .. sourcecode:: sql 

1572 

1573 somecolumn LIKE '%' || :param || '%' ESCAPE '/' 

1574 

1575 With the value of ``:param`` as ``"foo/%bar"``. 

1576 

1577 :param escape: a character which when given will render with the 

1578 ``ESCAPE`` keyword to establish that character as the escape 

1579 character. This character can then be placed preceding occurrences 

1580 of ``%`` and ``_`` to allow them to act as themselves and not 

1581 wildcard characters. 

1582 

1583 An expression such as:: 

1584 

1585 somecolumn.contains("foo/%bar", escape="^") 

1586 

1587 Will render as: 

1588 

1589 .. sourcecode:: sql 

1590 

1591 somecolumn LIKE '%' || :param || '%' ESCAPE '^' 

1592 

1593 The parameter may also be combined with 

1594 :paramref:`.ColumnOperators.contains.autoescape`:: 

1595 

1596 somecolumn.contains("foo%bar^bat", escape="^", autoescape=True) 

1597 

1598 Where above, the given literal parameter will be converted to 

1599 ``"foo^%bar^^bat"`` before being passed to the database. 

1600 

1601 .. seealso:: 

1602 

1603 :meth:`.ColumnOperators.startswith` 

1604 

1605 :meth:`.ColumnOperators.endswith` 

1606 

1607 :meth:`.ColumnOperators.like` 

1608 

1609 

1610 """ # noqa: E501 

1611 return self.operate(contains_op, other, **kw) 

1612 

1613 def icontains(self, other: Any, **kw: Any) -> ColumnOperators: 

1614 r"""Implement the ``icontains`` operator, e.g. case insensitive 

1615 version of :meth:`.ColumnOperators.contains`. 

1616 

1617 Produces a LIKE expression that tests against an insensitive match 

1618 for the middle of a string value: 

1619 

1620 .. sourcecode:: sql 

1621 

1622 lower(column) LIKE '%' || lower(<other>) || '%' 

1623 

1624 E.g.:: 

1625 

1626 stmt = select(sometable).where(sometable.c.column.icontains("foobar")) 

1627 

1628 Since the operator uses ``LIKE``, wildcard characters 

1629 ``"%"`` and ``"_"`` that are present inside the <other> expression 

1630 will behave like wildcards as well. For literal string 

1631 values, the :paramref:`.ColumnOperators.icontains.autoescape` flag 

1632 may be set to ``True`` to apply escaping to occurrences of these 

1633 characters within the string value so that they match as themselves 

1634 and not as wildcard characters. Alternatively, the 

1635 :paramref:`.ColumnOperators.icontains.escape` parameter will establish 

1636 a given character as an escape character which can be of use when 

1637 the target expression is not a literal string. 

1638 

1639 :param other: expression to be compared. This is usually a plain 

1640 string value, but can also be an arbitrary SQL expression. LIKE 

1641 wildcard characters ``%`` and ``_`` are not escaped by default unless 

1642 the :paramref:`.ColumnOperators.icontains.autoescape` flag is 

1643 set to True. 

1644 

1645 :param autoescape: boolean; when True, establishes an escape character 

1646 within the LIKE expression, then applies it to all occurrences of 

1647 ``"%"``, ``"_"`` and the escape character itself within the 

1648 comparison value, which is assumed to be a literal string and not a 

1649 SQL expression. 

1650 

1651 An expression such as:: 

1652 

1653 somecolumn.icontains("foo%bar", autoescape=True) 

1654 

1655 Will render as: 

1656 

1657 .. sourcecode:: sql 

1658 

1659 lower(somecolumn) LIKE '%' || lower(:param) || '%' ESCAPE '/' 

1660 

1661 With the value of ``:param`` as ``"foo/%bar"``. 

1662 

1663 :param escape: a character which when given will render with the 

1664 ``ESCAPE`` keyword to establish that character as the escape 

1665 character. This character can then be placed preceding occurrences 

1666 of ``%`` and ``_`` to allow them to act as themselves and not 

1667 wildcard characters. 

1668 

1669 An expression such as:: 

1670 

1671 somecolumn.icontains("foo/%bar", escape="^") 

1672 

1673 Will render as: 

1674 

1675 .. sourcecode:: sql 

1676 

1677 lower(somecolumn) LIKE '%' || lower(:param) || '%' ESCAPE '^' 

1678 

1679 The parameter may also be combined with 

1680 :paramref:`.ColumnOperators.contains.autoescape`:: 

1681 

1682 somecolumn.icontains("foo%bar^bat", escape="^", autoescape=True) 

1683 

1684 Where above, the given literal parameter will be converted to 

1685 ``"foo^%bar^^bat"`` before being passed to the database. 

1686 

1687 .. seealso:: 

1688 

1689 :meth:`.ColumnOperators.contains` 

1690 

1691 """ # noqa: E501 

1692 return self.operate(icontains_op, other, **kw) 

1693 

1694 def match(self, other: Any, **kwargs: Any) -> ColumnOperators: 

1695 """Implements a database-specific 'match' operator. 

1696 

1697 :meth:`_sql.ColumnOperators.match` attempts to resolve to 

1698 a MATCH-like function or operator provided by the backend. 

1699 Examples include: 

1700 

1701 * PostgreSQL - renders ``x @@ plainto_tsquery(y)`` 

1702 

1703 .. versionchanged:: 2.0 ``plainto_tsquery()`` is used instead 

1704 of ``to_tsquery()`` for PostgreSQL now; for compatibility with 

1705 other forms, see :ref:`postgresql_match`. 

1706 

1707 

1708 * MySQL - renders ``MATCH (x) AGAINST (y IN BOOLEAN MODE)`` 

1709 

1710 .. seealso:: 

1711 

1712 :class:`_mysql.match` - MySQL specific construct with 

1713 additional features. 

1714 

1715 * Oracle Database - renders ``CONTAINS(x, y)`` 

1716 * other backends may provide special implementations. 

1717 * Backends without any special implementation will emit 

1718 the operator as "MATCH". This is compatible with SQLite, for 

1719 example. 

1720 

1721 """ 

1722 return self.operate(match_op, other, **kwargs) 

1723 

1724 def regexp_match( 

1725 self, pattern: Any, flags: Optional[str] = None 

1726 ) -> ColumnOperators: 

1727 """Implements a database-specific 'regexp match' operator. 

1728 

1729 E.g.:: 

1730 

1731 stmt = select(table.c.some_column).where( 

1732 table.c.some_column.regexp_match("^(b|c)") 

1733 ) 

1734 

1735 :meth:`_sql.ColumnOperators.regexp_match` attempts to resolve to 

1736 a REGEXP-like function or operator provided by the backend, however 

1737 the specific regular expression syntax and flags available are 

1738 **not backend agnostic**. 

1739 

1740 Examples include: 

1741 

1742 * PostgreSQL - renders ``x ~ y`` or ``x !~ y`` when negated. 

1743 * Oracle Database - renders ``REGEXP_LIKE(x, y)`` 

1744 * SQLite - uses SQLite's ``REGEXP`` placeholder operator and calls into 

1745 the Python ``re.match()`` builtin. 

1746 * other backends may provide special implementations. 

1747 * Backends without any special implementation will emit 

1748 the operator as "REGEXP" or "NOT REGEXP". This is compatible with 

1749 SQLite and MySQL, for example. 

1750 

1751 Regular expression support is currently implemented for Oracle 

1752 Database, PostgreSQL, MySQL and MariaDB. Partial support is available 

1753 for SQLite. Support among third-party dialects may vary. 

1754 

1755 :param pattern: The regular expression pattern string or column 

1756 clause. 

1757 :param flags: Any regular expression string flags to apply, passed as 

1758 plain Python string only. These flags are backend specific. 

1759 Some backends, like PostgreSQL and MariaDB, may alternatively 

1760 specify the flags as part of the pattern. 

1761 When using the ignore case flag 'i' in PostgreSQL, the ignore case 

1762 regexp match operator ``~*`` or ``!~*`` will be used. 

1763 

1764 .. versionadded:: 1.4 

1765 

1766 .. versionchanged:: 1.4.48, 2.0.18 Note that due to an implementation 

1767 error, the "flags" parameter previously accepted SQL expression 

1768 objects such as column expressions in addition to plain Python 

1769 strings. This implementation did not work correctly with caching 

1770 and was removed; strings only should be passed for the "flags" 

1771 parameter, as these flags are rendered as literal inline values 

1772 within SQL expressions. 

1773 

1774 .. seealso:: 

1775 

1776 :meth:`_sql.ColumnOperators.regexp_replace` 

1777 

1778 

1779 """ 

1780 return self.operate(regexp_match_op, pattern, flags=flags) 

1781 

1782 def regexp_replace( 

1783 self, pattern: Any, replacement: Any, flags: Optional[str] = None 

1784 ) -> ColumnOperators: 

1785 """Implements a database-specific 'regexp replace' operator. 

1786 

1787 E.g.:: 

1788 

1789 stmt = select( 

1790 table.c.some_column.regexp_replace("b(..)", "X\1Y", flags="g") 

1791 ) 

1792 

1793 :meth:`_sql.ColumnOperators.regexp_replace` attempts to resolve to 

1794 a REGEXP_REPLACE-like function provided by the backend, that 

1795 usually emit the function ``REGEXP_REPLACE()``. However, 

1796 the specific regular expression syntax and flags available are 

1797 **not backend agnostic**. 

1798 

1799 Regular expression replacement support is currently implemented for 

1800 Oracle Database, PostgreSQL, MySQL 8 or greater and MariaDB. Support 

1801 among third-party dialects may vary. 

1802 

1803 :param pattern: The regular expression pattern string or column 

1804 clause. 

1805 :param pattern: The replacement string or column clause. 

1806 :param flags: Any regular expression string flags to apply, passed as 

1807 plain Python string only. These flags are backend specific. 

1808 Some backends, like PostgreSQL and MariaDB, may alternatively 

1809 specify the flags as part of the pattern. 

1810 

1811 .. versionadded:: 1.4 

1812 

1813 .. versionchanged:: 1.4.48, 2.0.18 Note that due to an implementation 

1814 error, the "flags" parameter previously accepted SQL expression 

1815 objects such as column expressions in addition to plain Python 

1816 strings. This implementation did not work correctly with caching 

1817 and was removed; strings only should be passed for the "flags" 

1818 parameter, as these flags are rendered as literal inline values 

1819 within SQL expressions. 

1820 

1821 

1822 .. seealso:: 

1823 

1824 :meth:`_sql.ColumnOperators.regexp_match` 

1825 

1826 """ 

1827 return self.operate( 

1828 regexp_replace_op, 

1829 pattern, 

1830 replacement=replacement, 

1831 flags=flags, 

1832 ) 

1833 

1834 def collate(self, collation: str) -> ColumnOperators: 

1835 """Produce a :func:`_expression.collate` clause against 

1836 the parent object, given the collation string. 

1837 

1838 .. seealso:: 

1839 

1840 :func:`_expression.collate` 

1841 

1842 """ 

1843 return self.operate(collate, collation) 

1844 

1845 def __radd__(self, other: Any) -> ColumnOperators: 

1846 """Implement the ``+`` operator in reverse. 

1847 

1848 See :meth:`.ColumnOperators.__add__`. 

1849 

1850 """ 

1851 return self.reverse_operate(add, other) 

1852 

1853 def __rsub__(self, other: Any) -> ColumnOperators: 

1854 """Implement the ``-`` operator in reverse. 

1855 

1856 See :meth:`.ColumnOperators.__sub__`. 

1857 

1858 """ 

1859 return self.reverse_operate(sub, other) 

1860 

1861 def __rmul__(self, other: Any) -> ColumnOperators: 

1862 """Implement the ``*`` operator in reverse. 

1863 

1864 See :meth:`.ColumnOperators.__mul__`. 

1865 

1866 """ 

1867 return self.reverse_operate(mul, other) 

1868 

1869 def __rmod__(self, other: Any) -> ColumnOperators: 

1870 """Implement the ``%`` operator in reverse. 

1871 

1872 See :meth:`.ColumnOperators.__mod__`. 

1873 

1874 """ 

1875 return self.reverse_operate(mod, other) 

1876 

1877 def between( 

1878 self, cleft: Any, cright: Any, symmetric: bool = False 

1879 ) -> ColumnOperators: 

1880 """Produce a :func:`_expression.between` clause against 

1881 the parent object, given the lower and upper range. 

1882 

1883 """ 

1884 return self.operate(between_op, cleft, cright, symmetric=symmetric) 

1885 

1886 def distinct(self) -> ColumnOperators: 

1887 """Produce a :func:`_expression.distinct` clause against the 

1888 parent object. 

1889 

1890 """ 

1891 return self.operate(distinct_op) 

1892 

1893 def any_(self) -> ColumnOperators: 

1894 """Produce an :func:`_expression.any_` clause against the 

1895 parent object. 

1896 

1897 See the documentation for :func:`_sql.any_` for examples. 

1898 

1899 .. note:: be sure to not confuse the newer 

1900 :meth:`_sql.ColumnOperators.any_` method with the **legacy** 

1901 version of this method, the :meth:`_types.ARRAY.Comparator.any` 

1902 method that's specific to :class:`_types.ARRAY`, which uses a 

1903 different calling style. 

1904 

1905 """ 

1906 return self.operate(any_op) 

1907 

1908 def all_(self) -> ColumnOperators: 

1909 """Produce an :func:`_expression.all_` clause against the 

1910 parent object. 

1911 

1912 See the documentation for :func:`_sql.all_` for examples. 

1913 

1914 .. note:: be sure to not confuse the newer 

1915 :meth:`_sql.ColumnOperators.all_` method with the **legacy** 

1916 version of this method, the :meth:`_types.ARRAY.Comparator.all` 

1917 method that's specific to :class:`_types.ARRAY`, which uses a 

1918 different calling style. 

1919 

1920 """ 

1921 return self.operate(all_op) 

1922 

1923 def __add__(self, other: Any) -> ColumnOperators: 

1924 """Implement the ``+`` operator. 

1925 

1926 In a column context, produces the clause ``a + b`` 

1927 if the parent object has non-string affinity. 

1928 If the parent object has a string affinity, 

1929 produces the concatenation operator, ``a || b`` - 

1930 see :meth:`.ColumnOperators.concat`. 

1931 

1932 """ 

1933 return self.operate(add, other) 

1934 

1935 def __sub__(self, other: Any) -> ColumnOperators: 

1936 """Implement the ``-`` operator. 

1937 

1938 In a column context, produces the clause ``a - b``. 

1939 

1940 """ 

1941 return self.operate(sub, other) 

1942 

1943 def __mul__(self, other: Any) -> ColumnOperators: 

1944 """Implement the ``*`` operator. 

1945 

1946 In a column context, produces the clause ``a * b``. 

1947 

1948 """ 

1949 return self.operate(mul, other) 

1950 

1951 def __mod__(self, other: Any) -> ColumnOperators: 

1952 """Implement the ``%`` operator. 

1953 

1954 In a column context, produces the clause ``a % b``. 

1955 

1956 """ 

1957 return self.operate(mod, other) 

1958 

1959 def __truediv__(self, other: Any) -> ColumnOperators: 

1960 """Implement the ``/`` operator. 

1961 

1962 In a column context, produces the clause ``a / b``, and 

1963 considers the result type to be numeric. 

1964 

1965 .. versionchanged:: 2.0 The truediv operator against two integers 

1966 is now considered to return a numeric value. Behavior on specific 

1967 backends may vary. 

1968 

1969 """ 

1970 return self.operate(truediv, other) 

1971 

1972 def __rtruediv__(self, other: Any) -> ColumnOperators: 

1973 """Implement the ``/`` operator in reverse. 

1974 

1975 See :meth:`.ColumnOperators.__truediv__`. 

1976 

1977 """ 

1978 return self.reverse_operate(truediv, other) 

1979 

1980 def __floordiv__(self, other: Any) -> ColumnOperators: 

1981 """Implement the ``//`` operator. 

1982 

1983 In a column context, produces the clause ``a / b``, 

1984 which is the same as "truediv", but considers the result 

1985 type to be integer. 

1986 

1987 .. versionadded:: 2.0 

1988 

1989 """ 

1990 return self.operate(floordiv, other) 

1991 

1992 def __rfloordiv__(self, other: Any) -> ColumnOperators: 

1993 """Implement the ``//`` operator in reverse. 

1994 

1995 See :meth:`.ColumnOperators.__floordiv__`. 

1996 

1997 """ 

1998 return self.reverse_operate(floordiv, other) 

1999 

2000 def __pow__(self, other: Any) -> ColumnOperators: 

2001 """Implement the ``**`` operator. 

2002 

2003 In a column context, produces the clause ``pow(a, b)``, or a similar 

2004 dialect-specific expression. 

2005 

2006 .. versionadded:: 2.1 

2007 

2008 """ 

2009 return self.operate(pow_, other) 

2010 

2011 def __rpow__(self, other: Any) -> ColumnOperators: 

2012 """Implement the ``**`` operator in reverse. 

2013 

2014 .. seealso:: 

2015 

2016 :meth:`.ColumnOperators.__pow__`. 

2017 

2018 .. versionadded:: 2.1 

2019 

2020 """ 

2021 return self.reverse_operate(pow_, other) 

2022 

2023 

2024_commutative: Set[Any] = {eq, ne, add, mul} 

2025_comparison: Set[Any] = {eq, ne, lt, gt, ge, le} 

2026 

2027 

2028def _operator_fn(fn: Callable[..., Any]) -> OperatorType: 

2029 return cast(OperatorType, fn) 

2030 

2031 

2032def commutative_op(fn: _FN) -> _FN: 

2033 _commutative.add(fn) 

2034 return fn 

2035 

2036 

2037def comparison_op(fn: _FN) -> _FN: 

2038 _comparison.add(fn) 

2039 return fn 

2040 

2041 

2042@_operator_fn 

2043def from_() -> Any: 

2044 raise NotImplementedError() 

2045 

2046 

2047@_operator_fn 

2048@comparison_op 

2049def function_as_comparison_op() -> Any: 

2050 raise NotImplementedError() 

2051 

2052 

2053@_operator_fn 

2054def as_() -> Any: 

2055 raise NotImplementedError() 

2056 

2057 

2058@_operator_fn 

2059def exists() -> Any: 

2060 raise NotImplementedError() 

2061 

2062 

2063@_operator_fn 

2064def is_true(a: Any) -> Any: 

2065 raise NotImplementedError() 

2066 

2067 

2068# 1.4 deprecated; see #5435 

2069if TYPE_CHECKING: 

2070 

2071 @_operator_fn 

2072 def istrue(a: Any) -> Any: ... 

2073 

2074else: 

2075 istrue = is_true 

2076 

2077 

2078@_operator_fn 

2079def is_false(a: Any) -> Any: 

2080 raise NotImplementedError() 

2081 

2082 

2083# 1.4 deprecated; see #5435 

2084if TYPE_CHECKING: 

2085 

2086 @_operator_fn 

2087 def isfalse(a: Any) -> Any: ... 

2088 

2089else: 

2090 isfalse = is_false 

2091 

2092 

2093@comparison_op 

2094@_operator_fn 

2095def is_distinct_from(a: Any, b: Any) -> Any: 

2096 return a.is_distinct_from(b) 

2097 

2098 

2099@comparison_op 

2100@_operator_fn 

2101def is_not_distinct_from(a: Any, b: Any) -> Any: 

2102 return a.is_not_distinct_from(b) 

2103 

2104 

2105# deprecated 1.4; see #5435 

2106if TYPE_CHECKING: 

2107 

2108 @_operator_fn 

2109 def isnot_distinct_from(a: Any, b: Any) -> Any: ... 

2110 

2111else: 

2112 isnot_distinct_from = is_not_distinct_from 

2113 

2114 

2115@comparison_op 

2116@_operator_fn 

2117def is_(a: Any, b: Any) -> Any: 

2118 return a.is_(b) 

2119 

2120 

2121@comparison_op 

2122@_operator_fn 

2123def is_not(a: Any, b: Any) -> Any: 

2124 return a.is_not(b) 

2125 

2126 

2127# 1.4 deprecated; see #5429 

2128if TYPE_CHECKING: 

2129 

2130 @_operator_fn 

2131 def isnot(a: Any, b: Any) -> Any: ... 

2132 

2133else: 

2134 isnot = is_not 

2135 

2136 

2137@_operator_fn 

2138def collate(a: Any, b: Any) -> Any: 

2139 return a.collate(b) 

2140 

2141 

2142@_operator_fn 

2143def op(a: Any, opstring: str, b: Any) -> Any: 

2144 return a.op(opstring)(b) 

2145 

2146 

2147@comparison_op 

2148@_operator_fn 

2149def like_op(a: Any, b: Any, escape: Optional[str] = None) -> Any: 

2150 return a.like(b, escape=escape) 

2151 

2152 

2153@comparison_op 

2154@_operator_fn 

2155def not_like_op(a: Any, b: Any, escape: Optional[str] = None) -> Any: 

2156 return a.notlike(b, escape=escape) 

2157 

2158 

2159# 1.4 deprecated; see #5435 

2160if TYPE_CHECKING: 

2161 

2162 @_operator_fn 

2163 def notlike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any: ... 

2164 

2165else: 

2166 notlike_op = not_like_op 

2167 

2168 

2169@comparison_op 

2170@_operator_fn 

2171def ilike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any: 

2172 return a.ilike(b, escape=escape) 

2173 

2174 

2175@comparison_op 

2176@_operator_fn 

2177def not_ilike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any: 

2178 return a.not_ilike(b, escape=escape) 

2179 

2180 

2181# 1.4 deprecated; see #5435 

2182if TYPE_CHECKING: 

2183 

2184 @_operator_fn 

2185 def notilike_op(a: Any, b: Any, escape: Optional[str] = None) -> Any: ... 

2186 

2187else: 

2188 notilike_op = not_ilike_op 

2189 

2190 

2191@comparison_op 

2192@_operator_fn 

2193def between_op(a: Any, b: Any, c: Any, symmetric: bool = False) -> Any: 

2194 return a.between(b, c, symmetric=symmetric) 

2195 

2196 

2197@comparison_op 

2198@_operator_fn 

2199def not_between_op(a: Any, b: Any, c: Any, symmetric: bool = False) -> Any: 

2200 return ~a.between(b, c, symmetric=symmetric) 

2201 

2202 

2203# 1.4 deprecated; see #5435 

2204if TYPE_CHECKING: 

2205 

2206 @_operator_fn 

2207 def notbetween_op( 

2208 a: Any, b: Any, c: Any, symmetric: bool = False 

2209 ) -> Any: ... 

2210 

2211else: 

2212 notbetween_op = not_between_op 

2213 

2214 

2215@comparison_op 

2216@_operator_fn 

2217def in_op(a: Any, b: Any) -> Any: 

2218 return a.in_(b) 

2219 

2220 

2221@comparison_op 

2222@_operator_fn 

2223def not_in_op(a: Any, b: Any) -> Any: 

2224 return a.not_in(b) 

2225 

2226 

2227# 1.4 deprecated; see #5429 

2228if TYPE_CHECKING: 

2229 

2230 @_operator_fn 

2231 def notin_op(a: Any, b: Any) -> Any: ... 

2232 

2233else: 

2234 notin_op = not_in_op 

2235 

2236 

2237@_operator_fn 

2238def distinct_op(a: Any) -> Any: 

2239 return a.distinct() 

2240 

2241 

2242@_operator_fn 

2243def any_op(a: Any) -> Any: 

2244 return a.any_() 

2245 

2246 

2247@_operator_fn 

2248def all_op(a: Any) -> Any: 

2249 return a.all_() 

2250 

2251 

2252def _escaped_like_impl( 

2253 fn: Callable[..., Any], other: Any, escape: Optional[str], autoescape: bool 

2254) -> Any: 

2255 if autoescape: 

2256 if autoescape is not True: 

2257 util.warn( 

2258 "The autoescape parameter is now a simple boolean True/False" 

2259 ) 

2260 if escape is None: 

2261 escape = "/" 

2262 

2263 if not isinstance(other, str): 

2264 raise TypeError("String value expected when autoescape=True") 

2265 

2266 if escape not in ("%", "_"): 

2267 other = other.replace(escape, escape + escape) 

2268 

2269 other = other.replace("%", escape + "%").replace("_", escape + "_") 

2270 

2271 return fn(other, escape=escape) 

2272 

2273 

2274@comparison_op 

2275@_operator_fn 

2276def startswith_op( 

2277 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2278) -> Any: 

2279 return _escaped_like_impl(a.startswith, b, escape, autoescape) 

2280 

2281 

2282@comparison_op 

2283@_operator_fn 

2284def not_startswith_op( 

2285 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2286) -> Any: 

2287 return ~_escaped_like_impl(a.startswith, b, escape, autoescape) 

2288 

2289 

2290# 1.4 deprecated; see #5435 

2291if TYPE_CHECKING: 

2292 

2293 @_operator_fn 

2294 def notstartswith_op( 

2295 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2296 ) -> Any: ... 

2297 

2298else: 

2299 notstartswith_op = not_startswith_op 

2300 

2301 

2302@comparison_op 

2303@_operator_fn 

2304def istartswith_op( 

2305 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2306) -> Any: 

2307 return _escaped_like_impl(a.istartswith, b, escape, autoescape) 

2308 

2309 

2310@comparison_op 

2311@_operator_fn 

2312def not_istartswith_op( 

2313 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2314) -> Any: 

2315 return ~_escaped_like_impl(a.istartswith, b, escape, autoescape) 

2316 

2317 

2318@comparison_op 

2319@_operator_fn 

2320def endswith_op( 

2321 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2322) -> Any: 

2323 return _escaped_like_impl(a.endswith, b, escape, autoescape) 

2324 

2325 

2326@comparison_op 

2327@_operator_fn 

2328def not_endswith_op( 

2329 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2330) -> Any: 

2331 return ~_escaped_like_impl(a.endswith, b, escape, autoescape) 

2332 

2333 

2334# 1.4 deprecated; see #5435 

2335if TYPE_CHECKING: 

2336 

2337 @_operator_fn 

2338 def notendswith_op( 

2339 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2340 ) -> Any: ... 

2341 

2342else: 

2343 notendswith_op = not_endswith_op 

2344 

2345 

2346@comparison_op 

2347@_operator_fn 

2348def iendswith_op( 

2349 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2350) -> Any: 

2351 return _escaped_like_impl(a.iendswith, b, escape, autoescape) 

2352 

2353 

2354@comparison_op 

2355@_operator_fn 

2356def not_iendswith_op( 

2357 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2358) -> Any: 

2359 return ~_escaped_like_impl(a.iendswith, b, escape, autoescape) 

2360 

2361 

2362@comparison_op 

2363@_operator_fn 

2364def contains_op( 

2365 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2366) -> Any: 

2367 return _escaped_like_impl(a.contains, b, escape, autoescape) 

2368 

2369 

2370@comparison_op 

2371@_operator_fn 

2372def not_contains_op( 

2373 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2374) -> Any: 

2375 return ~_escaped_like_impl(a.contains, b, escape, autoescape) 

2376 

2377 

2378# 1.4 deprecated; see #5435 

2379if TYPE_CHECKING: 

2380 

2381 @_operator_fn 

2382 def notcontains_op( 

2383 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2384 ) -> Any: ... 

2385 

2386else: 

2387 notcontains_op = not_contains_op 

2388 

2389 

2390@comparison_op 

2391@_operator_fn 

2392def icontains_op( 

2393 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2394) -> Any: 

2395 return _escaped_like_impl(a.icontains, b, escape, autoescape) 

2396 

2397 

2398@comparison_op 

2399@_operator_fn 

2400def not_icontains_op( 

2401 a: Any, b: Any, escape: Optional[str] = None, autoescape: bool = False 

2402) -> Any: 

2403 return ~_escaped_like_impl(a.icontains, b, escape, autoescape) 

2404 

2405 

2406@comparison_op 

2407@_operator_fn 

2408def match_op(a: Any, b: Any, **kw: Any) -> Any: 

2409 return a.match(b, **kw) 

2410 

2411 

2412@comparison_op 

2413@_operator_fn 

2414def regexp_match_op(a: Any, b: Any, flags: Optional[str] = None) -> Any: 

2415 return a.regexp_match(b, flags=flags) 

2416 

2417 

2418@comparison_op 

2419@_operator_fn 

2420def not_regexp_match_op(a: Any, b: Any, flags: Optional[str] = None) -> Any: 

2421 return ~a.regexp_match(b, flags=flags) 

2422 

2423 

2424@_operator_fn 

2425def regexp_replace_op( 

2426 a: Any, b: Any, replacement: Any, flags: Optional[str] = None 

2427) -> Any: 

2428 return a.regexp_replace(b, replacement=replacement, flags=flags) 

2429 

2430 

2431@comparison_op 

2432@_operator_fn 

2433def not_match_op(a: Any, b: Any, **kw: Any) -> Any: 

2434 return ~a.match(b, **kw) 

2435 

2436 

2437# 1.4 deprecated; see #5429 

2438if TYPE_CHECKING: 

2439 

2440 @_operator_fn 

2441 def notmatch_op(a: Any, b: Any, **kw: Any) -> Any: ... 

2442 

2443else: 

2444 notmatch_op = not_match_op 

2445 

2446 

2447@_operator_fn 

2448def comma_op(a: Any, b: Any) -> Any: 

2449 raise NotImplementedError() 

2450 

2451 

2452@_operator_fn 

2453def filter_op(a: Any, b: Any) -> Any: 

2454 raise NotImplementedError() 

2455 

2456 

2457@_operator_fn 

2458def concat_op(a: Any, b: Any) -> Any: 

2459 try: 

2460 concat = a.concat 

2461 except AttributeError: 

2462 return b._rconcat(a) 

2463 else: 

2464 return concat(b) 

2465 

2466 

2467@_operator_fn 

2468def desc_op(a: Any) -> Any: 

2469 return a.desc() 

2470 

2471 

2472@_operator_fn 

2473def asc_op(a: Any) -> Any: 

2474 return a.asc() 

2475 

2476 

2477@_operator_fn 

2478def nulls_first_op(a: Any) -> Any: 

2479 return a.nulls_first() 

2480 

2481 

2482# 1.4 deprecated; see #5435 

2483if TYPE_CHECKING: 

2484 

2485 @_operator_fn 

2486 def nullsfirst_op(a: Any) -> Any: ... 

2487 

2488else: 

2489 nullsfirst_op = nulls_first_op 

2490 

2491 

2492@_operator_fn 

2493def nulls_last_op(a: Any) -> Any: 

2494 return a.nulls_last() 

2495 

2496 

2497# 1.4 deprecated; see #5435 

2498if TYPE_CHECKING: 

2499 

2500 @_operator_fn 

2501 def nullslast_op(a: Any) -> Any: ... 

2502 

2503else: 

2504 nullslast_op = nulls_last_op 

2505 

2506 

2507@_operator_fn 

2508def json_getitem_op(a: Any, b: Any) -> Any: 

2509 raise NotImplementedError() 

2510 

2511 

2512@_operator_fn 

2513def json_path_getitem_op(a: Any, b: Any) -> Any: 

2514 raise NotImplementedError() 

2515 

2516 

2517@_operator_fn 

2518def bitwise_xor_op(a: Any, b: Any) -> Any: 

2519 return a.bitwise_xor(b) 

2520 

2521 

2522@_operator_fn 

2523def bitwise_or_op(a: Any, b: Any) -> Any: 

2524 return a.bitwise_or(b) 

2525 

2526 

2527@_operator_fn 

2528def bitwise_and_op(a: Any, b: Any) -> Any: 

2529 return a.bitwise_and(b) 

2530 

2531 

2532@_operator_fn 

2533def bitwise_not_op(a: Any) -> Any: 

2534 return a.bitwise_not() 

2535 

2536 

2537@_operator_fn 

2538def bitwise_lshift_op(a: Any, b: Any) -> Any: 

2539 return a.bitwise_lshift(b) 

2540 

2541 

2542@_operator_fn 

2543def bitwise_rshift_op(a: Any, b: Any) -> Any: 

2544 return a.bitwise_rshift(b) 

2545 

2546 

2547def is_comparison(op: OperatorType) -> bool: 

2548 return op in _comparison or isinstance(op, custom_op) and op.is_comparison 

2549 

2550 

2551def is_commutative(op: OperatorType) -> bool: 

2552 return op in _commutative 

2553 

2554 

2555def is_ordering_modifier(op: OperatorType) -> bool: 

2556 return op in (asc_op, desc_op, nulls_first_op, nulls_last_op) 

2557 

2558 

2559def is_natural_self_precedent(op: OperatorType) -> bool: 

2560 return ( 

2561 op in _natural_self_precedent 

2562 or isinstance(op, custom_op) 

2563 and op.natural_self_precedent 

2564 ) 

2565 

2566 

2567_booleans = (inv, is_true, is_false, and_, or_) 

2568 

2569 

2570def is_boolean(op: OperatorType) -> bool: 

2571 return is_comparison(op) or op in _booleans 

2572 

2573 

2574_mirror = {gt: lt, ge: le, lt: gt, le: ge} 

2575 

2576 

2577def mirror(op: OperatorType) -> OperatorType: 

2578 """rotate a comparison operator 180 degrees. 

2579 

2580 Note this is not the same as negation. 

2581 

2582 """ 

2583 return _mirror.get(op, op) 

2584 

2585 

2586_associative = _commutative.union([concat_op, and_, or_]).difference([eq, ne]) 

2587 

2588 

2589def is_associative(op: OperatorType) -> bool: 

2590 return op in _associative 

2591 

2592 

2593def is_order_by_modifier(op: Optional[OperatorType]) -> bool: 

2594 return op in _order_by_modifier 

2595 

2596 

2597_order_by_modifier = {desc_op, asc_op, nulls_first_op, nulls_last_op} 

2598 

2599_natural_self_precedent = _associative.union( 

2600 [getitem, json_getitem_op, json_path_getitem_op] 

2601) 

2602"""Operators where if we have (a op b) op c, we don't want to 

2603parenthesize (a op b). 

2604 

2605""" 

2606 

2607 

2608@_operator_fn 

2609def _asbool(a: Any) -> Any: 

2610 raise NotImplementedError() 

2611 

2612 

2613class _OpLimit(IntEnum): 

2614 _smallest = -100 

2615 _largest = 100 

2616 

2617 

2618_PRECEDENCE: Dict[OperatorType, int] = { 

2619 from_: 15, 

2620 function_as_comparison_op: 15, 

2621 any_op: 15, 

2622 all_op: 15, 

2623 getitem: 15, 

2624 json_getitem_op: 15, 

2625 json_path_getitem_op: 15, 

2626 pow_: 15, 

2627 mul: 8, 

2628 truediv: 8, 

2629 floordiv: 8, 

2630 mod: 8, 

2631 neg: 8, 

2632 bitwise_not_op: 8, 

2633 add: 7, 

2634 sub: 7, 

2635 bitwise_xor_op: 7, 

2636 bitwise_or_op: 7, 

2637 bitwise_and_op: 7, 

2638 bitwise_lshift_op: 7, 

2639 bitwise_rshift_op: 7, 

2640 filter_op: 6, 

2641 concat_op: 5, 

2642 match_op: 5, 

2643 not_match_op: 5, 

2644 regexp_match_op: 5, 

2645 not_regexp_match_op: 5, 

2646 regexp_replace_op: 5, 

2647 ilike_op: 5, 

2648 not_ilike_op: 5, 

2649 like_op: 5, 

2650 not_like_op: 5, 

2651 in_op: 5, 

2652 not_in_op: 5, 

2653 is_: 5, 

2654 is_not: 5, 

2655 eq: 5, 

2656 ne: 5, 

2657 is_distinct_from: 5, 

2658 is_not_distinct_from: 5, 

2659 gt: 5, 

2660 lt: 5, 

2661 ge: 5, 

2662 le: 5, 

2663 between_op: 5, 

2664 not_between_op: 5, 

2665 distinct_op: 5, 

2666 inv: 5, 

2667 is_true: 5, 

2668 is_false: 5, 

2669 and_: 3, 

2670 or_: 2, 

2671 comma_op: -1, 

2672 desc_op: 3, 

2673 asc_op: 3, 

2674 collate: 4, 

2675 as_: -1, 

2676 exists: 0, 

2677 _asbool: -10, 

2678} 

2679 

2680 

2681def is_precedent( 

2682 operator: OperatorType, against: Optional[OperatorType] 

2683) -> bool: 

2684 if operator is against and is_natural_self_precedent(operator): 

2685 return False 

2686 elif against is None: 

2687 return True 

2688 else: 

2689 return bool( 

2690 _PRECEDENCE.get( 

2691 operator, getattr(operator, "precedence", _OpLimit._smallest) 

2692 ) 

2693 <= _PRECEDENCE.get( 

2694 against, getattr(against, "precedence", _OpLimit._largest) 

2695 ) 

2696 )