diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-04-12 13:52:31 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-04-13 17:19:31 -0400 |
commit | 428262a2d5374613f4a4cf925bbd9e94e0e34acc (patch) | |
tree | 9f71ec4a09d3ea584b3e399085254fb278049a6f /lib/sqlalchemy/sql/default_comparator.py | |
parent | a45e2284dad17fbbba3bea9d5e5304aab21c8c94 (diff) | |
download | sqlalchemy-428262a2d5374613f4a4cf925bbd9e94e0e34acc.tar.gz |
implement multi-element expression constructs
Improved the construction of SQL binary expressions to allow for very long
expressions against the same associative operator without special steps
needed in order to avoid high memory use and excess recursion depth. A
particular binary operation ``A op B`` can now be joined against another
element ``op C`` and the resulting structure will be "flattened" so that
the representation as well as SQL compilation does not require recursion.
To implement this more cleanly, the biggest change here is that
column-oriented lists of things are broken away from ClauseList
in a new class ExpressionClauseList, that also forms the basis
of BooleanClauseList. ClauseList is still used for the generic
"comma-separated list" of things such as Tuple and things like
ORDER BY, as well as in some API endpoints.
Also adds __slots__ to the TypeEngine-bound Comparator
classes. Still can't really do __slots__ on ClauseElement.
Fixes: #7744
Change-Id: I81a8ceb6f8f3bb0fe52d58f3cb42e4b6c2bc9018
Diffstat (limited to 'lib/sqlalchemy/sql/default_comparator.py')
-rw-r--r-- | lib/sqlalchemy/sql/default_comparator.py | 37 |
1 files changed, 18 insertions, 19 deletions
diff --git a/lib/sqlalchemy/sql/default_comparator.py b/lib/sqlalchemy/sql/default_comparator.py index 944a0a5ce..512fca8d0 100644 --- a/lib/sqlalchemy/sql/default_comparator.py +++ b/lib/sqlalchemy/sql/default_comparator.py @@ -27,11 +27,12 @@ from . import type_api from .elements import and_ from .elements import BinaryExpression from .elements import ClauseElement -from .elements import ClauseList from .elements import CollationClause from .elements import CollectionAggregate +from .elements import ExpressionClauseList from .elements import False_ from .elements import Null +from .elements import OperatorExpression from .elements import or_ from .elements import True_ from .elements import UnaryExpression @@ -56,11 +57,9 @@ def _boolean_compare( reverse: bool = False, _python_is_types: Tuple[Type[Any], ...] = (type(None), bool), _any_all_expr: bool = False, - result_type: Optional[ - Union[Type[TypeEngine[bool]], TypeEngine[bool]] - ] = None, + result_type: Optional[TypeEngine[bool]] = None, **kwargs: Any, -) -> BinaryExpression[bool]: +) -> OperatorExpression[bool]: if result_type is None: result_type = type_api.BOOLEANTYPE @@ -71,7 +70,7 @@ def _boolean_compare( if op in (operators.eq, operators.ne) and isinstance( obj, (bool, True_, False_) ): - return BinaryExpression( + return OperatorExpression._construct_for_op( expr, coercions.expect(roles.ConstExprRole, obj), op, @@ -83,7 +82,7 @@ def _boolean_compare( operators.is_distinct_from, operators.is_not_distinct_from, ): - return BinaryExpression( + return OperatorExpression._construct_for_op( expr, coercions.expect(roles.ConstExprRole, obj), op, @@ -98,7 +97,7 @@ def _boolean_compare( else: # all other None uses IS, IS NOT if op in (operators.eq, operators.is_): - return BinaryExpression( + return OperatorExpression._construct_for_op( expr, coercions.expect(roles.ConstExprRole, obj), operators.is_, @@ -106,7 +105,7 @@ def _boolean_compare( type_=result_type, ) elif op in (operators.ne, operators.is_not): - return BinaryExpression( + return OperatorExpression._construct_for_op( expr, coercions.expect(roles.ConstExprRole, obj), operators.is_not, @@ -125,7 +124,7 @@ def _boolean_compare( ) if reverse: - return BinaryExpression( + return OperatorExpression._construct_for_op( obj, expr, op, @@ -134,7 +133,7 @@ def _boolean_compare( modifiers=kwargs, ) else: - return BinaryExpression( + return OperatorExpression._construct_for_op( expr, obj, op, @@ -169,11 +168,9 @@ def _binary_operate( obj: roles.BinaryElementRole[Any], *, reverse: bool = False, - result_type: Optional[ - Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"] - ] = None, + result_type: Optional[TypeEngine[_T]] = None, **kw: Any, -) -> BinaryExpression[_T]: +) -> OperatorExpression[_T]: coerced_obj = coercions.expect( roles.BinaryElementRole, obj, expr=expr, operator=op @@ -189,7 +186,9 @@ def _binary_operate( op, right.comparator ) - return BinaryExpression(left, right, op, type_=result_type, modifiers=kw) + return OperatorExpression._construct_for_op( + left, right, op, type_=result_type, modifiers=kw + ) def _conjunction_operate( @@ -311,7 +310,9 @@ def _between_impl( """See :meth:`.ColumnOperators.between`.""" return BinaryExpression( expr, - ClauseList( + ExpressionClauseList._construct_for_list( + operators.and_, + type_api.NULLTYPE, coercions.expect( roles.BinaryElementRole, cleft, @@ -324,9 +325,7 @@ def _between_impl( expr=expr, operator=operators.and_, ), - operator=operators.and_, group=False, - group_contents=False, ), op, negate=operators.not_between_op |