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

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

600 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 Optional 

45from typing import overload 

46from typing import Protocol 

47from typing import Set 

48from typing import Tuple 

49from typing import Type 

50from typing import TYPE_CHECKING 

51from typing import TypeVar 

52from typing import Union 

53 

54from .. import exc 

55from .. import util 

56from ..util.typing import Literal 

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 ColumnOperators(Operators): 

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

504 :class:`_expression.ColumnElement` expressions. 

505 

506 By default, all methods call down to 

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

508 passing in the appropriate operator function from the 

509 Python builtin ``operator`` module or 

510 a SQLAlchemy-specific operator function from 

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

512 the ``__eq__`` function:: 

513 

514 def __eq__(self, other): 

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

516 

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

518 

519 def eq(a, b): 

520 return a == b 

521 

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

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

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

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

526 construct. 

527 

528 .. seealso:: 

529 

530 :ref:`types_operators` 

531 

532 :attr:`.TypeEngine.comparator_factory` 

533 

534 :class:`.ColumnOperators` 

535 

536 :class:`.PropComparator` 

537 

538 """ 

539 

540 __slots__ = () 

541 

542 timetuple: Literal[None] = None 

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

544 

545 if typing.TYPE_CHECKING: 

546 

547 def operate( 

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

549 ) -> ColumnOperators: ... 

550 

551 def reverse_operate( 

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

553 ) -> ColumnOperators: ... 

554 

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

556 """Implement the ``<`` operator. 

557 

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

559 

560 """ 

561 return self.operate(lt, other) 

562 

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

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

565 

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

567 

568 """ 

569 return self.operate(le, other) 

570 

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

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

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

574 if TYPE_CHECKING: 

575 

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

577 

578 else: 

579 __hash__ = Operators.__hash__ 

580 

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

582 """Implement the ``==`` operator. 

583 

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

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

586 

587 """ 

588 return self.operate(eq, other) 

589 

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

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

592 

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

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

595 

596 """ 

597 return self.operate(ne, other) 

598 

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

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

601 

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

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

604 

605 """ 

606 return self.operate(is_distinct_from, other) 

607 

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

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

610 

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

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

613 

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

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

616 The previous name remains available for backwards compatibility. 

617 

618 """ 

619 return self.operate(is_not_distinct_from, other) 

620 

621 # deprecated 1.4; see #5435 

622 if TYPE_CHECKING: 

623 

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

625 

626 else: 

627 isnot_distinct_from = is_not_distinct_from 

628 

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

630 """Implement the ``>`` operator. 

631 

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

633 

634 """ 

635 return self.operate(gt, other) 

636 

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

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

639 

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

641 

642 """ 

643 return self.operate(ge, other) 

644 

645 def __neg__(self) -> ColumnOperators: 

646 """Implement the ``-`` operator. 

647 

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

649 

650 """ 

651 return self.operate(neg) 

652 

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

654 return self.operate(contains, other) 

655 

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

657 """Implement the [] operator. 

658 

659 This can be used by some database-specific types 

660 such as PostgreSQL ARRAY and HSTORE. 

661 

662 """ 

663 return self.operate(getitem, index) 

664 

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

666 """Implement the ``<<`` operator. 

667 

668 Not used by SQLAlchemy core, this is provided 

669 for custom operator systems which want to use 

670 << as an extension point. 

671 """ 

672 return self.operate(lshift, other) 

673 

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

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

676 

677 Not used by SQLAlchemy core, this is provided 

678 for custom operator systems which want to use 

679 << as an extension point. 

680 """ 

681 return self.reverse_operate(lshift, other) 

682 

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

684 """Implement the ``>>`` operator. 

685 

686 Not used by SQLAlchemy core, this is provided 

687 for custom operator systems which want to use 

688 >> as an extension point. 

689 """ 

690 return self.operate(rshift, other) 

691 

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

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

694 

695 Not used by SQLAlchemy core, this is provided 

696 for custom operator systems which want to use 

697 >> as an extension point. 

698 """ 

699 return self.reverse_operate(rshift, other) 

700 

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

702 """Implement the ``@`` operator. 

703 

704 Not used by SQLAlchemy core, this is provided 

705 for custom operator systems which want to use 

706 @ as an extension point. 

707 """ 

708 return self.operate(matmul, other) 

709 

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

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

712 

713 Not used by SQLAlchemy core, this is provided 

714 for custom operator systems which want to use 

715 @ as an extension point. 

716 """ 

717 return self.reverse_operate(matmul, other) 

718 

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

720 """Implement the 'concat' operator. 

721 

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

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

724 

725 """ 

726 return self.operate(concat_op, other) 

727 

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

729 """Implement an 'rconcat' operator. 

730 

731 this is for internal use at the moment 

732 

733 .. versionadded:: 1.4.40 

734 

735 """ 

736 return self.reverse_operate(concat_op, other) 

737 

738 def like( 

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

740 ) -> ColumnOperators: 

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

742 

743 In a column context, produces the expression: 

744 

745 .. sourcecode:: sql 

746 

747 a LIKE other 

748 

749 E.g.:: 

750 

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

752 

753 :param other: expression to be compared 

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

755 keyword, e.g.:: 

756 

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

758 

759 .. seealso:: 

760 

761 :meth:`.ColumnOperators.ilike` 

762 

763 """ 

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

