From d49eef15bfb759fb33d7d23988cc5a385d9e8a40 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 23 Jul 2021 16:07:50 -0400 Subject: add columns_clause_froms and related use cases Added new attribute :attr:`_sql.Select.columns_clause_froms` that will retrieve the FROM list implied by the columns clause of the :class:`_sql.Select` statement. This differs from the old :attr:`_sql.Select.froms` collection in that it does not perform any ORM compilation steps, which necessarily deannotate the FROM elements and do things like compute joinedloads etc., which makes it not an appropriate candidate for the :meth:`_sql.Select.select_from` method. Additionally adds a new parameter :paramref:`_sql.Select.with_only_columns.maintain_column_froms` that transfers this collection to :meth:`_sql.Select.select_from` before replacing the columns collection. In addition, the :attr:`_sql.Select.froms` is renamed to :meth:`_sql.Select.get_final_froms`, to stress that this collection is not a simple accessor and is instead calculated given the full state of the object, which can be an expensive call when used in an ORM context. Additionally fixes a regression involving the :func:`_orm.with_only_columns` function to support applying criteria to column elements that were replaced with either :meth:`_sql.Select.with_only_columns` or :meth:`_orm.Query.with_entities` , which had broken as part of :ticket:`6503` released in 1.4.19. Fixes: #6808 Change-Id: Ib5d66cce488bbaca06dab4f68fb5cdaa73e8823e --- test/sql/test_deprecations.py | 11 +++++++++++ test/sql/test_selectable.py | 27 ++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'test/sql') diff --git a/test/sql/test_deprecations.py b/test/sql/test_deprecations.py index 44135e373..9b74ab1fa 100644 --- a/test/sql/test_deprecations.py +++ b/test/sql/test_deprecations.py @@ -451,6 +451,17 @@ class SelectableTest(fixtures.TestBase, AssertsCompiledSQL): "deprecated" ) + def test_froms_renamed(self): + t1 = table("t1", column("q")) + + stmt = select(t1) + + with testing.expect_deprecated( + r"The Select.froms attribute is moved to the " + r"Select.get_final_froms\(\) method." + ): + eq_(stmt.froms, [t1]) + def test_select_list_argument(self): with testing.expect_deprecated_20( diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py index 5a94d4038..b76873490 100644 --- a/test/sql/test_selectable.py +++ b/test/sql/test_selectable.py @@ -1,5 +1,4 @@ """Test various algorithmic properties of selectables.""" - from sqlalchemy import and_ from sqlalchemy import bindparam from sqlalchemy import Boolean @@ -590,6 +589,32 @@ class SelectableTest( "table1.col3, table1.colx FROM table1) AS anon_1", ) + @testing.combinations( + ( + [table1.c.col1], + [table1.join(table2)], + [table1.join(table2)], + [table1], + ), + ([table1], [table2], [table1, table2], [table1]), + ( + [table1.c.col1, table2.c.col1], + [], + [table1, table2], + [table1, table2], + ), + ) + def test_froms_accessors( + self, cols_expr, select_from, exp_final_froms, exp_cc_froms + ): + """tests for #6808""" + s1 = select(*cols_expr).select_from(*select_from) + + for ff, efp in util.zip_longest(s1.get_final_froms(), exp_final_froms): + assert ff.compare(efp) + + eq_(s1.columns_clause_froms, exp_cc_froms) + def test_scalar_subquery_from_subq_same_source(self): s1 = select(table1.c.col1) -- cgit v1.2.1