summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2021-01-26 22:31:21 +0000
committerGerrit Code Review <gerrit@bbpush.zzzcomputing.com>2021-01-26 22:31:21 +0000
commit6bba01e1f77bdafbfc3cfb3ff1f3b424608d3d9b (patch)
treef4d088aa29297ee0716dcc77bb170b7ef908de2d /lib
parentb6f83d6013ca4d2bc545754b98bd9400511e0dab (diff)
parent22f65156bbe846dea2fb9f87fe4187abe0ed790a (diff)
downloadsqlalchemy-6bba01e1f77bdafbfc3cfb3ff1f3b424608d3d9b.tar.gz
Merge "Replace with_labels() and apply_labels() in ORM/Core"
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/__init__.py4
-rw-r--r--lib/sqlalchemy/orm/context.py6
-rw-r--r--lib/sqlalchemy/orm/loading.py5
-rw-r--r--lib/sqlalchemy/orm/mapper.py7
-rw-r--r--lib/sqlalchemy/orm/persistence.py5
-rw-r--r--lib/sqlalchemy/orm/query.py57
-rw-r--r--lib/sqlalchemy/orm/session.py11
-rw-r--r--lib/sqlalchemy/orm/strategies.py11
-rw-r--r--lib/sqlalchemy/sql/__init__.py4
-rw-r--r--lib/sqlalchemy/sql/coercions.py8
-rw-r--r--lib/sqlalchemy/sql/expression.py4
-rw-r--r--lib/sqlalchemy/sql/selectable.py208
12 files changed, 268 insertions, 62 deletions
diff --git a/lib/sqlalchemy/__init__.py b/lib/sqlalchemy/__init__.py
index 607585460..2d092be65 100644
--- a/lib/sqlalchemy/__init__.py
+++ b/lib/sqlalchemy/__init__.py
@@ -54,6 +54,10 @@ from .sql import insert # noqa
from .sql import intersect # noqa
from .sql import intersect_all # noqa
from .sql import join # noqa
+from .sql import LABEL_STYLE_DEFAULT # noqa
+from .sql import LABEL_STYLE_DISAMBIGUATE_ONLY # noqa
+from .sql import LABEL_STYLE_NONE # noqa
+from .sql import LABEL_STYLE_TABLENAME_PLUS_COL # noqa
from .sql import lambda_stmt # noqa
from .sql import lateral # noqa
from .sql import literal # noqa
diff --git a/lib/sqlalchemy/orm/context.py b/lib/sqlalchemy/orm/context.py
index 584a07970..f9a0b72fe 100644
--- a/lib/sqlalchemy/orm/context.py
+++ b/lib/sqlalchemy/orm/context.py
@@ -373,9 +373,11 @@ class ORMFromStatementCompileState(ORMCompileState):
if (
isinstance(statement, expression.SelectBase)
and not statement._is_textual
- and not statement.use_labels
+ and statement._label_style is util.symbol("LABEL_STYLE_NONE")
):
- self.statement = statement.apply_labels()
+ self.statement = statement.set_label_style(
+ LABEL_STYLE_TABLENAME_PLUS_COL
+ )
else:
self.statement = statement
self.order_by = None
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py
index 3a85a2d7f..6c38931b4 100644
--- a/lib/sqlalchemy/orm/loading.py
+++ b/lib/sqlalchemy/orm/loading.py
@@ -31,6 +31,7 @@ from ..engine.result import ChunkedIteratorResult
from ..engine.result import FrozenResult
from ..engine.result import SimpleResultMetaData
from ..sql import util as sql_util
+from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
_new_runid = util.counter()
@@ -1396,7 +1397,9 @@ def load_scalar_attributes(mapper, state, attribute_names, passive):
result = load_on_ident(
session,
- future.select(mapper).apply_labels(),
+ future.select(mapper).set_label_style(
+ LABEL_STYLE_TABLENAME_PLUS_COL
+ ),
identity_key,
refresh_state=state,
only_load_props=attribute_names,
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 9ac0c85c6..5a9bc102e 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -54,6 +54,7 @@ from ..sql import operators
from ..sql import roles
from ..sql import util as sql_util
from ..sql import visitors
+from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
from ..util import HasMemoized
@@ -3008,7 +3009,11 @@ class Mapper(
cols = []
for key in col_attribute_names:
cols.extend(props[key].columns)
- return sql.select(*cols).where(cond).apply_labels()
+ return (
+ sql.select(*cols)
+ .where(cond)
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+ )
def _iterate_to_target_viawpoly(self, mapper):
if self.isa(mapper):
diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py
index 42b787580..7ba3a26d0 100644
--- a/lib/sqlalchemy/orm/persistence.py
+++ b/lib/sqlalchemy/orm/persistence.py
@@ -40,6 +40,7 @@ from ..sql.base import Options
from ..sql.dml import DeleteDMLState
from ..sql.dml import UpdateDMLState
from ..sql.elements import BooleanClauseList
+from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
def _bulk_insert(
@@ -1521,7 +1522,9 @@ def _finalize_insert_update_commands(base_mapper, uowtransaction, states):
if toload_now:
state.key = base_mapper._identity_key_from_state(state)
- stmt = future.select(mapper).apply_labels()
+ stmt = future.select(mapper).set_label_style(
+ LABEL_STYLE_TABLENAME_PLUS_COL
+ )
loading.load_on_ident(
uowtransaction.session,
stmt,
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 5dd2a8a21..1422fd6a1 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -470,7 +470,7 @@ class Query(
"""
q = self.enable_eagerloads(False)
if with_labels:
- q = q.with_labels()
+ q = q.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
q = q.statement
@@ -576,7 +576,11 @@ class Query(
return self.enable_eagerloads(False).statement.scalar_subquery()
def __clause_element__(self):
- return self.enable_eagerloads(False).with_labels().statement
+ return (
+ self.enable_eagerloads(False)
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+ .statement
+ )
@_generative
def only_return_tuples(self, value):
@@ -637,8 +641,27 @@ class Query(
"""
self._compile_options += {"_enable_eagerloads": value}
- @_generative
+ @util.deprecated_20(
+ ":meth:`_orm.Query.with_labels` and :meth:`_orm.Query.apply_labels`",
+ alternative="Use set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) "
+ "instead.",
+ )
def with_labels(self):
+ return self.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+
+ apply_labels = with_labels
+
+ @property
+ def get_label_style(self):
+ """
+ Retrieve the current label style.
+
+ .. versionadded:: 1.4
+
+ """
+ return self._label_style
+
+ def set_label_style(self, style):
"""Apply column labels to the return value of Query.statement.
Indicates that this Query's `statement` accessor should return
@@ -650,26 +673,28 @@ class Query(
When the `Query` actually issues SQL to load rows, it always
uses column labeling.
- .. note:: The :meth:`_query.Query.with_labels` method *only* applies
+ .. note:: The :meth:`_query.Query.set_label_style` method *only* applies
the output of :attr:`_query.Query.statement`, and *not* to any of
the result-row invoking systems of :class:`_query.Query` itself,
e.g.
:meth:`_query.Query.first`, :meth:`_query.Query.all`, etc.
To execute
- a query using :meth:`_query.Query.with_labels`, invoke the
+ a query using :meth:`_query.Query.set_label_style`, invoke the
:attr:`_query.Query.statement` using :meth:`.Session.execute`::
- result = session.execute(query.with_labels().statement)
-
-
- """
- self._label_style = LABEL_STYLE_TABLENAME_PLUS_COL
+ result = session.execute(
+ query
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+ .statement
+ )
- apply_labels = with_labels
+ .. versionadded:: 1.4
- @property
- def use_labels(self):
- return self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL
+ """ # noqa
+ if self._label_style is not style:
+ self = self._generate()
+ self._label_style = style
+ return self
@_generative
def enable_assertions(self, value):
@@ -1259,7 +1284,7 @@ class Query(
def _from_self(self, *entities):
fromclause = (
- self.with_labels()
+ self.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
.enable_eagerloads(False)
.correlate(None)
.subquery()
@@ -2903,7 +2928,7 @@ class Query(
inner = (
self.enable_eagerloads(False)
.add_columns(sql.literal_column("1"))
- .with_labels()
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
.statement.with_only_columns(1)
)
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 8a7a64f78..06a69b425 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -37,6 +37,7 @@ from ..sql import dml
from ..sql import roles
from ..sql import visitors
from ..sql.base import CompileState
+from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
__all__ = ["Session", "SessionTransaction", "sessionmaker"]
@@ -2741,15 +2742,17 @@ class Session(_SessionClassMethods):
elif instance is attributes.PASSIVE_CLASS_MISMATCH:
return None
- # apply_labels() not strictly necessary, however this will ensure that
- # tablename_colname style is used which at the moment is asserted
- # in a lot of unit tests :)
+ # set_label_style() not strictly necessary, however this will ensure
+ # that tablename_colname style is used which at the moment is
+ # asserted in a lot of unit tests :)
load_options = context.QueryContext.default_load_options
if populate_existing:
load_options += {"_populate_existing": populate_existing}
- statement = sql.select(mapper).apply_labels()
+ statement = sql.select(mapper).set_label_style(
+ LABEL_STYLE_TABLENAME_PLUS_COL
+ )
if with_for_update is not None:
statement._for_update_arg = query.ForUpdateArg._from_argument(
with_for_update
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 837d4d548..c80b8f5a2 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -41,6 +41,7 @@ from .. import sql
from .. import util
from ..sql import util as sql_util
from ..sql import visitors
+from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
def _register_attribute(
@@ -487,7 +488,9 @@ class DeferredColumnLoader(LoaderStrategy):
if (
loading.load_on_ident(
session,
- sql.select(localparent).apply_labels(),
+ sql.select(localparent).set_label_style(
+ LABEL_STYLE_TABLENAME_PLUS_COL
+ ),
state.key,
only_load_props=group,
refresh_state=state,
@@ -901,7 +904,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
stmt = sql.lambda_stmt(
lambda: sql.select(self.entity)
- .apply_labels()
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
._set_compile_options(ORMCompileState.default_compile_options),
global_track_bound_values=False,
lambda_cache=self._query_cache,
@@ -1304,7 +1307,7 @@ class SubqueryLoader(PostLoader):
# which we'll join onto.
# LEGACY: as "q" is a Query, the before_compile() event is invoked
# here.
- embed_q = q.apply_labels().subquery()
+ embed_q = q.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL).subquery()
left_alias = orm_util.AliasedClass(
leftmost_mapper, embed_q, use_mapper_path=True
)
@@ -2751,7 +2754,7 @@ class SelectInLoader(PostLoader, util.MemoizedSlots):
lambda: sql.select(
orm_util.Bundle("pk", *pk_cols), effective_entity
)
- .apply_labels()
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
._set_compile_options(ORMCompileState.default_compile_options)
._set_propagate_attrs(
{
diff --git a/lib/sqlalchemy/sql/__init__.py b/lib/sqlalchemy/sql/__init__.py
index 11795c3b2..7ee0bd8f4 100644
--- a/lib/sqlalchemy/sql/__init__.py
+++ b/lib/sqlalchemy/sql/__init__.py
@@ -47,6 +47,10 @@ from .expression import intersect_all # noqa
from .expression import Join # noqa
from .expression import join # noqa
from .expression import label # noqa
+from .expression import LABEL_STYLE_DEFAULT # noqa
+from .expression import LABEL_STYLE_DISAMBIGUATE_ONLY # noqa
+from .expression import LABEL_STYLE_NONE # noqa
+from .expression import LABEL_STYLE_TABLENAME_PLUS_COL # noqa
from .expression import lambda_stmt # noqa
from .expression import LambdaElement # noqa
from .expression import lateral # noqa
diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py
index 05e0a4fcf..3b972be41 100644
--- a/lib/sqlalchemy/sql/coercions.py
+++ b/lib/sqlalchemy/sql/coercions.py
@@ -67,7 +67,13 @@ def _deep_is_literal(element):
return (
not isinstance(
element,
- (Visitable, schema.SchemaEventTarget, HasCacheKey, Options),
+ (
+ Visitable,
+ schema.SchemaEventTarget,
+ HasCacheKey,
+ Options,
+ util.langhelpers._symbol,
+ ),
)
and not hasattr(element, "__clause_element__")
and (
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index 359f5e533..3eb1443a3 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -158,6 +158,10 @@ from .selectable import HasCTE # noqa
from .selectable import HasPrefixes # noqa
from .selectable import HasSuffixes # noqa
from .selectable import Join # noqa
+from .selectable import LABEL_STYLE_DEFAULT # noqa
+from .selectable import LABEL_STYLE_DISAMBIGUATE_ONLY # noqa
+from .selectable import LABEL_STYLE_NONE # noqa
+from .selectable import LABEL_STYLE_TABLENAME_PLUS_COL # noqa
from .selectable import Lateral # noqa
from .selectable import ReturnsRows # noqa
from .selectable import ScalarSelect # noqa
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index 8e478583f..e1cf367c8 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -825,7 +825,7 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
this is used to "ping" a derived selectable to add a new column
to its .c. collection when a Column has been added to one of the
- Table objects it ultimtely derives from.
+ Table objects it ultimately derives from.
If the given selectable hasn't populated its .c. collection yet,
it should at least pass on the message to the contained selectables,
@@ -849,6 +849,96 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
return self.alias(name=name)
+LABEL_STYLE_NONE = util.symbol(
+ "LABEL_STYLE_NONE",
+ """Label style indicating no automatic labeling should be applied to the
+ columns clause of a SELECT statement.
+
+ Below, the columns named ``columna`` are both rendered as is, meaning that
+ the name ``columna`` can only refer to the first occurrence of this name
+ within a result set, as well as if the statement were used as a subquery::
+
+ >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_NONE
+ >>> table1 = table("table1", column("columna"), column("columnb"))
+ >>> table2 = table("table2", column("columna"), column("columnc"))
+ >>> print(select(table1, table2).join(table2, true()).set_label_style(LABEL_STYLE_NONE))
+ SELECT table1.columna, table1.columnb, table2.columna, table2.columnc
+ FROM table1 JOIN table2 ON true
+
+ Used with the :meth:`_sql.Select.set_label_style` method.
+
+ .. versionadded:: 1.4
+
+""", # noqa E501
+)
+
+LABEL_STYLE_TABLENAME_PLUS_COL = util.symbol(
+ "LABEL_STYLE_TABLENAME_PLUS_COL",
+ """Label style indicating all columns should be labeled as
+ ``<tablename>_<columnname>`` when generating the columns clause of a SELECT
+ statement, to disambiguate same-named columns referenced from different
+ tables, aliases, or subqueries.
+
+ Below, all column names are given a label so that the two same-named
+ columns ``columna`` are disambiguated as ``table1_columna`` and
+ ``table2_columna`::
+
+ >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_TABLENAME_PLUS_COL
+ >>> table1 = table("table1", column("columna"), column("columnb"))
+ >>> table2 = table("table2", column("columna"), column("columnc"))
+ >>> print(select(table1, table2).join(table2, true()).set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL))
+ SELECT table1.columna AS table1_columna, table1.columnb AS table1_columnb, table2.columna AS table2_columna, table2.columnc AS table2_columnc
+ FROM table1 JOIN table2 ON true
+
+ Used with the :meth:`_sql.GenerativeSelect.set_label_style` method.
+ Equivalent to the legacy method ``Select.apply_labels()``;
+ :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` is SQLAlchemy's legacy
+ auto-labeling style. :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` provides a
+ less intrusive approach to disambiguation of same-named column expressions.
+
+
+ .. versionadded:: 1.4
+
+""", # noqa E501
+)
+
+
+LABEL_STYLE_DISAMBIGUATE_ONLY = util.symbol(
+ "LABEL_STYLE_DISAMBIGUATE_ONLY",
+ """Label style indicating that columns with a name that conflicts with
+ an existing name should be labeled with a semi-anonymizing label
+ when generating the columns clause of a SELECT statement.
+
+ Below, most column names are left unaffected, except for the second
+ occurrence of the name ``columna``, which is labeled using the
+ label ``columna_1`` to disambiguate it from that of ``tablea.columna``::
+
+ >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_DISAMBIGUATE_ONLY
+ >>> table1 = table("table1", column("columna"), column("columnb"))
+ >>> table2 = table("table2", column("columna"), column("columnc"))
+ >>> print(select(table1, table2).join(table2, true()).set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY))
+ SELECT table1.columna, table1.columnb, table2.columna AS columna_1, table2.columnc
+ FROM table1 JOIN table2 ON true
+
+ Used with the :meth:`_sql.GenerativeSelect.set_label_style` method,
+ :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` is the default labeling style
+ for all SELECT statements outside of :term:`1.x style` ORM queries.
+
+ .. versionadded:: 1.4
+
+""", # noqa: E501,
+)
+
+
+LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY
+"""The default label style, refers to
+:data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`.
+
+.. versionadded:: 1.4
+
+"""
+
+
class Join(roles.DMLTableRole, FromClause):
"""Represent a ``JOIN`` construct between two
:class:`_expression.FromClause`
@@ -1277,7 +1367,12 @@ class Join(roles.DMLTableRole, FromClause):
full=self.full,
)
else:
- return self.select().apply_labels().correlate(None).alias(name)
+ return (
+ self.select()
+ .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+ .correlate(None)
+ .alias(name)
+ )
@util.deprecated_20(
":meth:`_sql.Join.alias`",
@@ -1312,7 +1407,7 @@ class Join(roles.DMLTableRole, FromClause):
j = alias(
select(j.left, j.right).\
select_from(j).\
- apply_labels().\
+ set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL).\
correlate(False),
name=name
)
@@ -2054,9 +2149,7 @@ class Subquery(AliasedReturnsRows):
"use the :meth:`_query.Query.scalar_subquery` method.",
)
def as_scalar(self):
- return self.element._set_label_style(
- LABEL_STYLE_NONE
- ).scalar_subquery()
+ return self.element.set_label_style(LABEL_STYLE_NONE).scalar_subquery()
class FromGrouping(GroupedElement, FromClause):
@@ -2633,7 +2726,7 @@ class SelectBase(
"""
if self._label_style is not LABEL_STYLE_NONE:
- self = self._set_label_style(LABEL_STYLE_NONE)
+ self = self.set_label_style(LABEL_STYLE_NONE)
return ScalarSelect(self)
@@ -2760,6 +2853,14 @@ class SelectStatementGrouping(GroupedElement, SelectBase):
else:
return self
+ def get_label_style(self):
+ return self._label_style
+
+ def set_label_style(self, label_style):
+ return SelectStatementGrouping(
+ self.element.set_label_style(label_style)
+ )
+
@property
def _label_style(self):
return self.element._label_style
@@ -2854,11 +2955,6 @@ class DeprecatedSelectBaseGenerations(object):
self.group_by.non_generative(self, *clauses)
-LABEL_STYLE_NONE = util.symbol("LABEL_STYLE_NONE")
-LABEL_STYLE_TABLENAME_PLUS_COL = util.symbol("LABEL_STYLE_TABLENAME_PLUS_COL")
-LABEL_STYLE_DISAMBIGUATE_ONLY = util.symbol("LABEL_STYLE_DISAMBIGUATE_ONLY")
-
-
class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase):
"""Base class for SELECT statements where additional elements can be
added.
@@ -2892,7 +2988,7 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase):
)
def __init__(
self,
- _label_style=LABEL_STYLE_NONE,
+ _label_style=LABEL_STYLE_DEFAULT,
use_labels=False,
limit=None,
offset=None,
@@ -2901,6 +2997,15 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase):
bind=None,
):
if use_labels:
+ if util.SQLALCHEMY_WARN_20:
+ util.warn_deprecated_20(
+ "The use_labels=True keyword argument to GenerativeSelect "
+ "is deprecated and will be removed in version 2.0. Please "
+ "use "
+ "select.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) "
+ "if you need to replicate this legacy behavior.",
+ stacklevel=4,
+ )
_label_style = LABEL_STYLE_TABLENAME_PLUS_COL
self._label_style = _label_style
@@ -2979,29 +3084,66 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase):
key_share=key_share,
)
- @property
- def use_labels(self):
- return self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL
+ def get_label_style(self):
+ """
+ Retrieve the current label style.
- def apply_labels(self):
- """Return a new selectable with the 'use_labels' flag set to True.
+ .. versionadded:: 1.4
- This will result in column expressions being generated using labels
- against their table name, such as "SELECT somecolumn AS
- tablename_somecolumn". This allows selectables which contain multiple
- FROM clauses to produce a unique set of column names regardless of
- name conflicts among the individual FROM clauses.
+ """
+ return self._label_style
+
+ def set_label_style(self, style):
+ """Return a new selectable with the specified label style.
+
+ There are three "label styles" available,
+ :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`,
+ :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL`, and
+ :data:`_sql.LABEL_STYLE_NONE`. The default style is
+ :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL`.
+
+ In modern SQLAlchemy, there is not generally a need to change the
+ labeling style, as per-expression labels are more effectively used by
+ making use of the :meth:`_sql.ColumnElement.label` method. In past
+ versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to
+ disambiguate same-named columns from different tables, aliases, or
+ subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now
+ applies labels only to names that conflict with an existing name so
+ that the impact of this labeling is minimal.
+
+ The rationale for disambiguation is mostly so that all column
+ expressions are available from a given :attr:`_sql.FromClause.c`
+ collection when a subquery is created.
+
+ .. versionadded:: 1.4 - the
+ :meth:`_sql.GenerativeSelect.set_label_style` method replaces the
+ previous combination of ``.apply_labels()``, ``.with_labels()`` and
+ ``use_labels=True`` methods and/or parameters.
+ .. seealso::
- """
- return self._set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+ :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`
- def _set_label_style(self, style):
+ :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL`
+
+ :data:`_sql.LABEL_STYLE_NONE`
+
+ :data:`_sql.LABEL_STYLE_DEFAULT`
+
+ """
if self._label_style is not style:
self = self._generate()
self._label_style = style
return self
+ @util.deprecated_20(
+ ":meth:`_sql.GenerativeSelect.apply_labels`",
+ alternative="Use set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) "
+ "instead.",
+ )
+ def apply_labels(self):
+ return self.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
+
@property
def _group_by_clause(self):
"""ClauseList access to group_by_clauses for legacy dialects"""
@@ -3525,8 +3667,9 @@ class CompoundSelect(HasCompileState, GenerativeSelect):
# ForeignKeys in. this would allow the union() to have all
# those fks too.
select_0 = self.selects[0]
- if self._label_style is not LABEL_STYLE_NONE:
- select_0 = select_0._set_label_style(self._label_style)
+
+ if self._label_style is not LABEL_STYLE_DEFAULT:
+ select_0 = select_0.set_label_style(self._label_style)
select_0._generate_fromclause_column_proxies(subquery)
# hand-construct the "_proxies" collection to include all
@@ -4347,12 +4490,12 @@ class Select(
This parameter can also be specified on an existing
:class:`_expression.Select` object using the
- :meth:`_expression.Select.apply_labels`
+ :meth:`_expression.Select.set_label_style`
method.
.. seealso::
- :meth:`_expression.Select.apply_labels`
+ :meth:`_expression.Select.set_label_style`
"""
self = cls.__new__(cls)
@@ -4917,7 +5060,8 @@ class Select(
comparison in the WHERE clause of the statement. The primary purpose
of this method is to automatically construct a select statement
with all uniquely-named columns, without the need to use
- table-qualified labels as :meth:`_expression.Select.apply_labels`
+ table-qualified labels as
+ :meth:`_expression.Select.set_label_style`
does.
When columns are omitted based on foreign key, the referred-to
@@ -5263,7 +5407,7 @@ class Select(
def _ensure_disambiguated_names(self):
if self._label_style is LABEL_STYLE_NONE:
- self = self._set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY)
+ self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY)
return self
def _generate_columns_plus_names(self, anon_for_dupe_key):