765 

766 def ilike( 

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

768 ) -> ColumnOperators: 

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

770 

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

772 

773 .. sourcecode:: sql 

774 

775 lower(a) LIKE lower(other) 

776 

777 Or on backends that support the ILIKE operator: 

778 

779 .. sourcecode:: sql 

780 

781 a ILIKE other 

782 

783 E.g.:: 

784 

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

786 

787 :param other: expression to be compared 

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

789 keyword, e.g.:: 

790 

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

792 

793 .. seealso:: 

794 

795 :meth:`.ColumnOperators.like` 

796 

797 """ # noqa: E501 

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

799 

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

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

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

803 

804 .. versionadded:: 2.0.2 

805 

806 .. seealso:: 

807 

808 :ref:`operators_bitwise` 

809 

810 """ 

811 

812 return self.operate(bitwise_xor_op, other) 

813 

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

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

816 operator. 

817 

818 .. versionadded:: 2.0.2 

819 

820 .. seealso:: 

821 

822 :ref:`operators_bitwise` 

823 

824 """ 

825 

826 return self.operate(bitwise_or_op, other) 

827 

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

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

830 operator. 

831 

832 .. versionadded:: 2.0.2 

833 

834 .. seealso:: 

835 

836 :ref:`operators_bitwise` 

837 

838 """ 

839 

840 return self.operate(bitwise_and_op, other) 

841 

842 def bitwise_not(self) -> ColumnOperators: 

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

844 operator. 

845 

846 .. versionadded:: 2.0.2 

847 

848 .. seealso:: 

849 

850 :ref:`operators_bitwise` 

851 

852 """ 

853 

854 return self.operate(bitwise_not_op) 

855 

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

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

858 operator. 

859 

860 .. versionadded:: 2.0.2 

861 

862 .. seealso:: 

863 

864 :ref:`operators_bitwise` 

865 

866 """ 

867 

868 return self.operate(bitwise_lshift_op, other) 

869 

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

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

872 operator. 

873 

874 .. versionadded:: 2.0.2 

875 

876 .. seealso:: 

877 

878 :ref:`operators_bitwise` 

879 

880 """ 

881 

882 return self.operate(bitwise_rshift_op, other) 

883 

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

885 """Implement the ``in`` operator. 

886 

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

888 

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

890 

891 * A list of literal values, 

892 e.g.:: 

893 

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

895 

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

897 bound parameters the same length as the list given: 

898 

899 .. sourcecode:: sql 

900 

901 WHERE COL IN (?, ?, ?) 

902 

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

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

905 

906 from sqlalchemy import tuple_ 

907 

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

909 

910 * An empty list, 

911 e.g.:: 

912 

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

914 

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

916 expression. These expressions are tailored to individual backends 

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

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

919 

920 .. sourcecode:: sql 

921 

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

923 

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

925 execution-time generated SELECT subquery in all cases. 

926 

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

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

929 

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

931 

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

933 placeholder expression that looks like: 

934 

935 .. sourcecode:: sql 

936 

937 WHERE COL IN ([EXPANDING_value]) 

938 

939 This placeholder expression is intercepted at statement execution 

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

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

942 

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

944 

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

946 

947 .. sourcecode:: sql 

948 

949 WHERE COL IN (?, ?, ?) 

950 

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

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

953 SQLite this would be: 

954 

955 .. sourcecode:: sql 

956 

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

958 

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

960 correlated scalar select:: 

961 

962 stmt.where( 

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

964 ) 

965 

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

967 

968 .. sourcecode:: sql 

969 

