--- /dev/null
+.. change::
+ :tags: change, sql
+ :tickets: 10236
+
+ The ``.c`` and ``.columns`` attributes on the :class:`.Select` and
+ :class:`.TextualSelect` constructs, which are not instances of
+ :class:`.FromClause`, have been removed completely, in addition to the
+ ``.select()`` method as well as other codepaths which would implicitly
+ generate a subquery from a :class:`.Select` without the need to explicitly
+ call the :meth:`.Select.subquery` method.
+
+ In the case of ``.c`` and ``.columns``, these attributes were never useful
+ in practice and have caused a great deal of confusion, hence were
+ deprecated back in version 1.4, and have emitted warnings since that
+ version. Accessing the columns that are specific to a :class:`.Select`
+ construct is done via the :attr:`.Select.selected_columns` attribute, which
+ was added in version 1.4 to suit the use case that users often expected
+ ``.c`` to accomplish. In the larger sense, implicit production of
+ subqueries works against SQLAlchemy's modern practice of making SQL
+ structure as explicit as possible.
+
+ Note that this is **not related** to the usual :attr:`.FromClause.c` and
+ :attr:`.FromClause.columns` attributes, common to objects such as
+ :class:`.Table` and :class:`.Subquery`, which are unaffected by this
+ change.
+
+ .. seealso::
+
+ :ref:`change_4617` - original notes from SQLAlchemy 1.4
+
_role_name = "ORM mapped or aliased entity"
-class ORMFromClauseRole(roles.StrictFromClauseRole):
+class ORMFromClauseRole(roles.FromClauseRole):
__slots__ = ()
_role_name = "ORM mapped entity, aliased entity, or FROM expression"
if local_table is not None:
self.local_table = coercions.expect(
- roles.StrictFromClauseRole,
+ roles.FromClauseRole,
local_table,
disable_inspection=True,
argname="local_table",
self.with_polymorphic = (
self.with_polymorphic[0],
coercions.expect(
- roles.StrictFromClauseRole,
+ roles.FromClauseRole,
self.with_polymorphic[1],
- allow_select=True,
),
)
) -> Tuple[Sequence[Mapper[Any]], FromClause]:
if selectable not in (None, False):
selectable = coercions.expect(
- roles.StrictFromClauseRole, selectable, allow_select=True
+ roles.FromClauseRole,
+ selectable,
)
if self.with_polymorphic:
) -> None:
fa = [
coercions.expect(
- roles.StrictFromClauseRole,
+ roles.FromClauseRole,
elem,
- allow_select=True,
apply_propagate_attrs=self,
)
for elem in obj
for key in table_map:
table = table_map[key]
- table = coercions.expect(
- roles.StrictFromClauseRole, table, allow_select=True
- )
+ table = coercions.expect(roles.FromClauseRole, table)
table_map[key] = table
m = {}
argname: Optional[str] = None,
*,
explicit_subquery: bool = False,
- allow_select: bool = True,
**kw: Any,
) -> Any:
- if resolved._is_select_base:
- if explicit_subquery:
- return resolved.subquery()
- elif allow_select:
- util.warn_deprecated(
- "Implicit coercion of SELECT and textual SELECT "
- "constructs into FROM clauses is deprecated; please call "
- ".subquery() on any Core select or ORM Query object in "
- "order to produce a subquery object.",
- version="1.4",
- )
- return resolved._implicit_subquery
- elif resolved._is_text_clause:
- return resolved
- else:
- self._raise_for_expected(element, argname, resolved)
+ if resolved._is_select_base and explicit_subquery:
+ return resolved.subquery()
+
+ self._raise_for_expected(element, argname, resolved)
def _post_coercion(self, element, *, deannotate=False, **kw):
if deannotate:
return element
-class StrictFromClauseImpl(FromClauseImpl):
- __slots__ = ()
-
- def _implicit_coercions(
- self,
- element: Any,
- resolved: Any,
- argname: Optional[str] = None,
- *,
- allow_select: bool = False,
- **kw: Any,
- ) -> Any:
- if resolved._is_select_base and allow_select:
- util.warn_deprecated(
- "Implicit coercion of SELECT and textual SELECT constructs "
- "into FROM clauses is deprecated; please call .subquery() "
- "on any Core select or ORM Query object in order to produce a "
- "subquery object.",
- version="1.4",
- )
- return resolved._implicit_subquery
- else:
- self._raise_for_expected(element, argname, resolved)
-
-
-class AnonymizedFromClauseImpl(StrictFromClauseImpl):
+class AnonymizedFromClauseImpl(FromClauseImpl):
__slots__ = ()
def _post_coercion(self, element, *, flat=False, name=None, **kw):
named_with_column: bool
-class StrictFromClauseRole(FromClauseRole):
- __slots__ = ()
- # does not allow text() or select() objects
-
-
-class AnonymizedFromClauseRole(StrictFromClauseRole):
+class AnonymizedFromClauseRole(FromClauseRole):
__slots__ = ()
if TYPE_CHECKING:
) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
"""A :class:`_expression.ColumnCollection`
that represents the "exported"
- columns of this :class:`_expression.Selectable`.
+ columns of this :class:`_expression.FromClause`.
The "exported" columns for a :class:`_expression.FromClause`
object are synonymous
name: Optional[str] = None,
flat: bool = False,
) -> NamedFromClause:
- return coercions.expect(
- roles.FromClauseRole, selectable, allow_select=True
- ).alias(name=name, flat=flat)
+ return coercions.expect(roles.FromClauseRole, selectable).alias(
+ name=name, flat=flat
+ )
class TableValuedAlias(LateralFromClause, Alias):
"""
return self.selected_columns.as_readonly()
- @property
- @util.deprecated(
- "1.4",
- "The :attr:`_expression.SelectBase.c` and "
- ":attr:`_expression.SelectBase.columns` attributes "
- "are deprecated and will be removed in a future release; these "
- "attributes implicitly create a subquery that should be explicit. "
- "Please call :meth:`_expression.SelectBase.subquery` "
- "first in order to create "
- "a subquery, which then contains this attribute. To access the "
- "columns that this SELECT object SELECTs "
- "from, use the :attr:`_expression.SelectBase.selected_columns` "
- "attribute.",
- )
- def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
- return self._implicit_subquery.columns
-
- @property
- def columns(
- self,
- ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
- return self.c
-
def get_label_style(self) -> SelectLabelStyle:
"""
Retrieve the current label style.
raise NotImplementedError()
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.SelectBase.select` method is deprecated "
- "and will be removed in a future release; this method implicitly "
- "creates a subquery that should be explicit. "
- "Please call :meth:`_expression.SelectBase.subquery` "
- "first in order to create "
- "a subquery, which then can be selected.",
- )
- def select(self, *arg: Any, **kw: Any) -> Select[Unpack[TupleAny]]:
- return self._implicit_subquery.select(*arg, **kw)
-
- @HasMemoized.memoized_attribute
- def _implicit_subquery(self) -> Subquery:
- return self.subquery()
-
def _scalar_type(self) -> TypeEngine[Any]:
raise NotImplementedError()
# the MIT License: https://www.opensource.org/licenses/mit-license.php
from .test_cte import * # noqa
from .test_ddl import * # noqa
-from .test_deprecations import * # noqa
from .test_dialect import * # noqa
from .test_insert import * # noqa
from .test_reflection import * # noqa
+++ /dev/null
-# testing/suite/test_deprecations.py
-# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
-# <see AUTHORS file>
-#
-# This module is part of SQLAlchemy and is released under
-# the MIT License: https://www.opensource.org/licenses/mit-license.php
-# mypy: ignore-errors
-
-from .. import fixtures
-from ..assertions import eq_
-from ..schema import Column
-from ..schema import Table
-from ... import Integer
-from ... import select
-from ... import testing
-from ... import union
-
-
-class DeprecatedCompoundSelectTest(fixtures.TablesTest):
- __backend__ = True
-
- @classmethod
- def define_tables(cls, metadata):
- Table(
- "some_table",
- metadata,
- Column("id", Integer, primary_key=True),
- Column("x", Integer),
- Column("y", Integer),
- )
-
- @classmethod
- def insert_data(cls, connection):
- connection.execute(
- cls.tables.some_table.insert(),
- [
- {"id": 1, "x": 1, "y": 2},
- {"id": 2, "x": 2, "y": 3},
- {"id": 3, "x": 3, "y": 4},
- {"id": 4, "x": 4, "y": 5},
- ],
- )
-
- def _assert_result(self, conn, select, result, params=None):
- eq_(conn.execute(select, params).fetchall(), result)
-
- def test_plain_union(self, connection):
- table = self.tables.some_table
- s1 = select(table).where(table.c.id == 2)
- s2 = select(table).where(table.c.id == 3)
-
- u1 = union(s1, s2)
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns "
- "attributes are deprecated"
- ):
- self._assert_result(
- connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
- )
-
- # note we've had to remove one use case entirely, which is this
- # one. the Select gets its FROMS from the WHERE clause and the
- # columns clause, but not the ORDER BY, which means the old ".c" system
- # allowed you to "order_by(s.c.foo)" to get an unnamed column in the
- # ORDER BY without adding the SELECT into the FROM and breaking the
- # query. Users will have to adjust for this use case if they were doing
- # it before.
- def _dont_test_select_from_plain_union(self, connection):
- table = self.tables.some_table
- s1 = select(table).where(table.c.id == 2)
- s2 = select(table).where(table.c.id == 3)
-
- u1 = union(s1, s2).alias().select()
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns "
- "attributes are deprecated"
- ):
- self._assert_result(
- connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
- )
-
- @testing.requires.order_by_col_from_union
- @testing.requires.parens_in_union_contained_select_w_limit_offset
- def test_limit_offset_selectable_in_unions(self, connection):
- table = self.tables.some_table
- s1 = select(table).where(table.c.id == 2).limit(1).order_by(table.c.id)
- s2 = select(table).where(table.c.id == 3).limit(1).order_by(table.c.id)
-
- u1 = union(s1, s2).limit(2)
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns "
- "attributes are deprecated"
- ):
- self._assert_result(
- connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
- )
-
- @testing.requires.parens_in_union_contained_select_wo_limit_offset
- def test_order_by_selectable_in_unions(self, connection):
- table = self.tables.some_table
- s1 = select(table).where(table.c.id == 2).order_by(table.c.id)
- s2 = select(table).where(table.c.id == 3).order_by(table.c.id)
-
- u1 = union(s1, s2).limit(2)
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns "
- "attributes are deprecated"
- ):
- self._assert_result(
- connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
- )
-
- def test_distinct_selectable_in_unions(self, connection):
- table = self.tables.some_table
- s1 = select(table).where(table.c.id == 2).distinct()
- s2 = select(table).where(table.c.id == 3).distinct()
-
- u1 = union(s1, s2).limit(2)
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns "
- "attributes are deprecated"
- ):
- self._assert_result(
- connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
- )
-
- def test_limit_offset_aliased_selectable_in_unions(self, connection):
- table = self.tables.some_table
- s1 = (
- select(table)
- .where(table.c.id == 2)
- .limit(1)
- .order_by(table.c.id)
- .alias()
- .select()
- )
- s2 = (
- select(table)
- .where(table.c.id == 3)
- .limit(1)
- .order_by(table.c.id)
- .alias()
- .select()
- )
-
- u1 = union(s1, s2).limit(2)
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns "
- "attributes are deprecated"
- ):
- self._assert_result(
- connection, u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
- )
# in pysqlite itself. background at:
# https://thread.gmane.org/gmane.comp.python.db.pysqlite.user/2290
- @testing.crashes("mysql+cymysql", "blocking")
- def test_join_cache_deprecated_coercion(self):
- metadata = MetaData()
- table1 = Table(
- "table1",
- metadata,
- Column(
- "id", Integer, primary_key=True, test_needs_autoincrement=True
- ),
- Column("data", String(30)),
- )
- table2 = Table(
- "table2",
- metadata,
- Column(
- "id", Integer, primary_key=True, test_needs_autoincrement=True
- ),
- Column("data", String(30)),
- Column("t1id", Integer, ForeignKey("table1.id")),
- )
-
- class Foo:
- pass
-
- class Bar:
- pass
-
- self.mapper_registry.map_imperatively(
- Foo,
- table1,
- properties={
- "bars": relationship(
- self.mapper_registry.map_imperatively(Bar, table2)
- )
- },
- )
- metadata.create_all(self.engine)
- session = sessionmaker(self.engine)
-
- @profile_memory()
- def go():
- s = table2.select()
- sess = session()
- with testing.expect_deprecated(
- "Implicit coercion of SELECT and textual SELECT constructs",
- "An alias is being generated automatically",
- assert_=False,
- ):
- sess.query(Foo).join(s, Foo.bars).all()
- sess.rollback()
-
- try:
- go()
- finally:
- metadata.drop_all(self.engine)
-
@testing.crashes("mysql+cymysql", "blocking")
def test_join_cache(self):
metadata = MetaData()
from sqlalchemy.orm import with_parent
from sqlalchemy.orm import with_polymorphic
from sqlalchemy.orm.collections import collection
-from sqlalchemy.orm.util import polymorphic_union
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import assertions
from sqlalchemy.testing import AssertsCompiledSQL
from sqlalchemy.testing import expect_raises_message
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
-from sqlalchemy.testing import is_true
from sqlalchemy.testing import mock
from sqlalchemy.testing.entities import ComparableEntity
from sqlalchemy.testing.fixtures import CacheKeyFixture
def setup_mappers(cls):
cls._setup_stock_mapping()
- @classmethod
- def _expect_implicit_subquery(cls):
- return assertions.expect_deprecated(
- "Implicit coercion of SELECT and textual SELECT constructs into "
- r"FROM clauses is deprecated; please call \.subquery\(\) on any "
- "Core select or ORM Query object in order to produce a "
- "subquery object."
- )
-
- def test_deprecated_select_coercion_join_target(self):
- User = self.classes.User
- addresses = self.tables.addresses
-
- s = addresses.select()
- sess = fixture_session()
- with testing.expect_deprecated(
- "Implicit coercion of SELECT and textual SELECT constructs",
- "An alias is being generated automatically against joined entity",
- ):
- self.assert_compile(
- sess.query(User).join(s, User.addresses),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users JOIN (SELECT addresses.id AS id, "
- "addresses.user_id AS user_id, addresses.email_address "
- "AS email_address FROM addresses) AS anon_1 "
- "ON users.id = anon_1.user_id",
- )
-
def test_invalid_column(self):
User = self.classes.User
):
s.query(User).as_scalar()
- def test_select_from_q_statement_no_aliasing(self):
- User = self.classes.User
- sess = fixture_session()
-
- q = sess.query(User)
- with self._expect_implicit_subquery():
- q = sess.query(User).select_from(User, q.statement)
- self.assert_compile(
- q.filter(User.name == "ed"),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users, (SELECT users.id AS id, users.name AS name FROM "
- "users) AS anon_1 WHERE users.name = :name_1",
- )
-
def test_apply_labels(self):
User = self.classes.User
self.assert_sql_count(testing.db, go, expected)
-class DeprecatedInhTest(_poly_fixtures._Polymorphic):
- def test_with_polymorphic(self):
- Person = _poly_fixtures.Person
- Engineer = _poly_fixtures.Engineer
-
- with DeprecatedQueryTest._expect_implicit_subquery():
- p_poly = with_polymorphic(Person, [Engineer], select(Person))
-
- is_true(
- sa.inspect(p_poly).selectable.compare(select(Person).subquery())
- )
-
-
class DeprecatedMapperTest(
fixtures.RemovesEvents, _fixtures.FixtureTest, AssertsCompiledSQL
):
):
is_(manager.deferred_scalar_loader, myloader)
- def test_polymorphic_union_w_select(self):
- users, addresses = self.tables.users, self.tables.addresses
-
- with DeprecatedQueryTest._expect_implicit_subquery():
- dep = polymorphic_union(
- {"u": users.select(), "a": addresses.select()},
- "type",
- "bcjoin",
- )
-
- subq_version = polymorphic_union(
- {
- "u": users.select().subquery(),
- "a": addresses.select().subquery(),
- },
- "type",
- "bcjoin",
- )
- is_true(dep.compare(subq_version))
-
def test_comparable_column(self):
users, User = self.tables.users, self.classes.User
assert not hasattr(table1.select().subquery().c.myid, "columns")
assert not hasattr(table1.alias().c.myid, "columns")
assert not hasattr(table1.alias().c.myid, "c")
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns attributes are "
- "deprecated"
- ):
- assert hasattr(table1.select(), "c")
assert_raises_message(
exc.InvalidRequestError,
-from sqlalchemy import alias
from sqlalchemy import and_
-from sqlalchemy import bindparam
from sqlalchemy import CHAR
from sqlalchemy import column
from sqlalchemy import exc
from sqlalchemy import ForeignKey
from sqlalchemy import func
from sqlalchemy import Integer
-from sqlalchemy import join
from sqlalchemy import literal_column
from sqlalchemy import MetaData
-from sqlalchemy import null
from sqlalchemy import or_
from sqlalchemy import schema
from sqlalchemy import select
from sqlalchemy import Sequence
-from sqlalchemy import sql
from sqlalchemy import String
from sqlalchemy import table
from sqlalchemy import testing
-from sqlalchemy import text
from sqlalchemy.engine import default
-from sqlalchemy.sql import coercions
-from sqlalchemy.sql import LABEL_STYLE_TABLENAME_PLUS_COL
from sqlalchemy.sql import operators
-from sqlalchemy.sql import quoted_name
-from sqlalchemy.sql import roles
-from sqlalchemy.sql import visitors
-from sqlalchemy.sql.selectable import SelectStatementGrouping
from sqlalchemy.testing import assertions
from sqlalchemy.testing import AssertsCompiledSQL
from sqlalchemy.testing import config
"myothertable", column("otherid", Integer), column("othername", String)
)
- def test_select_of_select(self):
- stmt = select(self.table1.c.myid)
-
- with testing.expect_deprecated(
- r"The SelectBase.select\(\) method is deprecated and will be "
- "removed"
- ):
- self.assert_compile(
- stmt.select(),
- "SELECT anon_1.myid FROM (SELECT mytable.myid AS myid "
- "FROM mytable) AS anon_1",
- )
-
- def test_standalone_alias(self):
- with testing.expect_deprecated(
- "Implicit coercion of SELECT and textual SELECT constructs"
- ):
- stmt = alias(select(self.table1.c.myid), "foo")
-
- self.assert_compile(stmt, "SELECT mytable.myid FROM mytable")
-
- is_true(
- stmt.compare(select(self.table1.c.myid).subquery().alias("foo"))
- )
-
def test_as_scalar(self):
with testing.expect_deprecated(
r"The SelectBase.as_scalar\(\) method is deprecated and "
is_true(stmt.compare(select(self.table1.c.myid).scalar_subquery()))
- def test_fromclause_subquery(self):
- stmt = select(self.table1.c.myid)
- with testing.expect_deprecated(
- "Implicit coercion of SELECT and textual SELECT constructs "
- "into FROM clauses is deprecated"
- ):
- coerced = coercions.expect(
- roles.StrictFromClauseRole, stmt, allow_select=True
- )
-
- is_true(coerced.compare(stmt.subquery()))
-
- def test_plain_fromclause_select_to_subquery(self):
- with testing.expect_deprecated(
- "Implicit coercion of SELECT and textual SELECT "
- "constructs into FROM clauses is deprecated;"
- ):
- element = coercions.expect(
- roles.FromClauseRole,
- SelectStatementGrouping(select(self.table1)),
- )
- is_true(
- element.compare(
- SelectStatementGrouping(select(self.table1)).subquery()
- )
- )
-
- def test_functions_select_method_two(self):
- expr = func.rows("foo")
- with testing.expect_deprecated(
- "Implicit coercion of SELECT and textual SELECT constructs "
- "into FROM clauses is deprecated"
- ):
- stmt = select("*").select_from(expr.select())
- self.assert_compile(
- stmt, "SELECT * FROM (SELECT rows(:rows_2) AS rows_1) AS anon_1"
- )
-
- def test_functions_with_cols(self):
- users = table(
- "users", column("id"), column("name"), column("fullname")
- )
- calculate = select(column("q"), column("z"), column("r")).select_from(
- func.calculate(bindparam("x", None), bindparam("y", None))
- )
-
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns attributes are "
- "deprecated and will be removed"
- ):
- self.assert_compile(
- select(users).where(users.c.id > calculate.c.z),
- "SELECT users.id, users.name, users.fullname "
- "FROM users, (SELECT q, z, r "
- "FROM calculate(:x, :y)) AS anon_1 "
- "WHERE users.id > anon_1.z",
- )
-
class LateralSubqueryCoercionsTest(fixtures.TablesTest, AssertsCompiledSQL):
__dialect__ = default.DefaultDialect(supports_native_boolean=True)
"ON basefrom.a = joinfrom.a",
)
- def test_against_cloned_non_table(self):
- # test that corresponding column digs across
- # clone boundaries with anonymous labeled elements
- col = func.count().label("foo")
- sel = select(col)
-
- sel2 = visitors.ReplacingCloningVisitor().traverse(sel)
- with testing.expect_deprecated("The SelectBase.c"):
- assert (
- sel2._implicit_subquery.corresponding_column(col) is sel2.c.foo
- )
-
- sel3 = visitors.ReplacingCloningVisitor().traverse(sel2)
- with testing.expect_deprecated("The SelectBase.c"):
- assert (
- sel3._implicit_subquery.corresponding_column(col) is sel3.c.foo
- )
-
- def test_alias_union(self):
- # same as testunion, except its an alias of the union
-
- u = (
- select(
- self.table1.c.col1,
- self.table1.c.col2,
- self.table1.c.col3,
- self.table1.c.colx,
- null().label("coly"),
- )
- .union(
- select(
- self.table2.c.col1,
- self.table2.c.col2,
- self.table2.c.col3,
- null().label("colx"),
- self.table2.c.coly,
- )
- )
- .alias("analias")
- )
- s1 = self.table1.select().set_label_style(
- LABEL_STYLE_TABLENAME_PLUS_COL
- )
- s2 = self.table2.select().set_label_style(
- LABEL_STYLE_TABLENAME_PLUS_COL
- )
- with self._c_deprecated():
- assert u.corresponding_column(s1.c.table1_col2) is u.c.col2
- assert u.corresponding_column(s2.c.table2_col2) is u.c.col2
- assert u.corresponding_column(s2.c.table2_coly) is u.c.coly
- assert s2.c.corresponding_column(u.c.coly) is s2.c.table2_coly
-
- def test_join_against_self_implicit_subquery(self):
- jj = select(self.table1.c.col1.label("bar_col1"))
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns attributes are "
- "deprecated and will be removed",
- "Implicit coercion of SELECT",
- ):
- jjj = join(self.table1, jj, self.table1.c.col1 == jj.c.bar_col1)
-
- jjj_bar_col1 = jjj.c["%s_bar_col1" % jj._implicit_subquery.name]
- assert jjj_bar_col1 is not None
-
- # test column directly against itself
-
- assert jjj.corresponding_column(jjj.c.table1_col1) is jjj.c.table1_col1
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns attributes are "
- "deprecated and will be removed"
- ):
- assert jjj.corresponding_column(jj.c.bar_col1) is jjj_bar_col1
-
- def test_select_labels(self):
- a = self.table1.select().set_label_style(
- LABEL_STYLE_TABLENAME_PLUS_COL
- )
- j = join(a._implicit_subquery, self.table2)
-
- criterion = a._implicit_subquery.c.table1_col1 == self.table2.c.col2
- self.assert_(criterion.compare(j.onclause))
-
-
-class QuoteTest(fixtures.TestBase, AssertsCompiledSQL):
- __dialect__ = "default"
-
- def test_literal_column_label_embedded_select_samename_explicit_quote(
- self,
- ):
- col = sql.literal_column("NEEDS QUOTES").label(
- quoted_name("NEEDS QUOTES", True)
- )
-
- with testing.expect_deprecated(
- r"The SelectBase.select\(\) method is deprecated"
- ):
- self.assert_compile(
- select(col).select(),
- 'SELECT anon_1."NEEDS QUOTES" FROM '
- '(SELECT NEEDS QUOTES AS "NEEDS QUOTES") AS anon_1',
- )
-
- def test_literal_column_label_embedded_select_diffname_explicit_quote(
- self,
- ):
- col = sql.literal_column("NEEDS QUOTES").label(
- quoted_name("NEEDS QUOTES_", True)
- )
-
- with testing.expect_deprecated(
- r"The SelectBase.select\(\) method is deprecated"
- ):
- self.assert_compile(
- select(col).select(),
- 'SELECT anon_1."NEEDS QUOTES_" FROM '
- '(SELECT NEEDS QUOTES AS "NEEDS QUOTES_") AS anon_1',
- )
-
- def test_literal_column_label_embedded_select_diffname(self):
- col = sql.literal_column("NEEDS QUOTES").label("NEEDS QUOTES_")
-
- with testing.expect_deprecated(
- r"The SelectBase.select\(\) method is deprecated"
- ):
- self.assert_compile(
- select(col).select(),
- 'SELECT anon_1."NEEDS QUOTES_" FROM (SELECT NEEDS QUOTES AS '
- '"NEEDS QUOTES_") AS anon_1',
- )
-
- def test_literal_column_label_embedded_select_samename(self):
- col = sql.literal_column("NEEDS QUOTES").label("NEEDS QUOTES")
-
- with testing.expect_deprecated(
- r"The SelectBase.select\(\) method is deprecated"
- ):
- self.assert_compile(
- select(col).select(),
- 'SELECT anon_1."NEEDS QUOTES" FROM (SELECT NEEDS QUOTES AS '
- '"NEEDS QUOTES") AS anon_1',
- )
-
-
-class TextualSelectTest(fixtures.TestBase, AssertsCompiledSQL):
- __dialect__ = "default"
-
- table1 = table(
- "mytable",
- column("myid", Integer),
- column("name", String),
- column("description", String),
- )
-
- table2 = table(
- "myothertable", column("otherid", Integer), column("othername", String)
- )
-
- def test_basic_subquery_resultmap(self):
- table1 = self.table1
- t = text("select id, name from user").columns(id=Integer, name=String)
-
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns", "Implicit coercion"
- ):
- stmt = select(table1.c.myid).select_from(
- table1.join(t, table1.c.myid == t.c.id)
- )
- compiled = stmt.compile()
- eq_(
- compiled._create_result_map(),
- {
- "myid": (
- "myid",
- (table1.c.myid, "myid", "myid", "mytable_myid"),
- table1.c.myid.type,
- 0,
- )
- },
- )
-
- def test_column_collection_ordered(self):
- t = text("select a, b, c from foo").columns(
- column("a"), column("b"), column("c")
- )
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns"
- ):
- eq_(t.c.keys(), ["a", "b", "c"])
-
- def test_column_collection_pos_plus_bykey(self):
- # overlapping positional names + type names
- t = text("select a, b, c from foo").columns(
- column("a"), column("b"), b=Integer, c=String
- )
-
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns"
- ):
- eq_(t.c.keys(), ["a", "b", "c"])
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns"
- ):
- eq_(t.c.b.type._type_affinity, Integer)
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns"
- ):
- eq_(t.c.c.type._type_affinity, String)
-
class KeyTargetingTest(fixtures.TablesTest):
run_inserts = "once"
c1 = Column("foo", self._add_override_factory())
self._assert_add_override(c1)
- def test_column_proxy(self):
- t = Table("t", MetaData(), Column("foo", self._add_override_factory()))
- with testing.expect_deprecated(
- "The SelectBase.c and SelectBase.columns attributes "
- "are deprecated"
- ):
- proxied = t.select().c.foo
- self._assert_add_override(proxied)
- self._assert_and_override(proxied)
-
def test_subquery_proxy(self):
t = Table("t", MetaData(), Column("foo", self._add_override_factory()))
proxied = t.select().subquery().c.foo
from sqlalchemy.testing import assert_raises
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import AssertsCompiledSQL
+from sqlalchemy.testing import expect_raises_message
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
from sqlalchemy.testing import is_instance_of
)
def test_select_is_coerced_into_fromclause_w_deprecation(self):
- with testing.expect_deprecated(
- "Implicit coercion of SELECT and textual SELECT "
- "constructs into FROM clauses is deprecated;"
+ with testing.expect_raises_message(
+ exc.ArgumentError,
+ r"FROM expression, such as a Table or alias\(\) object expected",
):
- element = expect(
- roles.FromClauseRole, SelectStatementGrouping(select(t))
- )
- is_true(
- element.compare(SelectStatementGrouping(select(t)).subquery())
- )
+ expect(roles.FromClauseRole, SelectStatementGrouping(select(t)))
def test_offset_or_limit_role_only_ints_or_clauseelement(self):
assert_raises(ValueError, select(t).limit, "some limit")
d1 = DDL("hi")
is_(expect(roles.StatementRole, d1), d1)
- def test_strict_from_clause_role(self):
+ def test_from_clause_role(self):
stmt = select(t).subquery()
is_true(
- expect(roles.StrictFromClauseRole, stmt).compare(
- select(t).subquery()
- )
+ expect(roles.FromClauseRole, stmt).compare(select(t).subquery())
)
- def test_strict_from_clause_role_disallow_select(self):
+ def test_from_clause_role_disallow_select(self):
stmt = select(t)
assert_raises_message(
exc.ArgumentError,
r"FROM expression, such as a Table or alias\(\) "
"object expected, got .*Select",
expect,
- roles.StrictFromClauseRole,
+ roles.FromClauseRole,
stmt,
)
coerced = coercions.expect(role, stmt.alias())
is_true(coerced.compare(stmt.scalar_subquery()))
+ def test_fromclause_subquery(self):
+ stmt = select(self.table1.c.myid)
+ with expect_raises_message(
+ exc.ArgumentError,
+ r"FROM expression, such as a Table or alias\(\) object expected",
+ ):
+ coercions.expect(roles.FromClauseRole, stmt)
+
+ def test_plain_fromclause_select_to_subquery(self):
+ with expect_raises_message(
+ exc.ArgumentError,
+ r"FROM expression, such as a Table or alias\(\) object expected",
+ ):
+ coercions.expect(
+ roles.FromClauseRole,
+ SelectStatementGrouping(select(self.table1)),
+ )
+
def test_labeled_role(self):
stmt = select(self.table1.c.myid)
"SELECT table1.col1 AS a FROM table1) AS b) AS c) AS anon_1",
)
- def test_self_referential_select_raises(self):
- t = table("t", column("x"))
-
- # this issue is much less likely as subquery() applies a labeling
- # style to the select, eliminating the self-referential call unless
- # the select already had labeling applied
-
- s = select(t).set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
-
- with testing.expect_deprecated("The SelectBase.c"):
- s.where.non_generative(s, s.c.t_x > 5)
-
- assert_raises_message(
- exc.InvalidRequestError,
- r"select\(\) construct refers to itself as a FROM",
- s.compile,
- )
-
def test_unusual_column_elements_text(self):
"""test that .c excludes text()."""