summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/selectable.py
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2021-02-12 17:10:21 +0000
committerGerrit Code Review <gerrit@ci3.zzzcomputing.com>2021-02-12 17:10:21 +0000
commit4aa0c7ae76894048c5c30c89c403c7cbf5d844ff (patch)
tree59ca106bf70bf526a5c12873613561ecb2a0a2f5 /lib/sqlalchemy/sql/selectable.py
parent88b881f12c3a4db3f7f8b58b95c5dcec16ab893e (diff)
parent553ac45aae5712e64a5380ba1fa1c6028acf5f39 (diff)
downloadsqlalchemy-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.py147
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