diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-08-29 12:09:17 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-08-30 17:57:38 -0400 |
| commit | f6c9b20a04d183d86078252048563b14e27fb6d2 (patch) | |
| tree | d8fbb764aa6322f56f2529fde793f937565bc96e /lib/sqlalchemy/sql/annotation.py | |
| parent | 2b042b6d18dc527c12b2ef1239bfe5ee2b658930 (diff) | |
| download | sqlalchemy-f6c9b20a04d183d86078252048563b14e27fb6d2.tar.gz | |
Annotate session-bind-lookup entity in Query-produced selectables
Added new entity-targeting capabilities to the :class:`.Query` object to
help with the case where the :class:`.Session` is using a bind dictionary
against mapped classes, rather than a single bind, and the :class:`.Query`
is against a Core statement that was ultimately generated from a method
such as :meth:`.Query.subquery`; a deep search is performed to locate
any ORM entity related to the query in order to locate a mapper if
one is not otherwise present.
Fixes: #4829
Change-Id: I95cf325a5aba21baec4b313246c6f4d692284820
Diffstat (limited to 'lib/sqlalchemy/sql/annotation.py')
| -rw-r--r-- | lib/sqlalchemy/sql/annotation.py | 74 |
1 files changed, 73 insertions, 1 deletions
diff --git a/lib/sqlalchemy/sql/annotation.py b/lib/sqlalchemy/sql/annotation.py index 7fc9245ab..a0264845e 100644 --- a/lib/sqlalchemy/sql/annotation.py +++ b/lib/sqlalchemy/sql/annotation.py @@ -15,8 +15,80 @@ from . import operators from .. import util +class SupportsCloneAnnotations(object): + _annotations = util.immutabledict() + + def _annotate(self, values): + """return a copy of this ClauseElement with annotations + updated by the given dictionary. + + """ + new = self._clone() + new._annotations = new._annotations.union(values) + return new + + def _with_annotations(self, values): + """return a copy of this ClauseElement with annotations + replaced by the given dictionary. + + """ + new = self._clone() + new._annotations = util.immutabledict(values) + return new + + def _deannotate(self, values=None, clone=False): + """return a copy of this :class:`.ClauseElement` with annotations + removed. + + :param values: optional tuple of individual values + to remove. + + """ + if clone or self._annotations: + # clone is used when we are also copying + # the expression for a deep deannotation + new = self._clone() + new._annotations = {} + return new + else: + return self + + +class SupportsWrappingAnnotations(object): + def _annotate(self, values): + """return a copy of this ClauseElement with annotations + updated by the given dictionary. + + """ + return Annotated(self, values) + + def _with_annotations(self, values): + """return a copy of this ClauseElement with annotations + replaced by the given dictionary. + + """ + return Annotated(self, values) + + def _deannotate(self, values=None, clone=False): + """return a copy of this :class:`.ClauseElement` with annotations + removed. + + :param values: optional tuple of individual values + to remove. + + """ + if clone: + # clone is used when we are also copying + # the expression for a deep deannotation + return self._clone() + else: + # if no clone, since we have no annotations we return + # self + return self + + class Annotated(object): - """clones a ClauseElement and applies an 'annotations' dictionary. + """clones a SupportsAnnotated and applies an 'annotations' dictionary. Unlike regular clones, this clone also mimics __hash__() and __cmp__() of the original element so that it takes its place |