970 WHERE COL IN (SELECT othertable.y 

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

972 

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

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

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

976 

977 """ # noqa: E501 

978 return self.operate(in_op, other) 

979 

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

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

982 

983 This is equivalent to using negation with 

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

985 

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

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

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

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

990 alter this behavior. 

991 

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

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

994 available for backwards compatibility. 

995 

996 .. seealso:: 

997 

998 :meth:`.ColumnOperators.in_` 

999 

1000 """ 

1001 return self.operate(not_in_op, other) 

1002 

1003 # deprecated 1.4; see #5429 

1004 if TYPE_CHECKING: 

1005 

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

1007 

1008 else: 

1009 notin_ = not_in 

1010 

1011 def not_like( 

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

1013 ) -> ColumnOperators: 

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

1015 

1016 This is equivalent to using negation with 

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

1018 

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

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

1021 available for backwards compatibility. 

1022 

1023 .. seealso:: 

1024 

1025 :meth:`.ColumnOperators.like` 

1026 

1027 """ 

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

1029 

1030 # deprecated 1.4; see #5435 

1031 if TYPE_CHECKING: 

1032 

1033 def notlike( 

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

1035 ) -> ColumnOperators: ... 

1036 

1037 else: 

1038 notlike = not_like 

1039 

1040 def not_ilike( 

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

1042 ) -> ColumnOperators: 

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

1044 

1045 This is equivalent to using negation with 

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

1047 

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

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

1050 available for backwards compatibility. 

1051 

1052 .. seealso:: 

1053 

1054 :meth:`.ColumnOperators.ilike` 

1055 

1056 """ 

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

1058 

1059 # deprecated 1.4; see #5435 

1060 if TYPE_CHECKING: 

1061 

1062 def notilike( 

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

1064 ) -> ColumnOperators: ... 

1065 

1066 else: 

1067 notilike = not_ilike 

1068 

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

1070 """Implement the ``IS`` operator. 

1071 

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

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

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

1075 on certain platforms. 

1076 

1077 .. seealso:: :meth:`.ColumnOperators.is_not` 

1078 

1079 """ 

1080 return self.operate(is_, other) 

1081 

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

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

1084 

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

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

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

1088 on certain platforms. 

1089 

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

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

1092 available for backwards compatibility. 

1093 

1094 .. seealso:: :meth:`.ColumnOperators.is_` 

1095 

1096 """ 

1097 return self.operate(is_not, other) 

1098 

1099 # deprecated 1.4; see #5429 

1100 if TYPE_CHECKING: 

1101 

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

1103 

1104 else: 

1105 isnot = is_not 

1106 

1107 def startswith( 

1108 self, 

1109 other: Any, 

1110 escape: Optional[str] = None, 

1111 autoescape: bool = False, 

1112 ) -> ColumnOperators: 

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

1114 

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

1116 of a string value: 

1117 

1118 .. sourcecode:: sql 

1119 

1120 column LIKE <other> || '%' 

1121 

1122 E.g.:: 

1123 

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

1125 

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

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

1128 will behave like wildcards as well. For literal string 

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

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

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

1132 and not as wildcard characters. Alternatively, the 

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

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

1135 the target expression is not a literal string. 

1136 

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

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

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

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

1141 set to True. 

1142 

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

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

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

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

1147 SQL expression. 

1148 

1149 An expression such as:: 

1150 

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

1152 

1153 Will render as: 

1154 

1155 .. sourcecode:: sql 

1156 

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

1158 

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

1160 

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

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

1163 character. This character can then be placed preceding occurrences 

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

1165 wildcard characters. 

1166 

1167 An expression such as:: 

1168 

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

1170 

1171 Will render as: 

1172 

1173 .. sourcecode:: sql 

1174 

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

1176 

1177 The parameter may also be combined with 

1178 :paramref:`.ColumnOperators.startswith.autoescape`:: 

1179 

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

1181 

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

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

1184 

1185 .. seealso:: 

1186 

1187 :meth:`.ColumnOperators.endswith` 

1188 

1189 :meth:`.ColumnOperators.contains` 

1190 

1191 :meth:`.ColumnOperators.like` 

1192 

1193 """ # noqa: E501 

1194 return self.operate( 

1195 startswith_op, other, escape=escape, autoescape=autoescape 

1196 ) 

1197 

1198 def istartswith( 

1199 self, 

1200 other: Any, 

1201 escape: Optional[str] = None, 

1202 autoescape: bool = False, 

1203 ) -> ColumnOperators: 

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

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

1206 

1207 Produces a LIKE expression that tests against an insensitive 

1208 match for the start of a string value: 

1209 

1210 .. sourcecode:: sql 

1211 

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

1213 

1214 E.g.:: 

1215 

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

1217 

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

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

1220 will behave like wildcards as well. For literal string 

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

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

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

1224 and not as wildcard characters. Alternatively, the 

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

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

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

1228 

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

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

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

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

1233 set to True. 

1234 

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

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

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

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

1239 SQL expression. 

1240 

1241 An expression such as:: 

1242 

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

1244 

1245 Will render as: 

1246 

1247 .. sourcecode:: sql 

1248 

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

1250 

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

1252 

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

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

1255 character. This character can then be placed preceding occurrences 

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

1257 wildcard characters. 

1258 

1259 An expression such as:: 

1260 

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

1262 

1263 Will render as: 

1264 

1265 .. sourcecode:: sql 

1266 

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

1268 

1269 The parameter may also be combined with 

1270 :paramref:`.ColumnOperators.istartswith.autoescape`:: 

1271 

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

1273 

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

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

1276 

1277 .. seealso:: 

1278 

1279 :meth:`.ColumnOperators.startswith` 

1280 """ # noqa: E501 

1281 return self.operate( 

1282 istartswith_op, other, escape=escape, autoescape=autoescape 

1283 ) 

1284 

1285 def endswith( 

1286 self, 

1287 other: Any, 

1288 escape: Optional[str] = None, 

1289 autoescape: bool = False, 

1290 ) -> ColumnOperators: 

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

1292 

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

1294 of a string value: 

1295 

1296 .. sourcecode:: sql 

1297 

1298 column LIKE '%' || <other> 

1299 

1300 E.g.:: 

1301 

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

1303 

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

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

1306 will behave like wildcards as well. For literal string 

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

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

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

1310 and not as wildcard characters. Alternatively, the 

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

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

1313 the target expression is not a literal string. 

1314 

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

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

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

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

1319 set to True. 

1320 

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

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

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

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

1325 SQL expression. 

1326 

1327 An expression such as:: 

1328 

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

1330 

1331 Will render as: 

1332 

1333 .. sourcecode:: sql 

1334 

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

1336 

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

1338 

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

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

1341 character. This character can then be placed preceding occurrences 

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

1343 wildcard characters. 

1344 

1345 An expression such as:: 

1346 

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

1348 

1349 Will render as: 

1350 

1351 .. sourcecode:: sql 

1352 

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

1354 

1355 The parameter may also be combined with 

1356 :paramref:`.ColumnOperators.endswith.autoescape`:: 

1357 

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

1359 

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

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

1362 

1363 .. seealso:: 

1364 

1365 :meth:`.ColumnOperators.startswith` 

1366 

1367 :meth:`.ColumnOperators.contains` 

1368 

1369 :meth:`.ColumnOperators.like` 

1370 

1371 """ # noqa: E501 

1372 return self.operate( 

1373 endswith_op, other, escape=escape, autoescape=autoescape 

1374 ) 

1375 

1376 def iendswith( 

1377 self, 

1378 other: Any, 

1379 escape: Optional[str] = None, 

1380 autoescape: bool = False, 

1381 ) -> ColumnOperators: 

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

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

1384 

1385 Produces a LIKE expression that tests against an insensitive match 

1386 for the end of a string value: 

1387 

1388 .. sourcecode:: sql 

1389 

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

1391 

1392 E.g.:: 

1393 

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

1395 

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

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

1398 will behave like wildcards as well. For literal string 

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

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

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

1402 and not as wildcard characters. Alternatively, the 

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

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

1405 the target expression is not a literal string. 

1406 

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

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

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

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

1411 set to True. 

1412 

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

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

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

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

1417 SQL expression. 

1418 

1419 An expression such as:: 

1420 

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

1422 

1423 Will render as: 

1424 

1425 .. sourcecode:: sql 

1426 

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

1428 

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

1430 

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

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

1433 character. This character can then be placed preceding occurrences 

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

1435 wildcard characters. 

1436 

1437 An expression such as:: 

1438 

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

1440 

1441 Will render as: 

1442 

1443 .. sourcecode:: sql 

1444 

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

1446 

1447 The parameter may also be combined with 

1448 :paramref:`.ColumnOperators.iendswith.autoescape`:: 

1449 

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

1451 

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

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

1454 

1455 .. seealso:: 

1456 

1457 :meth:`.ColumnOperators.endswith` 

1458 """ # noqa: E501 

1459 return self.operate( 

1460 iendswith_op, other, escape=escape, autoescape=autoescape 

1461 ) 

1462 

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

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

1465 

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

1467 of a string value: 

1468 

1469 .. sourcecode:: sql 

1470 

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

1472 

1473 E.g.:: 

1474 

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

1476 

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

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

1479 will behave like wildcards as well. For literal string 

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

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

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

1483 and not as wildcard characters. Alternatively, the 

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

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

1486 the target expression is not a literal string. 

1487 

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

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

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

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

1492 set to True. 

1493 

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

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

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

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

1498 SQL expression. 

1499 

1500 An expression such as:: 

1501 

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

1503 

1504 Will render as: 

1505 

1506 .. sourcecode:: sql 

1507 

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

1509 

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

1511 

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

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

1514 character. This character can then be placed preceding occurrences 

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

1516 wildcard characters. 

1517 

1518 An expression such as:: 

1519 

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

1521 

1522 Will render as: 

1523 

1524 .. sourcecode:: sql 

1525 

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

1527 

1528 The parameter may also be combined with 

1529 :paramref:`.ColumnOperators.contains.autoescape`:: 

1530 

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

1532 

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

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

1535 

1536 .. seealso:: 

1537 

1538 :meth:`.ColumnOperators.startswith` 

1539 

1540 :meth:`.ColumnOperators.endswith` 

1541 

1542 :meth:`.ColumnOperators.like` 

1543 

1544 

1545 """ # noqa: E501 

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

1547 

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

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

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

1551 

1552 Produces a LIKE expression that tests against an insensitive match 

1553 for the middle of a string value: 

1554 

1555 .. sourcecode:: sql 

1556 

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

1558 

1559 E.g.:: 

1560 

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

1562 

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

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

1565 will behave like wildcards as well. For literal string 

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

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

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

1569 and not as wildcard characters. Alternatively, the 

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

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

1572 the target expression is not a literal string. 

1573 

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

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

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

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

1578 set to True. 

1579 

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

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

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

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

1584 SQL expression. 

1585 

1586 An expression such as:: 

1587 

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

1589 

1590 Will render as: 

1591 

1592 .. sourcecode:: sql 

1593 

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

1595 

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

1597 

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

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

1600 character. This character can then be placed preceding occurrences 

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

1602 wildcard characters. 

1603 

1604 An expression such as:: 

1605 

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

1607 

1608 Will render as: 

1609 

1610 .. sourcecode:: sql 

1611 

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

1613 

1614 The parameter may also be combined with 

1615 :paramref:`.ColumnOperators.contains.autoescape`:: 

1616 

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

1618 

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

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

1621 

1622 .. seealso:: 

1623 

1624 :meth:`.ColumnOperators.contains` 

1625 

1626 """ # noqa: E501 

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

1628 

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

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

1631 

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

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

1634 Examples include: 

1635 

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

1637 

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

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

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

1641 

1642 

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

1644 

1645 .. seealso:: 

1646 

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

1648 additional features. 

1649 

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

1651 * other backends may provide special implementations. 

1652 * Backends without any special implementation will emit 

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

1654 example. 

1655 

1656 """ 

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

1658 

1659 def regexp_match( 

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

1661 ) -> ColumnOperators: 

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

1663 

1664 E.g.:: 

1665 

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

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

1668 ) 

