summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/elements.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql/elements.py')
-rw-r--r--lib/sqlalchemy/sql/elements.py50
1 files changed, 43 insertions, 7 deletions
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index 7310edd3f..c1bc9edbc 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -26,7 +26,6 @@ from .annotation import SupportsWrappingAnnotations
from .base import _clone
from .base import _generative
from .base import Executable
-from .base import HasCacheKey
from .base import HasMemoized
from .base import Immutable
from .base import NO_ARG
@@ -35,6 +34,7 @@ from .base import SingletonConstant
from .coercions import _document_text_coercion
from .traversals import _copy_internals
from .traversals import _get_children
+from .traversals import MemoizedHasCacheKey
from .traversals import NO_CACHE
from .visitors import cloned_traverse
from .visitors import InternalTraversal
@@ -179,7 +179,10 @@ def not_(clause):
@inspection._self_inspects
class ClauseElement(
- roles.SQLRole, SupportsWrappingAnnotations, HasCacheKey, Traversible,
+ roles.SQLRole,
+ SupportsWrappingAnnotations,
+ MemoizedHasCacheKey,
+ Traversible,
):
"""Base class for elements of a programmatically constructed SQL
expression.
@@ -206,6 +209,7 @@ class ClauseElement(
_is_select_container = False
_is_select_statement = False
_is_bind_parameter = False
+ _is_clause_list = False
_order_by_label_element = None
@@ -300,7 +304,7 @@ class ClauseElement(
used.
"""
- return self._params(True, optionaldict, kwargs)
+ return self._replace_params(True, optionaldict, kwargs)
def params(self, *optionaldict, **kwargs):
"""Return a copy with :func:`bindparam()` elements replaced.
@@ -315,9 +319,9 @@ class ClauseElement(
{'foo':7}
"""
- return self._params(False, optionaldict, kwargs)
+ return self._replace_params(False, optionaldict, kwargs)
- def _params(self, unique, optionaldict, kwargs):
+ def _replace_params(self, unique, optionaldict, kwargs):
if len(optionaldict) == 1:
kwargs.update(optionaldict[0])
elif len(optionaldict) > 1:
@@ -371,7 +375,7 @@ class ClauseElement(
continue
if obj is not None:
- result = meth(self, obj, **kw)
+ result = meth(self, attrname, obj, **kw)
if result is not None:
setattr(self, attrname, result)
@@ -2070,6 +2074,8 @@ class ClauseList(
__visit_name__ = "clauselist"
+ _is_clause_list = True
+
_traverse_internals = [
("clauses", InternalTraversal.dp_clauseelement_list),
("operator", InternalTraversal.dp_operator),
@@ -2079,6 +2085,8 @@ class ClauseList(
self.operator = kwargs.pop("operator", operators.comma_op)
self.group = kwargs.pop("group", True)
self.group_contents = kwargs.pop("group_contents", True)
+ if kwargs.pop("_flatten_sub_clauses", False):
+ clauses = util.flatten_iterator(clauses)
self._tuple_values = kwargs.pop("_tuple_values", False)
self._text_converter_role = text_converter_role = kwargs.pop(
"_literal_as_text_role", roles.WhereHavingRole
@@ -2116,7 +2124,9 @@ class ClauseList(
@property
def _select_iterable(self):
- return iter(self)
+ return itertools.chain.from_iterable(
+ [elem._select_iterable for elem in self.clauses]
+ )
def append(self, clause):
if self.group_contents:
@@ -2224,6 +2234,32 @@ class BooleanClauseList(ClauseList, ColumnElement):
return cls._construct_raw(operator)
@classmethod
+ def _construct_for_whereclause(cls, clauses):
+ operator, continue_on, skip_on = (
+ operators.and_,
+ True_._singleton,
+ False_._singleton,
+ )
+
+ lcc, convert_clauses = cls._process_clauses_for_boolean(
+ operator,
+ continue_on,
+ skip_on,
+ clauses, # these are assumed to be coerced already
+ )
+
+ if lcc > 1:
+ # multiple elements. Return regular BooleanClauseList
+ # which will link elements against the operator.
+ return cls._construct_raw(operator, convert_clauses)
+ elif lcc == 1:
+ # just one element. return it as a single boolean element,
+ # not a list and discard the operator.
+ return convert_clauses[0]
+ else:
+ return None
+
+ @classmethod
def _construct_raw(cls, operator, clauses=None):
self = cls.__new__(cls)
self.clauses = clauses if clauses else []