From 428262a2d5374613f4a4cf925bbd9e94e0e34acc Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 12 Apr 2022 13:52:31 -0400 Subject: 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 --- lib/sqlalchemy/dialects/postgresql/array.py | 32 ++++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'lib/sqlalchemy/dialects/postgresql/array.py') diff --git a/lib/sqlalchemy/dialects/postgresql/array.py b/lib/sqlalchemy/dialects/postgresql/array.py index 74643c4d9..7eec7b86f 100644 --- a/lib/sqlalchemy/dialects/postgresql/array.py +++ b/lib/sqlalchemy/dialects/postgresql/array.py @@ -5,14 +5,19 @@ # This module is part of SQLAlchemy and is released under # the MIT License: https://www.opensource.org/licenses/mit-license.php +from __future__ import annotations + import re +from typing import Any +from typing import TypeVar from ... import types as sqltypes from ... import util -from ...sql import coercions from ...sql import expression from ...sql import operators -from ...sql import roles + + +_T = TypeVar("_T", bound=Any) def Any(other, arrexpr, operator=operators.eq): @@ -33,7 +38,7 @@ def All(other, arrexpr, operator=operators.eq): return arrexpr.all(other, operator) -class array(expression.ClauseList, expression.ColumnElement): +class array(expression.ExpressionClauseList[_T]): """A PostgreSQL ARRAY literal. @@ -90,16 +95,19 @@ class array(expression.ClauseList, expression.ColumnElement): inherit_cache = True def __init__(self, clauses, **kw): - clauses = [ - coercions.expect(roles.ExpressionElementRole, c) for c in clauses - ] - - self._type_tuple = [arg.type for arg in clauses] - main_type = kw.pop( - "type_", - self._type_tuple[0] if self._type_tuple else sqltypes.NULLTYPE, + + type_arg = kw.pop("type_", None) + super(array, self).__init__(operators.comma_op, *clauses, **kw) + + self._type_tuple = [arg.type for arg in self.clauses] + + main_type = ( + type_arg + if type_arg is not None + else self._type_tuple[0] + if self._type_tuple + else sqltypes.NULLTYPE ) - super(array, self).__init__(*clauses, **kw) if isinstance(main_type, ARRAY): self.type = ARRAY( -- cgit v1.2.1