1669 

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

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

1672 the specific regular expression syntax and flags available are 

1673 **not backend agnostic**. 

1674 

1675 Examples include: 

1676 

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

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

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

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

1681 * other backends may provide special implementations. 

1682 * Backends without any special implementation will emit 

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

1684 SQLite and MySQL, for example. 

1685 

1686 Regular expression support is currently implemented for Oracle 

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

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

1689 

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

1691 clause. 

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

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

1694 Some backends, like PostgreSQL and MariaDB, may alternatively 

1695 specify the flags as part of the pattern. 

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

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

1698 

1699 .. versionadded:: 1.4 

1700 

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

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

1703 objects such as column expressions in addition to plain Python 

1704 strings. This implementation did not work correctly with caching 

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

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

1707 within SQL expressions. 

1708 

1709 .. seealso:: 

1710 

1711 :meth:`_sql.ColumnOperators.regexp_replace` 

1712 

1713 

1714 """ 

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

1716 

1717 def regexp_replace( 

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

1719 ) -> ColumnOperators: 

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

1721 

1722 E.g.:: 

1723 

1724 stmt = select( 

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

1726 ) 

1727 

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

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

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

1731 the specific regular expression syntax and flags available are 

1732 **not backend agnostic**. 

1733 

1734 Regular expression replacement support is currently implemented for 

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

1736 among third-party dialects may vary. 

1737 

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

1739 clause. 

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

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

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

1743 Some backends, like PostgreSQL and MariaDB, may alternatively 

1744 specify the flags as part of the pattern. 

1745 

1746 .. versionadded:: 1.4 

1747 

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

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

1750 objects such as column expressions in addition to plain Python 

1751 strings. This implementation did not work correctly with caching 

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

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

1754 within SQL expressions. 

1755 

1756 

1757 .. seealso:: 

1758 

1759 :meth:`_sql.ColumnOperators.regexp_match` 

1760 

1761 """ 

