summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
authorGord Thompson <gord@gordthompson.com>2020-09-13 12:37:40 -0600
committerMike Bayer <mike_mp@zzzcomputing.com>2020-09-28 12:08:04 -0400
commit75ac0abc7d5653d10006769a881374a46b706db5 (patch)
tree9c64b49a6e2ac92741c8a7d56b977e4bf23c287f /lib/sqlalchemy/sql
parent5dcddfd37e2666c298ba934e85be2ac0140efd27 (diff)
downloadsqlalchemy-75ac0abc7d5653d10006769a881374a46b706db5.tar.gz
Add deprecation warning for .join().alias()
The :meth:`_sql.Join.alias` method is deprecated and will be removed in SQLAlchemy 2.0. An explicit select + subquery, or aliasing of the inner tables, should be used instead. Fixes: #5010 Change-Id: Ic913afc31f0d70b0605f9a7af2742a0de1f9ad19
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/coercions.py6
-rw-r--r--lib/sqlalchemy/sql/roles.py14
-rw-r--r--lib/sqlalchemy/sql/selectable.py88
3 files changed, 53 insertions, 55 deletions
diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py
index b8525925b..154564a08 100644
--- a/lib/sqlalchemy/sql/coercions.py
+++ b/lib/sqlalchemy/sql/coercions.py
@@ -55,7 +55,7 @@ def _deep_is_literal(element):
return (
not isinstance(
element,
- (Visitable, schema.SchemaEventTarget, HasCacheKey, Options,),
+ (Visitable, schema.SchemaEventTarget, HasCacheKey, Options),
)
and not hasattr(element, "__clause_element__")
and (
@@ -881,7 +881,9 @@ class AnonymizedFromClauseImpl(StrictFromClauseImpl):
__slots__ = ()
def _post_coercion(self, element, flat=False, name=None, **kw):
- return element.alias(name=name, flat=flat)
+ assert name is None
+
+ return element._anonymous_fromclause(flat=flat)
class DMLTableImpl(_SelectIsNotFrom, _NoTextCoercion, RoleImpl):
diff --git a/lib/sqlalchemy/sql/roles.py b/lib/sqlalchemy/sql/roles.py
index 4205d9f0d..b88625b88 100644
--- a/lib/sqlalchemy/sql/roles.py
+++ b/lib/sqlalchemy/sql/roles.py
@@ -144,19 +144,7 @@ class AnonymizedFromClauseRole(StrictFromClauseRole):
# calls .alias() as a post processor
def _anonymous_fromclause(self, name=None, flat=False):
- """A synonym for ``.alias()`` that is only present on objects of this
- role.
-
- This is an implicit assurance of the target object being part of the
- role where anonymous aliasing without any warnings is allowed,
- as opposed to other kinds of SELECT objects that may or may not have
- an ``.alias()`` method.
-
- The method is used by the ORM but is currently semi-private to
- preserve forwards-compatibility.
-
- """
- return self.alias(name=name, flat=flat)
+ raise NotImplementedError()
class CoerceTextStatementRole(SQLRole):
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index 9440fc48b..2e8f41cc8 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -155,9 +155,7 @@ class ReturnsRows(roles.ReturnsRowsRole, ClauseElement):
class Selectable(ReturnsRows):
- """Mark a class as being selectable.
-
- """
+ """Mark a class as being selectable."""
__visit_name__ = "selectable"
@@ -825,6 +823,9 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
"""
self._reset_column_collection()
+ def _anonymous_fromclause(self, name=None, flat=False):
+ return self.alias(name=name)
+
class Join(roles.DMLTableRole, FromClause):
"""Represent a ``JOIN`` construct between two
@@ -1224,6 +1225,33 @@ class Join(roles.DMLTableRole, FromClause):
return self.left.bind or self.right.bind
@util.preload_module("sqlalchemy.sql.util")
+ def _anonymous_fromclause(self, name=None, flat=False):
+ sqlutil = util.preloaded.sql_util
+ if flat:
+ if name is not None:
+ raise exc.ArgumentError("Can't send name argument with flat")
+ left_a, right_a = (
+ self.left._anonymous_fromclause(flat=True),
+ self.right._anonymous_fromclause(flat=True),
+ )
+ adapter = sqlutil.ClauseAdapter(left_a).chain(
+ sqlutil.ClauseAdapter(right_a)
+ )
+
+ return left_a.join(
+ right_a,
+ adapter.traverse(self.onclause),
+ isouter=self.isouter,
+ full=self.full,
+ )
+ else:
+ return self.select().apply_labels().correlate(None).alias(name)
+
+ @util.deprecated_20(
+ ":meth:`_sql.Join.alias`",
+ alternative="Create a select + subquery, or alias the "
+ "individual tables inside the join, instead.",
+ )
def alias(self, name=None, flat=False):
r"""Return an alias of this :class:`_expression.Join`.
@@ -1246,8 +1274,7 @@ class Join(roles.DMLTableRole, FromClause):
JOIN table_b ON table_a.id = table_b.a_id) AS anon_1
The equivalent long-hand form, given a :class:`_expression.Join`
- object
- ``j``, is::
+ object ``j``, is::
from sqlalchemy import select, alias
j = alias(
@@ -1322,25 +1349,7 @@ class Join(roles.DMLTableRole, FromClause):
:func:`_expression.alias`
"""
- sqlutil = util.preloaded.sql_util
- if flat:
- assert name is None, "Can't send name argument with flat"
- left_a, right_a = (
- self.left.alias(flat=True),
- self.right.alias(flat=True),
- )
- adapter = sqlutil.ClauseAdapter(left_a).chain(
- sqlutil.ClauseAdapter(right_a)
- )
-
- return left_a.join(
- right_a,
- adapter.traverse(self.onclause),
- isouter=self.isouter,
- full=self.full,
- )
- else:
- return self.select().apply_labels().correlate(None).alias(name)
+ return self._anonymous_fromclause(flat=flat, name=name)
@property
def _hide_froms(self):
@@ -1983,9 +1992,7 @@ class Subquery(AliasedReturnsRows):
@classmethod
def _factory(cls, selectable, name=None):
- """Return a :class:`.Subquery` object.
-
- """
+ """Return a :class:`.Subquery` object."""
return coercions.expect(
roles.SelectStatementRole, selectable
).subquery(name=name)
@@ -2035,6 +2042,9 @@ class FromGrouping(GroupedElement, FromClause):
def alias(self, **kw):
return FromGrouping(self.element.alias(**kw))
+ def _anonymous_fromclause(self, **kw):
+ return FromGrouping(self.element._anonymous_fromclause(**kw))
+
@property
def _hide_froms(self):
return self.element._hide_froms
@@ -2294,7 +2304,7 @@ class Values(Generative, FromClause):
_data = ()
_traverse_internals = [
- ("_column_args", InternalTraversal.dp_clauseelement_list,),
+ ("_column_args", InternalTraversal.dp_clauseelement_list),
("_data", InternalTraversal.dp_dml_multi_values),
("name", InternalTraversal.dp_string),
("literal_binds", InternalTraversal.dp_boolean),
@@ -3741,7 +3751,7 @@ class SelectState(util.MemoizedSlots, CompileState):
else:
self.from_clauses = self.from_clauses + (
- Join(left, right, onclause, isouter=isouter, full=full,),
+ Join(left, right, onclause, isouter=isouter, full=full),
)
@util.preload_module("sqlalchemy.sql.util")
@@ -3908,12 +3918,12 @@ class Select(
("_from_obj", InternalTraversal.dp_clauseelement_list),
("_where_criteria", InternalTraversal.dp_clauseelement_tuple),
("_having_criteria", InternalTraversal.dp_clauseelement_tuple),
- ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple,),
- ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple,),
- ("_setup_joins", InternalTraversal.dp_setup_join_tuple,),
- ("_legacy_setup_joins", InternalTraversal.dp_setup_join_tuple,),
+ ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple),
+ ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple),
+ ("_setup_joins", InternalTraversal.dp_setup_join_tuple),
+ ("_legacy_setup_joins", InternalTraversal.dp_setup_join_tuple),
("_correlate", InternalTraversal.dp_clauseelement_tuple),
- ("_correlate_except", InternalTraversal.dp_clauseelement_tuple,),
+ ("_correlate_except", InternalTraversal.dp_clauseelement_tuple),
("_limit_clause", InternalTraversal.dp_clauseelement),
("_offset_clause", InternalTraversal.dp_clauseelement),
("_for_update_arg", InternalTraversal.dp_clauseelement),
@@ -4312,7 +4322,7 @@ class Select(
else:
return cls._create_future_select(*args)
- def __init__(self,):
+ def __init__(self):
raise NotImplementedError()
def _scalar_type(self):
@@ -4537,7 +4547,7 @@ class Select(
:meth:`_expression.Select.join`
"""
- return self.join(target, onclause=onclause, isouter=True, full=full,)
+ return self.join(target, onclause=onclause, isouter=True, full=full)
@property
def froms(self):
@@ -4762,7 +4772,7 @@ class Select(
for c in coercions._expression_collection_was_a_list(
"columns", "Select.with_only_columns", columns
):
- c = coercions.expect(roles.ColumnsClauseRole, c,)
+ c = coercions.expect(roles.ColumnsClauseRole, c)
# TODO: why are we doing this here?
if isinstance(c, ScalarSelect):
c = c.self_group(against=operators.comma_op)
@@ -5312,9 +5322,7 @@ class ScalarSelect(roles.InElementRole, Generative, Grouping):
class Exists(UnaryExpression):
- """Represent an ``EXISTS`` clause.
-
- """
+ """Represent an ``EXISTS`` clause."""
_from_objects = []
inherit_cache = True