diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-12-01 17:24:27 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-05-24 11:54:08 -0400 |
| commit | dce8c7a125cb99fad62c76cd145752d5afefae36 (patch) | |
| tree | 352dfa2c38005207ca64f45170bbba2c0f8c927e /lib/sqlalchemy/sql/elements.py | |
| parent | 1502b5b3e4e4b93021eb927a6623f288ef006ba6 (diff) | |
| download | sqlalchemy-dce8c7a125cb99fad62c76cd145752d5afefae36.tar.gz | |
Unify Query and select() , move all processing to compile phase
Convert Query to do virtually all compile state computation
in the _compile_context() phase, and organize it all
such that a plain select() construct may also be used as the
source of information in order to generate ORM query state.
This makes it such that Query is not needed except for
its additional methods like from_self() which are all to
be deprecated.
The construction of ORM state will occur beyond the
caching boundary when the new execution model is integrated.
future select() gains a working join() and filter_by() method.
as we continue to rebase and merge each commit in the steps,
callcounts continue to bump around. will have to look at
the final result when it's all in.
References: #5159
References: #4705
References: #4639
References: #4871
References: #5010
Change-Id: I19e05b3424b07114cce6c439b05198ac47f7ac10
Diffstat (limited to 'lib/sqlalchemy/sql/elements.py')
| -rw-r--r-- | lib/sqlalchemy/sql/elements.py | 50 |
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 [] |