1762 return self.operate( 

1763 regexp_replace_op, 

1764 pattern, 

1765 replacement=replacement, 

1766 flags=flags, 

1767 ) 

1768 

1769 def desc(self) -> ColumnOperators: 

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

1771 parent object.""" 

1772 return self.operate(desc_op) 

1773 

1774 def asc(self) -> ColumnOperators: 

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

1776 parent object.""" 

1777 return self.operate(asc_op) 

1778 

1779 def nulls_first(self) -> ColumnOperators: 

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

1781 parent object. 

1782 

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

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

1785 The previous name remains available for backwards compatibility. 

1786 """ 

1787 return self.operate(nulls_first_op) 

1788 

1789 # deprecated 1.4; see #5435 

1790 if TYPE_CHECKING: 

1791 

1792 def nullsfirst(self) -> ColumnOperators: ... 

1793 

1794 else: 

1795 nullsfirst = nulls_first 

1796 

1797 def nulls_last(self) -> ColumnOperators: 

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

1799 parent object. 

1800 

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

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

1803 The previous name remains available for backwards compatibility. 

1804 """ 

1805 return self.operate(nulls_last_op) 

1806 

1807 # deprecated 1.4; see #5429 

1808 if TYPE_CHECKING: 

1809 

1810 def nullslast(self) -> ColumnOperators: ... 

1811 

1812 else: 

1813 nullslast = nulls_last 

1814 

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

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

1817 the parent object, given the collation string. 

1818 

1819 .. seealso:: 

1820 

1821 :func:`_expression.collate` 

1822 

1823 """ 

1824 return self.operate(collate, collation) 

1825 

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

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

1828 

1829 See :meth:`.ColumnOperators.__add__`. 

1830 

1831 """ 

1832 return self.reverse_operate(add, other) 

1833 

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

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

1836 

1837 See :meth:`.ColumnOperators.__sub__`. 

1838 

1839 """ 

1840 return self.reverse_operate(sub, other) 

1841 

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

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

1844 

1845 See :meth:`.ColumnOperators.__mul__`. 

1846 

1847 """ 

1848 return self.reverse_operate(mul, other) 

1849 

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

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

1852 

1853 See :meth:`.ColumnOperators.__mod__`. 

1854 

1855 """ 

1856 return self.reverse_operate(mod, other) 

1857 

1858 def between( 

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

1860 ) -> ColumnOperators: 

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

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

1863 

1864 """ 

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

1866 

1867 def distinct(self) -> ColumnOperators: 

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

1869 parent object. 

1870 

1871 """ 

1872 return self.operate(distinct_op) 

1873 

1874 def any_(self) -> ColumnOperators: 

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

1876 parent object. 

1877 

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

1879 

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

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

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

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

1884 different calling style. 

1885 

1886 """ 

1887 return self.operate(any_op) 

1888 

1889 def all_(self) -> ColumnOperators: 

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

1891 parent object. 

1892 

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

1894 

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

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

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

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

1899 different calling style. 

1900 

1901 """ 

1902 return self.operate(all_op) 

1903 

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

1905 """Implement the ``+`` operator. 

