diff options
author | mike bayer <mike_mp@zzzcomputing.com> | 2021-02-12 17:10:21 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@ci3.zzzcomputing.com> | 2021-02-12 17:10:21 +0000 |
commit | 4aa0c7ae76894048c5c30c89c403c7cbf5d844ff (patch) | |
tree | 59ca106bf70bf526a5c12873613561ecb2a0a2f5 /lib/sqlalchemy/sql/selectable.py | |
parent | 88b881f12c3a4db3f7f8b58b95c5dcec16ab893e (diff) | |
parent | 553ac45aae5712e64a5380ba1fa1c6028acf5f39 (diff) | |
download | sqlalchemy-4aa0c7ae76894048c5c30c89c403c7cbf5d844ff.tar.gz |
Merge "Apply consistent labeling for all future style ORM queries"
Diffstat (limited to 'lib/sqlalchemy/sql/selectable.py')
-rw-r--r-- | lib/sqlalchemy/sql/selectable.py | 147 |
1 files changed, 87 insertions, 60 deletions
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py index a273e0c90..7e2c5dd3b 100644 --- a/lib/sqlalchemy/sql/selectable.py +++ b/lib/sqlalchemy/sql/selectable.py @@ -2776,13 +2776,11 @@ class SelectBase( representing the columns that this SELECT statement or similar construct returns in its result set. - This collection differs from the - :attr:`_expression.FromClause.columns` collection - of a :class:`_expression.FromClause` - in that the columns within this collection - cannot be directly nested inside another SELECT statement; a subquery - must be applied first which provides for the necessary parenthesization - required by SQL. + This collection differs from the :attr:`_expression.FromClause.columns` + collection of a :class:`_expression.FromClause` in that the columns + within this collection cannot be directly nested inside another SELECT + statement; a subquery must be applied first which provides for the + necessary parenthesization required by SQL. .. versionadded:: 1.4 @@ -4078,6 +4076,60 @@ class SelectState(util.MemoizedSlots, CompileState): def from_statement(cls, statement, from_statement): cls._plugin_not_implemented() + @classmethod + def _column_naming_convention(cls, label_style): + names = set() + pa = [] + + if label_style is LABEL_STYLE_NONE: + + def go(c, col_name=None): + return col_name or c._proxy_key + + elif label_style is LABEL_STYLE_TABLENAME_PLUS_COL: + + def go(c, col_name=None): + # we use key_label since this name is intended for targeting + # within the ColumnCollection only, it's not related to SQL + # rendering which always uses column name for SQL label names + + if col_name: + name = c._gen_label(col_name) + else: + name = c._key_label + + if name in names: + if not pa: + pa.append(prefix_anon_map()) + + name = c._label_anon_label % pa[0] + else: + names.add(name) + + return name + + else: + + def go(c, col_name=None): + # we use key_label since this name is intended for targeting + # within the ColumnCollection only, it's not related to SQL + # rendering which always uses column name for SQL label names + if col_name: + name = col_name + else: + name = c._proxy_key + if name in names: + if not pa: + pa.append(prefix_anon_map()) + + name = c.anon_label % pa[0] + else: + names.add(name) + + return name + + return go + def _get_froms(self, statement): seen = set() froms = [] @@ -5519,63 +5571,41 @@ class Select( representing the columns that this SELECT statement or similar construct returns in its result set. - This collection differs from the - :attr:`_expression.FromClause.columns` collection - of a :class:`_expression.FromClause` - in that the columns within this collection - cannot be directly nested inside another SELECT statement; a subquery - must be applied first which provides for the necessary parenthesization - required by SQL. + This collection differs from the :attr:`_expression.FromClause.columns` + collection of a :class:`_expression.FromClause` in that the columns + within this collection cannot be directly nested inside another SELECT + statement; a subquery must be applied first which provides for the + necessary parenthesization required by SQL. For a :func:`_expression.select` construct, the collection here is - exactly what would be rendered inside the "SELECT" statement, and the - :class:`_expression.ColumnElement` - objects are directly present as they were - given, e.g.:: + exactly what would be rendered inside the "SELECT" statement, and the + :class:`_expression.ColumnElement` objects are directly present as they + were given, e.g.:: col1 = column('q', Integer) col2 = column('p', Integer) stmt = select(col1, col2) Above, ``stmt.selected_columns`` would be a collection that contains - the ``col1`` and ``col2`` objects directly. For a statement that is + the ``col1`` and ``col2`` objects directly. For a statement that is against a :class:`_schema.Table` or other - :class:`_expression.FromClause`, the collection - will use the :class:`_expression.ColumnElement` - objects that are in the + :class:`_expression.FromClause`, the collection will use the + :class:`_expression.ColumnElement` objects that are in the :attr:`_expression.FromClause.c` collection of the from element. .. versionadded:: 1.4 """ - names = set() - pa = None - collection = [] - - for c in self._exported_columns_iterator(): - # we use key_label since this name is intended for targeting - # within the ColumnCollection only, it's not related to SQL - # rendering which always uses column name for SQL label names - if self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL: - name = c._key_label - else: - name = c._proxy_key - if name in names: - if pa is None: - pa = prefix_anon_map() - - if self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL: - name = c._label_anon_label % pa - else: - name = c.anon_label % pa - else: - names.add(name) - collection.append((name, c)) - return ColumnCollection(collection).as_immutable() + # compare to SelectState._generate_columns_plus_names, which + # generates the actual names used in the SELECT string. that + # method is more complex because it also renders columns that are + # fully ambiguous, e.g. same column more than once. + conv = SelectState._column_naming_convention(self._label_style) - # def _exported_columns_iterator(self): - # return _select_iterables(self._raw_columns) + return ColumnCollection( + [(conv(c), c) for c in self._exported_columns_iterator()] + ).as_immutable() def _exported_columns_iterator(self): meth = SelectState.get_plugin_class(self).exported_columns_iterator @@ -6170,19 +6200,16 @@ class TextualSelect(SelectBase): representing the columns that this SELECT statement or similar construct returns in its result set. - This collection differs from the - :attr:`_expression.FromClause.columns` collection - of a :class:`_expression.FromClause` - in that the columns within this collection - cannot be directly nested inside another SELECT statement; a subquery - must be applied first which provides for the necessary parenthesization - required by SQL. + This collection differs from the :attr:`_expression.FromClause.columns` + collection of a :class:`_expression.FromClause` in that the columns + within this collection cannot be directly nested inside another SELECT + statement; a subquery must be applied first which provides for the + necessary parenthesization required by SQL. - For a :class:`_expression.TextualSelect` construct, - the collection contains the - :class:`_expression.ColumnElement` - objects that were passed to the constructor, - typically via the :meth:`_expression.TextClause.columns` method. + For a :class:`_expression.TextualSelect` construct, the collection + contains the :class:`_expression.ColumnElement` objects that were + passed to the constructor, typically via the + :meth:`_expression.TextClause.columns` method. .. versionadded:: 1.4 |