diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-09-07 00:01:34 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-09-07 00:01:34 -0400 |
commit | 7950270cf2b12807acd7c330b11dae36e50c3a28 (patch) | |
tree | f1ec50aa6fc604d7a2dadf1b41aff73952a05dcc /lib/sqlalchemy/sql/util.py | |
parent | e80c7cc5c103788a4c7e1c479af2c37cd9c958b3 (diff) | |
download | sqlalchemy-7950270cf2b12807acd7c330b11dae36e50c3a28.tar.gz |
- enhance ClauseAdapter / ColumnAdapter to have new behaviors with labels.
The "anonymize label" logic is now generalized to ClauseAdapter, and takes
place when the anonymize_labels flag is sent, taking effect for all
.columns lookups as well as within traverse() calls against the label
directly.
- traverse() will also memoize what it gets in columns, so that
calling upon traverse() / .columns against the same Label will
produce the same anonymized label. This is so that AliasedClass
produces the same anonymized label when it is accessed per-column
(e.g. SomeAlias.some_column) as well as when it is applied to a Query,
and within column loader strategies (e.g. query(SomeAlias)); the
former uses traverse() while the latter uses .columns
- AliasedClass now calls onto ColumnAdapter
- Query also makes sure to use that same ColumnAdapter from the AliasedClass
in all cases
- update the logic from 0.9 in #1068 to make use of the same
_label_resolve_dict we use for #2992, simplifying how that works
and adding support for new scenarios that were pretty broken
(see #3148, #3188)
Diffstat (limited to 'lib/sqlalchemy/sql/util.py')
-rw-r--r-- | lib/sqlalchemy/sql/util.py | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index 47ab61fdd..f630f9e93 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -488,8 +488,10 @@ class ClauseAdapter(visitors.ReplacingCloningVisitor): def __init__(self, selectable, equivalents=None, include=None, exclude=None, include_fn=None, exclude_fn=None, - adapt_on_names=False): - self.__traverse_options__ = {'stop_on': [selectable]} + adapt_on_names=False, anonymize_labels=False): + self.__traverse_options__ = { + 'stop_on': [selectable], + 'anonymize_labels': anonymize_labels} self.selectable = selectable if include: assert not include_fn @@ -549,9 +551,14 @@ class ColumnAdapter(ClauseAdapter): def __init__(self, selectable, equivalents=None, chain_to=None, include=None, exclude=None, adapt_required=False, - allow_label_resolve=True): + adapt_on_names=False, + allow_label_resolve=True, + anonymize_labels=False): ClauseAdapter.__init__(self, selectable, equivalents, - include, exclude) + include, exclude, + adapt_on_names=adapt_on_names, + anonymize_labels=anonymize_labels) + if chain_to: self.chain(chain_to) self.columns = util.populate_column_dict(self._locate_col) @@ -567,7 +574,13 @@ class ColumnAdapter(ClauseAdapter): ac.columns = util.populate_column_dict(ac._locate_col) return ac - adapt_clause = ClauseAdapter.traverse + def traverse(self, obj): + new_obj = ClauseAdapter.traverse(self, obj) + if new_obj is not obj: + self.columns[obj] = new_obj + return new_obj + + adapt_clause = traverse adapt_list = ClauseAdapter.copy_and_process def _wrap(self, local, wrapped): @@ -581,11 +594,6 @@ class ColumnAdapter(ClauseAdapter): if c is None: c = self.adapt_clause(col) - # anonymize labels in case they have a hardcoded name - # see test_eager_relations.py -> SubqueryTest.test_label_anonymizing - if isinstance(c, Label): - c = c.label(None) - # adapt_required used by eager loading to indicate that # we don't trust a result row column that is not translated. # this is to prevent a column from being interpreted as that |