1906 

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

1908 if the parent object has non-string affinity. 

1909 If the parent object has a string affinity, 

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

1911 see :meth:`.ColumnOperators.concat`. 

1912 

1913 """ 

1914 return self.operate(add, other) 

1915 

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

1917 """Implement the ``-`` operator. 

1918 

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

1920 

1921 """ 

1922 return self.operate(sub, other) 

1923 

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

1925 """Implement the ``*`` operator. 

1926 

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

1928 

1929 """ 

1930 return self.operate(mul, other) 

1931 

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

1933 """Implement the ``%`` operator. 

1934 

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

1936 

1937 """ 

1938 return self.operate(mod, other) 

1939 

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

1941 """Implement the ``/`` operator. 

1942 

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

1944 considers the result type to be numeric. 

1945 

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

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

1948 backends may vary. 

1949 

1950 """ 

1951 return self.operate(truediv, other) 

1952 

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

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

1955 

1956 See :meth:`.ColumnOperators.__truediv__`. 

1957 

1958 """ 

1959 return self.reverse_operate(truediv, other) 

1960 

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

1962 """Implement the ``//`` operator. 

1963 

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

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

1966 type to be integer. 

1967 

1968 .. versionadded:: 2.0 

1969 

1970 """ 

1971 return self.operate(floordiv, other) 

1972 

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

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

1975 

1976 See :meth:`.ColumnOperators.__floordiv__`. 

1977 

1978 """ 

1979 return self.reverse_operate(floordiv, other) 

1980 

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

1982 """Implement the ``**`` operator. 

1983 

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

1985 dialect-specific expression. 

1986 

1987 .. versionadded:: 2.1 

1988 

1989 """ 

1990 return self.operate(pow_, other) 

1991 

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

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

1994 

1995 .. seealso:: 

1996 

1997 :meth:`.ColumnOperators.__pow__`. 

1998 

1999 .. versionadded:: 2.1 

2000 

2001 """ 

2002 return self.reverse_operate(pow_, other) 

2003 

2004 

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

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

2007 

2008 

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

2010 return cast(OperatorType, fn) 

2011 

2012 

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

2014 _commutative.add(fn) 

2015 return fn 

2016 

2017 

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

2019 _comparison.add(fn) 

2020 return fn 

2021 

2022 

2023@_operator_fn 

2024def from_() -> Any: 

2025 raise NotImplementedError() 

2026 

2027 

2028@_operator_fn 

2029@comparison_op 

2030def function_as_comparison_op() -> Any: 

2031 raise NotImplementedError() 

2032 

2033 

2034@_operator_fn 

2035def as_() -> Any: 

2036 raise NotImplementedError() 

2037 

2038 

2039@_operator_fn 

2040def exists() -> Any: 

2041 raise NotImplementedError() 

2042 

2043 

2044@_operator_fn 

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

2046 raise NotImplementedError() 

2047 

2048 

2049# 1.4 deprecated; see #5435 

2050if TYPE_CHECKING: 

2051 

2052 @_operator_fn 

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

2054 

2055else: 

2056 istrue = is_true 

2057 

2058 

2059@_operator_fn 

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

2061 raise NotImplementedError() 

2062 

2063 

2064# 1.4 deprecated; see #5435 

2065if TYPE_CHECKING: 

2066 

2067 @_operator_fn 

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

2069 

2070else: 

2071 isfalse = is_false 

2072 

2073 

2074@comparison_op 

2075@_operator_fn 

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

2077 return a.is_distinct_from(b) 

2078 

2079 

2080@comparison_op 

2081@_operator_fn 

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

2083 return a.is_not_distinct_from(b) 

2084 

2085 

2086# deprecated 1.4; see #5435 

2087if TYPE_CHECKING: 

2088 

2089 @_operator_fn 

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

2091 

2092else: 

2093 isnot_distinct_from = is_not_distinct_from 

2094 

2095 

2096@comparison_op 

2097@_operator_fn 

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

2099 return a.is_(b) 

2100 

2101 

2102@comparison_op 

2103@_operator_fn 

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

2105 return a.is_not(b) 

2106 

2107 

2108# 1.4 deprecated; see #5429 

2109if TYPE_CHECKING: 

2110 

2111 @_operator_fn 

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

2113 

2114else: 

2115 isnot = is_not 

2116 

2117 

2118@_operator_fn 

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

2120 return a.collate(b) 

2121 

2122 

2123@_operator_fn 

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

2125 return a.op(opstring)(b) 

2126 

2127 

2128@comparison_op 

2129@_operator_fn 

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

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

2132 

2133 

2134@comparison_op 

2135@_operator_fn 

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

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

2138 

2139 

2140# 1.4 deprecated; see #5435 

2141if TYPE_CHECKING: 

2142 

2143 @_operator_fn 

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

2145 

2146else: 

2147 notlike_op = not_like_op 

2148 

2149 

2150@comparison_op 

2151@_operator_fn 

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

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

2154 

2155 

2156@comparison_op 

2157@_operator_fn 

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

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

2160 

2161 

2162# 1.4 deprecated; see #5435 

2163if TYPE_CHECKING: 

2164 

2165 @_operator_fn 

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

2167 

2168else: 

