diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-09-06 17:56:53 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-09-06 17:56:53 -0400 |
| commit | e80c7cc5c103788a4c7e1c479af2c37cd9c958b3 (patch) | |
| tree | 87df4dd4fe620b16df15d3ff5f6b7c04ba913a74 /lib/sqlalchemy/sql | |
| parent | 4e285fd6ba2cbaf4b43e943a0e6bb45cc104cf08 (diff) | |
| download | sqlalchemy-e80c7cc5c103788a4c7e1c479af2c37cd9c958b3.tar.gz | |
wip for #3148
Diffstat (limited to 'lib/sqlalchemy/sql')
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 6 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/elements.py | 26 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/selectable.py | 15 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/util.py | 6 |
4 files changed, 44 insertions, 9 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index af0fff826..4349c97f4 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -512,7 +512,7 @@ class SQLCompiler(Compiled): selectable = self.stack[-1]['selectable'] try: - col = selectable._inner_column_dict[element.text] + col = selectable._label_resolve_dict[element.text] except KeyError: # treat it like text() util.warn_limited( @@ -701,6 +701,10 @@ class SQLCompiler(Compiled): # here; we can only add a label in the ORDER BY for an individual # label expression in the columns clause. + # TODO: we should see if we can bring _resolve_label + # into this + + raw_col = set(l._order_by_label_element.name for l in order_by_select._raw_columns if l._order_by_label_element is not None) diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 870e96437..c8504f21f 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -675,6 +675,19 @@ class ColumnElement(operators.ColumnOperators, ClauseElement): """ + _resolve_label = None + """The name that should be used to identify this ColumnElement in a + select() object when "label resolution" logic is used; this refers + to using a string name in an expression like order_by() or group_by() + that wishes to target a labeled expression in the columns clause. + + The name is distinct from that of .name or ._label to account for the case + where anonymizing logic may be used to change the name that's actually + rendered at compile time; this attribute should hold onto the original + name that was user-assigned when producing a .label() construct. + + """ + _alt_names = () def self_group(self, against=None): @@ -691,6 +704,8 @@ class ColumnElement(operators.ColumnOperators, ClauseElement): else: return super(ColumnElement, self)._negate() + _allow_label_resolve = True + @util.memoized_property def type(self): return type_api.NULLTYPE @@ -1231,7 +1246,7 @@ class TextClause(Executable, ClauseElement): # help in those cases where text() is # interpreted in a column expression situation - key = _label = None + key = _label = _resolve_label = None def __init__( self, @@ -2869,8 +2884,13 @@ class Label(ColumnElement): :param obj: a :class:`.ColumnElement`. """ + + if isinstance(element, Label): + self._resolve_label = element._label + while isinstance(element, Label): element = element.element + if name: self.name = name else: @@ -2886,6 +2906,10 @@ class Label(ColumnElement): return self.__class__, (self.name, self._element, self._type) @util.memoized_property + def _allow_label_resolve(self): + return self.element._allow_label_resolve + + @util.memoized_property def _order_by_label_element(self): return self diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py index b802a6944..57b16f45f 100644 --- a/lib/sqlalchemy/sql/selectable.py +++ b/lib/sqlalchemy/sql/selectable.py @@ -1814,7 +1814,7 @@ class GenerativeSelect(SelectBase): *clauses, _literal_as_text=_literal_as_label_reference) @property - def _inner_column_dict(self): + def _label_resolve_dict(self): raise NotImplementedError() def _copy_internals(self, clone=_clone, **kw): @@ -1884,7 +1884,7 @@ class CompoundSelect(GenerativeSelect): GenerativeSelect.__init__(self, **kwargs) @property - def _inner_column_dict(self): + def _label_resolve_dict(self): return dict( (c.key, c) for c in self.c ) @@ -2498,11 +2498,14 @@ class Select(HasPrefixes, GenerativeSelect): return _select_iterables(self._raw_columns) @_memoized_property - def _inner_column_dict(self): + def _label_resolve_dict(self): d = dict( - (c._label or c.key, c) - for c in _select_iterables(self._raw_columns)) - d.update((c.key, c) for c in _select_iterables(self.froms)) + (c._resolve_label or c._label or c.key, c) + for c in _select_iterables(self._raw_columns) + if c._allow_label_resolve) + d.update( + (c.key, c) for c in + _select_iterables(self.froms) if c._allow_label_resolve) return d diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index 8bbae8b93..47ab61fdd 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -548,13 +548,15 @@ class ColumnAdapter(ClauseAdapter): def __init__(self, selectable, equivalents=None, chain_to=None, include=None, - exclude=None, adapt_required=False): + exclude=None, adapt_required=False, + allow_label_resolve=True): ClauseAdapter.__init__(self, selectable, equivalents, include, exclude) if chain_to: self.chain(chain_to) self.columns = util.populate_column_dict(self._locate_col) self.adapt_required = adapt_required + self.allow_label_resolve = allow_label_resolve def wrap(self, adapter): ac = self.__class__.__new__(self.__class__) @@ -580,6 +582,7 @@ class ColumnAdapter(ClauseAdapter): 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) @@ -591,6 +594,7 @@ class ColumnAdapter(ClauseAdapter): if self.adapt_required and c is col: return None + c._allow_label_resolve = self.allow_label_resolve return c def adapted_row(self, row): |