2169 notilike_op = not_ilike_op 

2170 

2171 

2172@comparison_op 

2173@_operator_fn 

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

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

2176 

2177 

2178@comparison_op 

2179@_operator_fn 

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

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

2182 

2183 

2184# 1.4 deprecated; see #5435 

2185if TYPE_CHECKING: 

2186 

2187 @_operator_fn 

2188 def notbetween_op( 

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

2190 ) -> Any: ... 

2191 

2192else: 

2193 notbetween_op = not_between_op 

2194 

2195 

2196@comparison_op 

2197@_operator_fn 

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

2199 return a.in_(b) 

2200 

2201 

2202@comparison_op 

2203@_operator_fn 

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

2205 return a.not_in(b) 

2206 

2207 

2208# 1.4 deprecated; see #5429 

2209if TYPE_CHECKING: 

2210 

2211 @_operator_fn 

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

2213 

2214else: 

2215 notin_op = not_in_op 

2216 

2217 

2218@_operator_fn 

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

2220 return a.distinct() 

2221 

2222 

2223@_operator_fn 

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

2225 return a.any_() 

2226 

2227 

2228@_operator_fn 

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

2230 return a.all_() 

2231 

2232 

2233def _escaped_like_impl( 

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

2235) -> Any: 

2236 if autoescape: 

2237 if autoescape is not True: 

2238 util.warn( 

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

2240 ) 

2241 if escape is None: 

2242 escape = "/" 

2243 

2244 if not isinstance(other, str): 

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

2246 

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

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

2249 

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

2251 

2252 return fn(other, escape=escape) 

2253 

2254 

2255@comparison_op 

2256@_operator_fn 

2257def startswith_op( 

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

2259) -> Any: 

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

2261 

2262 

2263@comparison_op 

2264@_operator_fn 

2265def not_startswith_op( 

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

2267) -> Any: 

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

2269 

2270 

2271# 1.4 deprecated; see #5435 

2272if TYPE_CHECKING: 

2273 

2274 @_operator_fn 

2275 def notstartswith_op( 

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

2277 ) -> Any: ... 

2278 

2279else: 

2280 notstartswith_op = not_startswith_op 

2281 

2282 

2283@comparison_op 

2284@_operator_fn 

2285def istartswith_op( 

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

2287) -> Any: 

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

2289 

2290 

2291@comparison_op 

2292@_operator_fn 

2293def not_istartswith_op( 

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

2295) -> Any: 

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

2297 

2298 

2299@comparison_op 

2300@_operator_fn 

2301def endswith_op( 

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

2303) -> Any: 

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

2305 

2306 

2307@comparison_op 

2308@_operator_fn 

2309def not_endswith_op( 

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

2311) -> Any: 

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

2313 

2314 

2315# 1.4 deprecated; see #5435 

2316if TYPE_CHECKING: 

2317 

2318 @_operator_fn 

2319 def notendswith_op( 

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

2321 ) -> Any: ... 

2322 

2323else: 

2324 notendswith_op = not_endswith_op 

2325 

2326 

2327@comparison_op 

2328@_operator_fn 

2329def iendswith_op( 

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

2331) -> Any: 

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

2333 

2334 

2335@comparison_op 

2336@_operator_fn 

2337def not_iendswith_op( 

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

2339) -> Any: 

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

2341 

2342 

2343@comparison_op 

2344@_operator_fn 

2345def contains_op( 

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

2347) -> Any: 

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

2349 

2350 

2351@comparison_op 

2352@_operator_fn 

2353def not_contains_op( 

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

2355) -> Any: 

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

2357 

2358 

2359# 1.4 deprecated; see #5435 

2360if TYPE_CHECKING: 

2361 

2362 @_operator_fn 

2363 def notcontains_op( 

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

2365 ) -> Any: ... 

2366 

2367else: 

2368 notcontains_op = not_contains_op 

2369 

2370 

2371@comparison_op 

2372@_operator_fn 

2373def icontains_op( 

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

2375) -> Any: 

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

2377 

2378 

2379@comparison_op 

2380@_operator_fn 

2381def not_icontains_op( 

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

2383) -> Any: 

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

2385 

2386 

2387@comparison_op 

2388@_operator_fn 

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

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

2391 

2392 

2393@comparison_op 

2394@_operator_fn 

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

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

2397 

2398 

2399@comparison_op 

2400@_operator_fn 

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

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

2403 

2404 

2405@_operator_fn 

2406def regexp_replace_op( 

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

2408) -> Any: 

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

2410 

2411 

2412@comparison_op 

2413@_operator_fn 

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

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

2416 

2417 

2418# 1.4 deprecated; see #5429 

2419if TYPE_CHECKING: 

2420 

2421 @_operator_fn 

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

2423 

2424else: 

2425 notmatch_op = not_match_op 

2426 

2427 

2428@_operator_fn 

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

2430 raise NotImplementedError() 

2431 

2432 

2433@_operator_fn 

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

2435 raise NotImplementedError() 

2436 

2437 

2438@_operator_fn 

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

2440 try: 

2441 concat = a.concat 

2442 except AttributeError: 

2443 return b._rconcat(a) 

2444 else: 

2445 return concat(b) 

2446 

2447 

2448@_operator_fn 

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

2450 return a.desc() 

2451 

2452 

2453@_operator_fn 

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

2455 return a.asc() 

2456 

2457 

2458@_operator_fn 

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

2460 return a.nulls_first() 

2461 

2462 

2463# 1.4 deprecated; see #5435 

2464if TYPE_CHECKING: 

2465 

2466 @_operator_fn 

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

2468 

2469else: 

2470 nullsfirst_op = nulls_first_op 

2471 

2472 

2473@_operator_fn 

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

2475 return a.nulls_last() 

2476 

2477 

2478# 1.4 deprecated; see #5435 

2479if TYPE_CHECKING: 

2480 

2481 @_operator_fn 

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

2483 

2484else: 

2485 nullslast_op = nulls_last_op 

2486 

2487 

2488@_operator_fn 

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

2490 raise NotImplementedError() 

2491 

2492 

2493@_operator_fn 

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

2495 raise NotImplementedError() 

2496 

2497 

2498@_operator_fn 

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

2500 return a.bitwise_xor(b) 

2501 

2502 

2503@_operator_fn 

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

2505 return a.bitwise_or(b) 

2506 

2507 

2508@_operator_fn 

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

2510 return a.bitwise_and(b) 

2511 

2512 

2513@_operator_fn 

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

2515 return a.bitwise_not() 

2516 

2517 

2518@_operator_fn 

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

2520 return a.bitwise_lshift(b) 

2521 

2522 

2523@_operator_fn 

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

2525 return a.bitwise_rshift(b) 

2526 

2527 

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

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

2530 

2531 

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

2533 return op in _commutative 

2534 

2535 

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

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

2538 

2539 

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

2541 return ( 

2542 op in _natural_self_precedent 

2543 or isinstance(op, custom_op) 

2544 and op.natural_self_precedent 

2545 ) 

2546 

2547 

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

2549 

2550 

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

2552 return is_comparison(op) or op in _booleans 

2553 

2554 

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

2556 

2557 

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

2559 """rotate a comparison operator 180 degrees. 

2560 

2561 Note this is not the same as negation. 

2562 

2563 """ 

2564 return _mirror.get(op, op) 

2565 

2566 

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

2568 

2569 

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

2571 return op in _associative 

2572 

2573 

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

2575 return op in _order_by_modifier 

2576 

2577 

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

2579 

2580_natural_self_precedent = _associative.union( 

2581 [getitem, json_getitem_op, json_path_getitem_op] 

2582) 

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

2584parenthesize (a op b). 

2585 

2586""" 

2587 

2588 

2589@_operator_fn 

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

2591 raise NotImplementedError() 

2592 

2593 

2594class _OpLimit(IntEnum): 

2595 _smallest = -100 

2596 _largest = 100 

2597 

2598 

2599_PRECEDENCE: Dict[OperatorType, int] = { 

2600 from_: 15, 

2601 function_as_comparison_op: 15, 

2602 any_op: 15, 

2603 all_op: 15, 

2604 getitem: 15, 

2605 json_getitem_op: 15, 

2606 json_path_getitem_op: 15, 

2607 pow_: 15, 

2608 mul: 8, 

2609 truediv: 8, 

2610 floordiv: 8, 

2611 mod: 8, 

2612 neg: 8, 

2613 bitwise_not_op: 8, 

2614 add: 7, 

2615 sub: 7, 

2616 bitwise_xor_op: 7, 

2617 bitwise_or_op: 7, 

2618 bitwise_and_op: 7, 

2619 bitwise_lshift_op: 7, 

2620 bitwise_rshift_op: 7, 

2621 filter_op: 6, 

2622 concat_op: 5, 

2623 match_op: 5, 

2624 not_match_op: 5, 

2625 regexp_match_op: 5, 

2626 not_regexp_match_op: 5, 

2627 regexp_replace_op: 5, 

2628 ilike_op: 5, 

2629 not_ilike_op: 5, 

2630 like_op: 5, 

2631 not_like_op: 5, 

2632 in_op: 5, 

2633 not_in_op: 5, 

2634 is_: 5, 

2635 is_not: 5, 

2636 eq: 5, 

2637 ne: 5, 

2638 is_distinct_from: 5, 

2639 is_not_distinct_from: 5, 

2640 gt: 5, 

2641 lt: 5, 

2642 ge: 5, 

2643 le: 5, 

2644 between_op: 5, 

2645 not_between_op: 5, 

2646 distinct_op: 5, 

2647 inv: 5, 

2648 is_true: 5, 

2649 is_false: 5, 

2650 and_: 3, 

2651 or_: 2, 

2652 comma_op: -1, 

2653 desc_op: 3, 

2654 asc_op: 3, 

2655 collate: 4, 

2656 as_: -1, 

2657 exists: 0, 

2658 _asbool: -10, 

2659} 

2660 

2661 

2662def is_precedent( 

2663 operator: OperatorType, against: Optional[OperatorType] 

2664) -> bool: 

2665 if operator is against and is_natural_self_precedent(operator): 

2666 return False 

2667 elif against is None: 

2668 return True 

2669 else: 

2670 return bool( 

2671 _PRECEDENCE.get( 

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

2673 ) 

2674 <= _PRECEDENCE.get( 

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

2676 ) 

2677 )