]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
warnings: select_entity_from()
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 22 Oct 2021 21:37:07 +0000 (17:37 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 25 Oct 2021 23:45:28 +0000 (19:45 -0400)
Change-Id: I8c259e61134c38a1fa907c308068337473c82914

lib/sqlalchemy/orm/context.py
lib/sqlalchemy/testing/warnings.py
test/orm/inheritance/test_basic.py
test/orm/inheritance/test_single.py
test/orm/test_deprecations.py
test/orm/test_froms.py
test/orm/test_joins.py
test/orm/test_query.py

index 45df57c5d112d17207dcae7a20c8814661a2700b..0a93d993af48935c79d51b8199f97290864e0db4 100644 (file)
@@ -1251,8 +1251,12 @@ class ORMSelectCompileState(ORMCompileState, SelectState):
 
         adapters = []
 
-        # vvvvvvvvvvvvvvv legacy vvvvvvvvvvvvvvvvvv
         if self._from_obj_alias:
+            # used for legacy going forward for query set_ops, e.g.
+            # union(), union_all(), etc.
+            # 1.4 and previously, also used for from_self(),
+            # select_entity_from()
+            #
             # for the "from obj" alias, apply extra rule to the
             # 'ORM only' check, if this query were generated from a
             # subquery of itself, i.e. _from_selectable(), apply adaption
@@ -1266,11 +1270,15 @@ class ORMSelectCompileState(ORMCompileState, SelectState):
                 )
             )
 
+        # vvvvvvvvvvvvvvv legacy vvvvvvvvvvvvvvvvvv
+        # this can totally go away when we remove join(..., aliased=True)
         if self._aliased_generations:
             adapters.append((False, self._adapt_aliased_generation))
         # ^^^^^^^^^^^^^ legacy ^^^^^^^^^^^^^^^^^^^^^
 
-        # this is the only adapter we would need going forward...
+        # this was *hopefully* the only adapter we were going to need
+        # going forward...however, we unfortunately need _from_obj_alias
+        # for query.union(), which we can't drop
         if self._polymorphic_adapters:
             adapters.append((False, self._adapt_polymorphic_element))
 
index 9886b122d104c9b25ca947c78e46aef5a174b627..40d03f0afee0904e30ece030749845753ceca415 100644 (file)
@@ -71,7 +71,6 @@ def setup_filters():
         r"The Query\.get\(\) method",
         r"The Query\.with_parent\(\) method",
         r"The Query\.with_parent\(\) method",
-        r"The Query\.select_entity_from\(\) method",
         r"The ``aliased`` and ``from_joinpoint`` keyword arguments",
         r"The Query.with_polymorphic\(\) method is considered "
         "legacy as of the 1.x series",
index e870a80f0d85f9e889d2069b78b4ca2d411a63cd..ac1661fdd16493a5c1f842ba397447d4ea2a565d 100644 (file)
@@ -3684,7 +3684,7 @@ class UnexpectedPolymorphicIdentityTest(fixtures.DeclarativeMappedTest):
 
         s = fixture_session()
 
-        q = s.query(ASingleSubA).select_entity_from(select(ASingle).subquery())
+        q = s.query(ASingleSubA).from_statement(select(ASingle))
 
         assert_raises_message(
             sa_exc.InvalidRequestError,
@@ -3700,7 +3700,7 @@ class UnexpectedPolymorphicIdentityTest(fixtures.DeclarativeMappedTest):
 
         s = fixture_session()
 
-        q = s.query(AJoinedSubA).select_entity_from(select(AJoined).subquery())
+        q = s.query(AJoinedSubA).from_statement(select(AJoined))
 
         assert_raises_message(
             sa_exc.InvalidRequestError,
index 690bdfc577a37deeb707441bc9c94d8ad675eb23..066f781d88aea5f531ed1432e211cafea7b87b35 100644 (file)
@@ -542,17 +542,16 @@ class SingleInheritanceTest(testing.AssertsCompiledSQL, fixtures.MappedTest):
         sess.add_all([m1, m2, e1, e2])
         sess.flush()
 
-        # note test_basic -> UnexpectedPolymorphicIdentityTest as well
+        ma = aliased(
+            Manager,
+            employees.select()
+            .where(employees.c.type == "manager")
+            .order_by(employees.c.employee_id)
+            .limit(10)
+            .subquery(),
+        )
         eq_(
-            sess.query(Manager)
-            .select_entity_from(
-                employees.select()
-                .where(employees.c.type == "manager")
-                .order_by(employees.c.employee_id)
-                .limit(10)
-                .subquery()
-            )
-            .all(),
+            sess.query(ma).all(),
             [m1, m2],
         )
 
@@ -582,24 +581,38 @@ class SingleInheritanceTest(testing.AssertsCompiledSQL, fixtures.MappedTest):
         sess.add_all([m1, m2, e1, e2])
         sess.flush()
 
-        stmt = (
-            select(reports, employees)
-            .select_from(
-                reports.outerjoin(
-                    employees,
-                    and_(
-                        employees.c.employee_id == reports.c.employee_id,
-                        employees.c.type == "manager",
-                    ),
-                )
+        stmt = select(reports, employees).select_from(
+            reports.outerjoin(
+                employees,
+                and_(
+                    employees.c.employee_id == reports.c.employee_id,
+                    employees.c.type == "manager",
+                ),
             )
-            .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
-            .subquery()
         )
+
+        subq = stmt.subquery()
+
+        ra = aliased(Report, subq)
+
+        # this test previously used select_entity_from().  the standard
+        # conversion to use aliased() neds to be adjusted to be against
+        # Employee, not Manger, otherwise the ORM will add the manager single
+        # inh criteria to the outside which will break the outer join
+        ma = aliased(Employee, subq)
+
+        eq_(
+            sess.query(ra, ma).order_by(ra.name).all(),
+            [(r1, m1), (r2, m2), (r3, None), (r4, None)],
+        )
+
+        # however if someone really wants to run that SELECT statement and
+        # get back these two entities, they can use from_statement() more
+        # directly.  in 1.4 we don't even need tablename label style for the
+        # select(), automatic disambiguation works great
         eq_(
             sess.query(Report, Manager)
-            .select_entity_from(stmt)
-            .order_by(Report.name)
+            .from_statement(stmt.order_by(reports.c.name))
             .all(),
             [(r1, m1), (r2, m2), (r3, None), (r4, None)],
         )
index 2ab45827b5e465b36ff32c1f78acff3c26cc492d..b868c63fe1a6e29787c9251f5df560aaeb2c240f 100644 (file)
@@ -9,6 +9,8 @@ from sqlalchemy import ForeignKey
 from sqlalchemy import func
 from sqlalchemy import inspect
 from sqlalchemy import Integer
+from sqlalchemy import join
+from sqlalchemy import lateral
 from sqlalchemy import literal_column
 from sqlalchemy import MetaData
 from sqlalchemy import or_
@@ -130,6 +132,11 @@ wparent_strings_dep = (
     r"in the ORM with_parent\(\) function"
 )
 
+sef_dep = (
+    r"The Query.select_entity_from\(\) method is considered "
+    "legacy as of the 1.x"
+)
+
 
 def _aliased_join_warning(arg=None):
     return testing.expect_warnings(
@@ -3992,6 +3999,25 @@ class InstancesTest(QueryTest, AssertsCompiledSQL):
         self.assert_sql_count(testing.db, go, 1)
 
 
+class TextTest(QueryTest):
+    def test_via_textasfrom_select_from(self):
+        User = self.classes.User
+        s = fixture_session()
+
+        with assertions.expect_deprecated_20(sef_dep):
+            eq_(
+                s.query(User)
+                .select_entity_from(
+                    text("select * from users")
+                    .columns(User.id, User.name)
+                    .subquery()
+                )
+                .order_by(User.id)
+                .all(),
+                [User(id=7), User(id=8), User(id=9), User(id=10)],
+            )
+
+
 class TestDeprecation20(fixtures.TestBase):
     def test_relation(self):
         with testing.expect_deprecated_20(".*relationship"):
@@ -7248,3 +7274,824 @@ class AliasedClassRelationshipTest(
 
         with assertions.expect_deprecated_20(opt_strings_dep):
             self.assert_sql_count(testing.db, go, 2)
+
+
+class ColumnAccessTest(QueryTest, AssertsCompiledSQL):
+    """test access of columns after _from_selectable has been applied"""
+
+    __dialect__ = "default"
+
+    def test_select_entity_from(self):
+        User = self.classes.User
+        sess = fixture_session()
+
+        q = sess.query(User)
+        with assertions.expect_deprecated_20(sef_dep):
+            q = sess.query(User).select_entity_from(q.statement.subquery())
+        self.assert_compile(
+            q.filter(User.name == "ed"),
+            "SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name "
+            "FROM (SELECT users.id AS id, users.name AS name FROM "
+            "users) AS anon_1 WHERE anon_1.name = :name_1",
+        )
+
+    def test_select_entity_from_no_entities(self):
+        User = self.classes.User
+        sess = fixture_session()
+
+        with assertions.expect_deprecated_20(sef_dep):
+            assert_raises_message(
+                sa.exc.ArgumentError,
+                r"A selectable \(FromClause\) instance is "
+                "expected when the base alias is being set",
+                sess.query(User).select_entity_from(User)._compile_context,
+            )
+
+
+class SelectFromTest(QueryTest, AssertsCompiledSQL):
+    run_setup_mappers = None
+    __dialect__ = "default"
+
+    def test_aliased_class_vs_nonaliased(self):
+        User, users = self.classes.User, self.tables.users
+        self.mapper_registry.map_imperatively(User, users)
+
+        sess = fixture_session()
+        with assertions.expect_deprecated_20(sef_dep):
+            self.assert_compile(
+                sess.query(User.name).select_entity_from(
+                    users.select().where(users.c.id > 5).subquery()
+                ),
+                "SELECT anon_1.name AS anon_1_name FROM "
+                "(SELECT users.id AS id, "
+                "users.name AS name FROM users WHERE users.id > :id_1) "
+                "AS anon_1",
+            )
+
+    def test_join_no_order_by(self):
+        User, users = self.classes.User, self.tables.users
+
+        self.mapper_registry.map_imperatively(User, users)
+
+        sel = users.select().where(users.c.id.in_([7, 8]))
+        sess = fixture_session()
+
+        with assertions.expect_deprecated_20(sef_dep):
+            eq_(
+                sess.query(User).select_entity_from(sel.subquery()).all(),
+                [User(name="jack", id=7), User(name="ed", id=8)],
+            )
+
+    def test_join(self):
+        users, Address, addresses, User = (
+            self.tables.users,
+            self.classes.Address,
+            self.tables.addresses,
+            self.classes.User,
+        )
+
+        self.mapper_registry.map_imperatively(
+            User, users, properties={"addresses": relationship(Address)}
+        )
+        self.mapper_registry.map_imperatively(Address, addresses)
+
+        sel = users.select().where(users.c.id.in_([7, 8]))
+        sess = fixture_session()
+
+        with assertions.expect_deprecated_20(sef_dep):
+            eq_(
+                sess.query(User)
+                .select_entity_from(sel.subquery())
+                .join("addresses")
+                .add_entity(Address)
+                .order_by(User.id)
+                .order_by(Address.id)
+                .all(),
+                [
+                    (
+                        User(name="jack", id=7),
+                        Address(
+                            user_id=7, email_address="jack@bean.com", id=1
+                        ),
+                    ),
+                    (
+                        User(name="ed", id=8),
+                        Address(user_id=8, email_address="ed@wood.com", id=2),
+                    ),
+                    (
+                        User(name="ed", id=8),
+                        Address(
+                            user_id=8, email_address="ed@bettyboop.com", id=3
+                        ),
+                    ),
+                    (
+                        User(name="ed", id=8),
+                        Address(user_id=8, email_address="ed@lala.com", id=4),
+                    ),
+                ],
+            )
+
+        adalias = aliased(Address)
+        with assertions.expect_deprecated_20(sef_dep):
+            eq_(
+                sess.query(User)
+                .select_entity_from(sel.subquery())
+                .join(adalias, "addresses")
+                .add_entity(adalias)
+                .order_by(User.id)
+                .order_by(adalias.id)
+                .all(),
+                [
+                    (
+                        User(name="jack", id=7),
+                        Address(
+                            user_id=7, email_address="jack@bean.com", id=1
+                        ),
+                    ),
+                    (
+                        User(name="ed", id=8),
+                        Address(user_id=8, email_address="ed@wood.com", id=2),
+                    ),
+                    (
+                        User(name="ed", id=8),
+                        Address(
+                            user_id=8, email_address="ed@bettyboop.com", id=3
+                        ),
+                    ),
+                    (
+                        User(name="ed", id=8),
+                        Address(user_id=8, email_address="ed@lala.com", id=4),
+                    ),
+                ],
+            )
+
+    def test_more_joins(self):
+        (
+            users,
+            Keyword,
+            orders,
+            items,
+            order_items,
+            Order,
+            Item,
+            User,
+            keywords,
+            item_keywords,
+        ) = (
+            self.tables.users,
+            self.classes.Keyword,
+            self.tables.orders,
+            self.tables.items,
+            self.tables.order_items,
+            self.classes.Order,
+            self.classes.Item,
+            self.classes.User,
+            self.tables.keywords,
+            self.tables.item_keywords,
+        )
+
+        self.mapper_registry.map_imperatively(
+            User,
+            users,
+            properties={"orders": relationship(Order, backref="user")},
+        )  # o2m, m2o
+        self.mapper_registry.map_imperatively(
+            Order,
+            orders,
+            properties={
+                "items": relationship(
+                    Item, secondary=order_items, order_by=items.c.id
+                )
+            },
+        )  # m2m
+
+        self.mapper_registry.map_imperatively(
+            Item,
+            items,
+            properties={
+                "keywords": relationship(
+                    Keyword, secondary=item_keywords, order_by=keywords.c.id
+                )
+            },
+        )  # m2m
+        self.mapper_registry.map_imperatively(Keyword, keywords)
+
+        sess = fixture_session()
+        sel = users.select().where(users.c.id.in_([7, 8]))
+
+        with assertions.expect_deprecated_20(sef_dep):
+            eq_(
+                sess.query(User)
+                .select_entity_from(sel.subquery())
+                .join(User.orders, Order.items, Item.keywords)
+                .filter(Keyword.name.in_(["red", "big", "round"]))
+                .all(),
+                [User(name="jack", id=7)],
+            )
+
+    def test_very_nested_joins_with_joinedload(self):
+        (
+            users,
+            Keyword,
+            orders,
+            items,
+            order_items,
+            Order,
+            Item,
+            User,
+            keywords,
+            item_keywords,
+        ) = (
+            self.tables.users,
+            self.classes.Keyword,
+            self.tables.orders,
+            self.tables.items,
+            self.tables.order_items,
+            self.classes.Order,
+            self.classes.Item,
+            self.classes.User,
+            self.tables.keywords,
+            self.tables.item_keywords,
+        )
+
+        self.mapper_registry.map_imperatively(
+            User,
+            users,
+            properties={"orders": relationship(Order, backref="user")},
+        )  # o2m, m2o
+        self.mapper_registry.map_imperatively(
+            Order,
+            orders,
+            properties={
+                "items": relationship(
+                    Item, secondary=order_items, order_by=items.c.id
+                )
+            },
+        )  # m2m
+        self.mapper_registry.map_imperatively(
+            Item,
+            items,
+            properties={
+                "keywords": relationship(
+                    Keyword, secondary=item_keywords, order_by=keywords.c.id
+                )
+            },
+        )  # m2m
+        self.mapper_registry.map_imperatively(Keyword, keywords)
+
+        sess = fixture_session()
+
+        sel = users.select().where(users.c.id.in_([7, 8]))
+
+        def go():
+            with assertions.expect_deprecated_20(sef_dep):
+                eq_(
+                    sess.query(User)
+                    .select_entity_from(sel.subquery())
+                    .options(
+                        joinedload("orders")
+                        .joinedload("items")
+                        .joinedload("keywords")
+                    )
+                    .join(User.orders, Order.items, Item.keywords)
+                    .filter(Keyword.name.in_(["red", "big", "round"]))
+                    .all(),
+                    [
+                        User(
+                            name="jack",
+                            orders=[
+                                Order(
+                                    description="order 1",
+                                    items=[
+                                        Item(
+                                            description="item 1",
+                                            keywords=[
+                                                Keyword(name="red"),
+                                                Keyword(name="big"),
+                                                Keyword(name="round"),
+                                            ],
+                                        ),
+                                        Item(
+                                            description="item 2",
+                                            keywords=[
+                                                Keyword(name="red", id=2),
+                                                Keyword(name="small", id=5),
+                                                Keyword(name="square"),
+                                            ],
+                                        ),
+                                        Item(
+                                            description="item 3",
+                                            keywords=[
+                                                Keyword(name="green", id=3),
+                                                Keyword(name="big", id=4),
+                                                Keyword(name="round", id=6),
+                                            ],
+                                        ),
+                                    ],
+                                ),
+                                Order(
+                                    description="order 3",
+                                    items=[
+                                        Item(
+                                            description="item 3",
+                                            keywords=[
+                                                Keyword(name="green", id=3),
+                                                Keyword(name="big", id=4),
+                                                Keyword(name="round", id=6),
+                                            ],
+                                        ),
+                                        Item(
+                                            description="item 4",
+                                            keywords=[],
+                                            id=4,
+                                        ),
+                                        Item(
+                                            description="item 5",
+                                            keywords=[],
+                                            id=5,
+                                        ),
+                                    ],
+                                ),
+                                Order(
+                                    description="order 5",
+                                    items=[
+                                        Item(description="item 5", keywords=[])
+                                    ],
+                                ),
+                            ],
+                        )
+                    ],
+                )
+
+        self.assert_sql_count(testing.db, go, 1)
+
+        sess.expunge_all()
+        sel2 = orders.select().where(orders.c.id.in_([1, 2, 3]))
+        with assertions.expect_deprecated_20(sef_dep):
+            eq_(
+                sess.query(Order)
+                .select_entity_from(sel2.subquery())
+                .join(Order.items)
+                .join(Item.keywords)
+                .filter(Keyword.name == "red")
+                .order_by(Order.id)
+                .all(),
+                [
+                    Order(description="order 1", id=1),
+                    Order(description="order 2", id=2),
+                ],
+            )
+
+    def test_replace_with_eager(self):
+        users, Address, addresses, User = (
+            self.tables.users,
+            self.classes.Address,
+            self.tables.addresses,
+            self.classes.User,
+        )
+
+        self.mapper_registry.map_imperatively(
+            User,
+            users,
+            properties={
+                "addresses": relationship(Address, order_by=addresses.c.id)
+            },
+        )
+        self.mapper_registry.map_imperatively(Address, addresses)
+
+        sel = users.select().where(users.c.id.in_([7, 8]))
+        sess = fixture_session()
+
+        def go():
+            with assertions.expect_deprecated_20(sef_dep):
+                eq_(
+                    sess.query(User)
+                    .options(joinedload("addresses"))
+                    .select_entity_from(sel.subquery())
+                    .order_by(User.id)
+                    .all(),
+                    [
+                        User(id=7, addresses=[Address(id=1)]),
+                        User(
+                            id=8,
+                            addresses=[
+                                Address(id=2),
+                                Address(id=3),
+                                Address(id=4),
+                            ],
+                        ),
+                    ],
+                )
+
+        self.assert_sql_count(testing.db, go, 1)
+        sess.expunge_all()
+
+        def go():
+            with assertions.expect_deprecated_20(sef_dep):
+                eq_(
+                    sess.query(User)
+                    .options(joinedload("addresses"))
+                    .select_entity_from(sel.subquery())
+                    .filter(User.id == 8)
+                    .order_by(User.id)
+                    .all(),
+                    [
+                        User(
+                            id=8,
+                            addresses=[
+                                Address(id=2),
+                                Address(id=3),
+                                Address(id=4),
+                            ],
+                        )
+                    ],
+                )
+
+        self.assert_sql_count(testing.db, go, 1)
+        sess.expunge_all()
+
+        def go():
+            with assertions.expect_deprecated_20(sef_dep):
+                eq_(
+                    sess.query(User)
+                    .options(joinedload("addresses"))
+                    .select_entity_from(sel.subquery())
+                    .order_by(User.id)[1],
+                    User(
+                        id=8,
+                        addresses=[
+                            Address(id=2),
+                            Address(id=3),
+                            Address(id=4),
+                        ],
+                    ),
+                )
+
+        self.assert_sql_count(testing.db, go, 1)
+
+    def test_select_from_aliased_one(self):
+        User, users = self.classes.User, self.tables.users
+
+        self.mapper_registry.map_imperatively(User, users)
+
+        sess = fixture_session()
+
+        not_users = table("users", column("id"), column("name"))
+        ua = aliased(User, select(not_users).alias(), adapt_on_names=True)
+
+        with assertions.expect_deprecated_20(sef_dep):
+            q = (
+                sess.query(User.name)
+                .select_entity_from(ua)
+                .order_by(User.name)
+            )
+        self.assert_compile(
+            q,
+            "SELECT anon_1.name AS anon_1_name FROM (SELECT users.id AS id, "
+            "users.name AS name FROM users) AS anon_1 ORDER BY anon_1.name",
+        )
+        eq_(q.all(), [("chuck",), ("ed",), ("fred",), ("jack",)])
+
+    def test_select_from_aliased_two(self):
+        User, users = self.classes.User, self.tables.users
+
+        self.mapper_registry.map_imperatively(User, users)
+
+        sess = fixture_session()
+
+        ua = aliased(User)
+
+        with assertions.expect_deprecated_20(sef_dep):
+            q = (
+                sess.query(User.name)
+                .select_entity_from(ua)
+                .order_by(User.name)
+            )
+        self.assert_compile(
+            q,
+            "SELECT users_1.name AS users_1_name FROM users AS users_1 "
+            "ORDER BY users_1.name",
+        )
+        eq_(q.all(), [("chuck",), ("ed",), ("fred",), ("jack",)])
+
+    def test_select_from_core_alias_one(self):
+        User, users = self.classes.User, self.tables.users
+
+        self.mapper_registry.map_imperatively(User, users)
+
+        sess = fixture_session()
+
+        ua = users.alias()
+
+        with assertions.expect_deprecated_20(sef_dep):
+            q = (
+                sess.query(User.name)
+                .select_entity_from(ua)
+                .order_by(User.name)
+            )
+        self.assert_compile(
+            q,
+            "SELECT users_1.name AS users_1_name FROM users AS users_1 "
+            "ORDER BY users_1.name",
+        )
+        eq_(q.all(), [("chuck",), ("ed",), ("fred",), ("jack",)])
+
+    def test_differentiate_self_external(self):
+        """test some different combinations of joining a table to a subquery of
+        itself."""
+
+        users, User = self.tables.users, self.classes.User
+
+        self.mapper_registry.map_imperatively(User, users)
+
+        sess = fixture_session()
+
+        sel = sess.query(User).filter(User.id.in_([7, 8])).subquery()
+        ualias = aliased(User)
+
+        with assertions.expect_deprecated_20(sef_dep):
+            self.assert_compile(
+                sess.query(ualias)
+                .select_entity_from(sel)
+                .filter(ualias.id > sel.c.id),
+                "SELECT users_1.id AS users_1_id, "
+                "users_1.name AS users_1_name "
+                "FROM users AS users_1, ("
+                "SELECT users.id AS id, users.name AS name FROM users "
+                "WHERE users.id IN ([POSTCOMPILE_id_1])) AS anon_1 "
+                "WHERE users_1.id > anon_1.id",
+                check_post_param={"id_1": [7, 8]},
+            )
+
+        with assertions.expect_deprecated_20(sef_dep):
+            self.assert_compile(
+                sess.query(ualias)
+                .select_entity_from(sel)
+                .join(ualias, ualias.id > sel.c.id),
+                "SELECT users_1.id AS users_1_id, "
+                "users_1.name AS users_1_name "
+                "FROM (SELECT users.id AS id, users.name AS name "
+                "FROM users WHERE users.id IN ([POSTCOMPILE_id_1])) AS anon_1 "
+                "JOIN users AS users_1 ON users_1.id > anon_1.id",
+                check_post_param={"id_1": [7, 8]},
+            )
+
+        with assertions.expect_deprecated_20(sef_dep):
+            self.assert_compile(
+                sess.query(ualias)
+                .select_entity_from(sel)
+                .join(ualias, ualias.id > User.id),
+                "SELECT users_1.id AS users_1_id, "
+                "users_1.name AS users_1_name "
+                "FROM (SELECT users.id AS id, users.name AS name FROM "
+                "users WHERE users.id IN ([POSTCOMPILE_id_1])) AS anon_1 "
+                "JOIN users AS users_1 ON users_1.id > anon_1.id",
+                check_post_param={"id_1": [7, 8]},
+            )
+
+        with assertions.expect_deprecated_20(sef_dep):
+            self.assert_compile(
+                sess.query(ualias).select_entity_from(
+                    join(sel, ualias, ualias.id > sel.c.id)
+                ),
+                "SELECT users_1.id AS users_1_id, "
+                "users_1.name AS users_1_name "
+                "FROM "
+                "(SELECT users.id AS id, users.name AS name "
+                "FROM users WHERE users.id "
+                "IN ([POSTCOMPILE_id_1])) AS anon_1 "
+                "JOIN users AS users_1 ON users_1.id > anon_1.id",
+                check_post_param={"id_1": [7, 8]},
+            )
+
+
+class JoinLateralTest(fixtures.MappedTest, AssertsCompiledSQL):
+    __dialect__ = default.DefaultDialect(supports_native_boolean=True)
+
+    run_setup_bind = None
+    run_setup_mappers = "once"
+
+    run_create_tables = None
+
+    @classmethod
+    def define_tables(cls, metadata):
+        Table(
+            "people",
+            metadata,
+            Column("people_id", Integer, primary_key=True),
+            Column("age", Integer),
+            Column("name", String(30)),
+        )
+        Table(
+            "bookcases",
+            metadata,
+            Column("bookcase_id", Integer, primary_key=True),
+            Column(
+                "bookcase_owner_id", Integer, ForeignKey("people.people_id")
+            ),
+            Column("bookcase_shelves", Integer),
+            Column("bookcase_width", Integer),
+        )
+        Table(
+            "books",
+            metadata,
+            Column("book_id", Integer, primary_key=True),
+            Column(
+                "bookcase_id", Integer, ForeignKey("bookcases.bookcase_id")
+            ),
+            Column("book_owner_id", Integer, ForeignKey("people.people_id")),
+            Column("book_weight", Integer),
+        )
+
+    @classmethod
+    def setup_classes(cls):
+        class Person(cls.Comparable):
+            pass
+
+        class Bookcase(cls.Comparable):
+            pass
+
+        class Book(cls.Comparable):
+            pass
+
+    @classmethod
+    def setup_mappers(cls):
+        Person, Bookcase, Book = cls.classes("Person", "Bookcase", "Book")
+        people, bookcases, books = cls.tables("people", "bookcases", "books")
+        cls.mapper_registry.map_imperatively(Person, people)
+        cls.mapper_registry.map_imperatively(
+            Bookcase,
+            bookcases,
+            properties={
+                "owner": relationship(Person),
+                "books": relationship(Book),
+            },
+        )
+        cls.mapper_registry.map_imperatively(Book, books)
+
+    # "sef" == "select entity from"
+    def test_select_subquery_sef_implicit_correlate(self):
+        Person, Book = self.classes("Person", "Book")
+
+        s = fixture_session()
+
+        stmt = s.query(Person).subquery()
+
+        subq = (
+            s.query(Book.book_id)
+            .filter(Person.people_id == Book.book_owner_id)
+            .subquery()
+            .lateral()
+        )
+
+        with assertions.expect_deprecated_20(sef_dep):
+            stmt = (
+                s.query(Person, subq.c.book_id)
+                .select_entity_from(stmt)
+                .join(subq, true())
+            )
+
+        self.assert_compile(
+            stmt,
+            "SELECT anon_1.people_id AS anon_1_people_id, "
+            "anon_1.age AS anon_1_age, anon_1.name AS anon_1_name, "
+            "anon_2.book_id AS anon_2_book_id "
+            "FROM "
+            "(SELECT people.people_id AS people_id, people.age AS age, "
+            "people.name AS name FROM people) AS anon_1 "
+            "JOIN LATERAL "
+            "(SELECT books.book_id AS book_id FROM books "
+            "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
+        )
+
+    def test_select_subquery_sef_implicit_correlate_coreonly(self):
+        Person, Book = self.classes("Person", "Book")
+
+        s = fixture_session()
+
+        stmt = s.query(Person).subquery()
+
+        subq = (
+            select(Book.book_id)
+            .where(Person.people_id == Book.book_owner_id)
+            .subquery()
+            .lateral()
+        )
+
+        with assertions.expect_deprecated_20(sef_dep):
+            stmt = (
+                s.query(Person, subq.c.book_id)
+                .select_entity_from(stmt)
+                .join(subq, true())
+            )
+
+        self.assert_compile(
+            stmt,
+            "SELECT anon_1.people_id AS anon_1_people_id, "
+            "anon_1.age AS anon_1_age, anon_1.name AS anon_1_name, "
+            "anon_2.book_id AS anon_2_book_id "
+            "FROM "
+            "(SELECT people.people_id AS people_id, people.age AS age, "
+            "people.name AS name FROM people) AS anon_1 "
+            "JOIN LATERAL "
+            "(SELECT books.book_id AS book_id FROM books "
+            "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
+        )
+
+    def test_select_subquery_sef_explicit_correlate_coreonly(self):
+        Person, Book = self.classes("Person", "Book")
+
+        s = fixture_session()
+
+        stmt = s.query(Person).subquery()
+
+        subq = (
+            select(Book.book_id)
+            .correlate(Person)
+            .where(Person.people_id == Book.book_owner_id)
+            .subquery()
+            .lateral()
+        )
+
+        with assertions.expect_deprecated_20(sef_dep):
+            stmt = (
+                s.query(Person, subq.c.book_id)
+                .select_entity_from(stmt)
+                .join(subq, true())
+            )
+
+        self.assert_compile(
+            stmt,
+            "SELECT anon_1.people_id AS anon_1_people_id, "
+            "anon_1.age AS anon_1_age, anon_1.name AS anon_1_name, "
+            "anon_2.book_id AS anon_2_book_id "
+            "FROM "
+            "(SELECT people.people_id AS people_id, people.age AS age, "
+            "people.name AS name FROM people) AS anon_1 "
+            "JOIN LATERAL "
+            "(SELECT books.book_id AS book_id FROM books "
+            "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
+        )
+
+    def test_select_subquery_sef_explicit_correlate(self):
+        Person, Book = self.classes("Person", "Book")
+
+        s = fixture_session()
+
+        stmt = s.query(Person).subquery()
+
+        subq = (
+            s.query(Book.book_id)
+            .correlate(Person)
+            .filter(Person.people_id == Book.book_owner_id)
+            .subquery()
+            .lateral()
+        )
+
+        with assertions.expect_deprecated_20(sef_dep):
+            stmt = (
+                s.query(Person, subq.c.book_id)
+                .select_entity_from(stmt)
+                .join(subq, true())
+            )
+
+        self.assert_compile(
+            stmt,
+            "SELECT anon_1.people_id AS anon_1_people_id, "
+            "anon_1.age AS anon_1_age, anon_1.name AS anon_1_name, "
+            "anon_2.book_id AS anon_2_book_id "
+            "FROM "
+            "(SELECT people.people_id AS people_id, people.age AS age, "
+            "people.name AS name FROM people) AS anon_1 "
+            "JOIN LATERAL "
+            "(SELECT books.book_id AS book_id FROM books "
+            "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
+        )
+
+    def test_from_function_sef(self):
+        Bookcase = self.classes.Bookcase
+
+        s = fixture_session()
+
+        subq = s.query(Bookcase).subquery()
+
+        srf = lateral(func.generate_series(1, Bookcase.bookcase_shelves))
+
+        with assertions.expect_deprecated_20(sef_dep):
+            q = s.query(Bookcase).select_entity_from(subq).join(srf, true())
+
+        self.assert_compile(
+            q,
+            "SELECT anon_1.bookcase_id AS anon_1_bookcase_id, "
+            "anon_1.bookcase_owner_id AS anon_1_bookcase_owner_id, "
+            "anon_1.bookcase_shelves AS anon_1_bookcase_shelves, "
+            "anon_1.bookcase_width AS anon_1_bookcase_width "
+            "FROM (SELECT bookcases.bookcase_id AS bookcase_id, "
+            "bookcases.bookcase_owner_id AS bookcase_owner_id, "
+            "bookcases.bookcase_shelves AS bookcase_shelves, "
+            "bookcases.bookcase_width AS bookcase_width FROM bookcases) "
+            "AS anon_1 "
+            "JOIN LATERAL "
+            "generate_series(:generate_series_1, anon_1.bookcase_shelves) "
+            "AS anon_2 ON true",
+        )
index 3351967fc1136aebc1b10a21fe697d9b5c8e2ecd..d8da90d421ed25c74c90ff5edf9eedc1e4cdc6da 100644 (file)
@@ -1,4 +1,3 @@
-import sqlalchemy as sa
 from sqlalchemy import and_
 from sqlalchemy import asc
 from sqlalchemy import desc
@@ -29,7 +28,6 @@ from sqlalchemy.orm import joinedload
 from sqlalchemy.orm import relationship
 from sqlalchemy.orm import Session
 from sqlalchemy.orm.context import ORMSelectCompileState
-from sqlalchemy.orm.util import join
 from sqlalchemy.sql import column
 from sqlalchemy.sql import table
 from sqlalchemy.sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
@@ -347,7 +345,7 @@ class RawSelectTest(QueryTest, AssertsCompiledSQL):
 
         self.assert_compile(
             sess.query(users)
-            .select_entity_from(users.select().subquery())
+            .select_from(users.select().subquery())
             .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
             .statement,
             "SELECT users.id AS users_id, users.name AS users_name "
@@ -377,7 +375,7 @@ class RawSelectTest(QueryTest, AssertsCompiledSQL):
 
         self.assert_compile(
             sess.query(users, s.c.email)
-            .select_entity_from(users.join(s, s.c.id == users.c.id))
+            .select_from(users.join(s, s.c.id == users.c.id))
             .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
             .statement,
             "SELECT users.id AS users_id, users.name AS users_name, "
@@ -694,30 +692,6 @@ class ColumnAccessTest(QueryTest, AssertsCompiledSQL):
 
     __dialect__ = "default"
 
-    def test_select_entity_from(self):
-        User = self.classes.User
-        sess = fixture_session()
-
-        q = sess.query(User)
-        q = sess.query(User).select_entity_from(q.statement.subquery())
-        self.assert_compile(
-            q.filter(User.name == "ed"),
-            "SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name "
-            "FROM (SELECT users.id AS id, users.name AS name FROM "
-            "users) AS anon_1 WHERE anon_1.name = :name_1",
-        )
-
-    def test_select_entity_from_no_entities(self):
-        User = self.classes.User
-        sess = fixture_session()
-
-        assert_raises_message(
-            sa.exc.ArgumentError,
-            r"A selectable \(FromClause\) instance is "
-            "expected when the base alias is being set",
-            sess.query(User).select_entity_from(User)._compile_context,
-        )
-
     def test_select_from_no_aliasing(self):
         User = self.classes.User
         sess = fixture_session()
@@ -1123,16 +1097,15 @@ class InstancesTest(QueryTest, AssertsCompiledSQL):
             .order_by(text("ulist.id"), addresses.c.id)
         )
         sess = fixture_session()
-        q = sess.query(User)
 
         def go():
             ulist = query.alias("ulist")
             ulist_alias = aliased(User, alias=ulist)
-            result = (
-                q.options(contains_eager(User.addresses, alias=ulist))
-                .select_entity_from(ulist_alias)
-                .all()
-            )
+            q = sess.query(ulist_alias)
+
+            result = q.options(
+                contains_eager(ulist_alias.addresses, alias=ulist)
+            ).all()
             assert self.static.user_address_result == result
 
         self.assert_sql_count(testing.db, go, 1)
@@ -1155,12 +1128,12 @@ class InstancesTest(QueryTest, AssertsCompiledSQL):
         )
         sess = fixture_session()
 
-        # better way.  use select_entity_from()
         def go():
+            qs = query.subquery()
+            ua = aliased(User, qs)
             result = (
-                sess.query(User)
-                .select_entity_from(query.subquery())
-                .options(contains_eager(User.addresses))
+                sess.query(ua)
+                .options(contains_eager(ua.addresses, alias=qs))
                 .all()
             )
             assert self.static.user_address_result == result
@@ -1173,12 +1146,10 @@ class InstancesTest(QueryTest, AssertsCompiledSQL):
             self.tables.addresses,
             self.tables.users,
         )
+        Address = self.classes.Address
 
         sess = fixture_session()
 
-        # same thing, but alias addresses, so that the adapter
-        # generated by select_entity_from() is wrapped within
-        # the adapter created by contains_eager()
         adalias = addresses.alias()
         query = (
             users.select()
@@ -1191,10 +1162,12 @@ class InstancesTest(QueryTest, AssertsCompiledSQL):
         )
 
         def go():
+            qs = query.subquery()
+            ua = aliased(User, qs)
+            aa = aliased(Address, qs)
             result = (
-                sess.query(User)
-                .select_entity_from(query.subquery())
-                .options(contains_eager(User.addresses, alias=adalias))
+                sess.query(ua)
+                .options(contains_eager(ua.addresses.of_type(aa)))
                 .all()
             )
             assert self.static.user_address_result == result
@@ -1241,10 +1214,11 @@ class InstancesTest(QueryTest, AssertsCompiledSQL):
         sess = fixture_session()
 
         adalias = addresses.alias()
+        qq = users.outerjoin(adalias)
+        ua = aliased(User, qq)
         q = (
-            sess.query(User)
-            .select_entity_from(users.outerjoin(adalias))
-            .options(contains_eager(User.addresses, alias=adalias))
+            sess.query(ua)
+            .options(contains_eager(ua.addresses, alias=adalias))
             .order_by(User.id, adalias.c.id)
         )
 
@@ -1774,8 +1748,9 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL):
 
         sess = fixture_session()
         sel = users.select().where(User.id.in_([7, 8])).alias()
-        q = sess.query(User.name)
-        q2 = q.select_entity_from(sel).all()
+        ua = aliased(User, sel)
+        q = sess.query(ua.name)
+        q2 = q.all()
         eq_(list(q2), [("jack",), ("ed",)])
 
     def test_column_queries_three(self):
@@ -1989,7 +1964,6 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL):
             .limit(10)
         )
 
-        # test eager aliasing, with/without select_entity_from aliasing
         for q in [q1, q2]:
             eq_(
                 q.all(),
@@ -2371,22 +2345,18 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL):
             (user10, None),
         ]
 
-        q = sess.query(User)
         adalias = addresses.alias("adalias")
-        q = q.add_entity(Address, alias=adalias).select_entity_from(
-            users.outerjoin(adalias)
-        )
+        uaj = users.outerjoin(adalias)
+        ua = aliased(User, uaj)
+        q = sess.query(ua)
+        q = q.add_entity(Address, alias=adalias)
         result = q.order_by(User.id, adalias.c.id).all()
         assert result == expected
 
         sess.expunge_all()
 
-        q = sess.query(User).add_entity(Address, alias=adalias)
-        result = (
-            q.select_entity_from(users.outerjoin(adalias))
-            .filter(adalias.c.email_address == "ed@bettyboop.com")
-            .all()
-        )
+        q = sess.query(ua).add_entity(Address, alias=adalias)
+        result = q.filter(adalias.c.email_address == "ed@bettyboop.com").all()
         assert result == [(user8, address3)]
 
     def test_with_entities(self):
@@ -2553,14 +2523,14 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL):
             eq_(result, expected)
 
         with fixture_session() as sess:
-            # test with select_entity_from()
+            uaj = users.outerjoin(addresses)
+            ua = aliased(User, uaj)
             q = (
                 fixture_session()
-                .query(User)
+                .query(ua)
                 .add_columns(
                     func.count(addresses.c.id), ("Name:" + users.c.name)
                 )
-                .select_entity_from(users.outerjoin(addresses))
                 .group_by(users)
                 .order_by(users.c.id)
             )
@@ -2729,40 +2699,29 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         sel = users.select().where(users.c.id.in_([7, 8])).alias()
         sess = fixture_session()
 
+        ua = aliased(User, sel)
         eq_(
-            sess.query(User).select_entity_from(sel).all(),
+            sess.query(ua).all(),
             [User(id=7), User(id=8)],
         )
 
         eq_(
-            sess.query(User)
-            .select_entity_from(sel)
-            .filter(User.id == 8)
-            .all(),
+            sess.query(ua).filter(ua.id == 8).all(),
             [User(id=8)],
         )
 
         eq_(
-            sess.query(User)
-            .select_entity_from(sel)
-            .order_by(desc(User.name))
-            .all(),
+            sess.query(ua).order_by(desc(ua.name)).all(),
             [User(name="jack", id=7), User(name="ed", id=8)],
         )
 
         eq_(
-            sess.query(User)
-            .select_entity_from(sel)
-            .order_by(asc(User.name))
-            .all(),
+            sess.query(ua).order_by(asc(ua.name)).all(),
             [User(name="ed", id=8), User(name="jack", id=7)],
         )
 
         eq_(
-            sess.query(User)
-            .select_entity_from(sel)
-            .options(joinedload(User.addresses))
-            .first(),
+            sess.query(ua).options(joinedload(ua.addresses)).first(),
             User(name="jack", addresses=[Address(id=1)]),
         )
 
@@ -2776,7 +2735,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         not_users = table("users", column("id"), column("name"))
         ua = aliased(User, select(not_users).alias(), adapt_on_names=True)
 
-        q = sess.query(User.name).select_entity_from(ua).order_by(User.name)
+        q = sess.query(ua.name).order_by(ua.name)
         self.assert_compile(
             q,
             "SELECT anon_1.name AS anon_1_name FROM (SELECT users.id AS id, "
@@ -2793,24 +2752,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
 
         ua = aliased(User)
 
-        q = sess.query(User.name).select_entity_from(ua).order_by(User.name)
-        self.assert_compile(
-            q,
-            "SELECT users_1.name AS users_1_name FROM users AS users_1 "
-            "ORDER BY users_1.name",
-        )
-        eq_(q.all(), [("chuck",), ("ed",), ("fred",), ("jack",)])
-
-    def test_select_from_core_alias_one(self):
-        User, users = self.classes.User, self.tables.users
-
-        self.mapper_registry.map_imperatively(User, users)
-
-        sess = fixture_session()
-
-        ua = users.alias()
-
-        q = sess.query(User.name).select_entity_from(ua).order_by(User.name)
+        q = sess.query(ua.name).order_by(ua.name)
         self.assert_compile(
             q,
             "SELECT users_1.name AS users_1_name FROM users AS users_1 "
@@ -2831,6 +2773,8 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         sel = sess.query(User).filter(User.id.in_([7, 8])).subquery()
         ualias = aliased(User)
 
+        ua = aliased(User, sel)
+
         self.assert_compile(
             sess.query(User).join(sel, User.id > sel.c.id),
             "SELECT users.id AS users_id, users.name AS users_name FROM "
@@ -2840,9 +2784,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         )
 
         self.assert_compile(
-            sess.query(ualias)
-            .select_entity_from(sel)
-            .filter(ualias.id > sel.c.id),
+            sess.query(ualias).select_from(ua).filter(ualias.id > ua.id),
             "SELECT users_1.id AS users_1_id, users_1.name AS users_1_name "
             "FROM users AS users_1, ("
             "SELECT users.id AS id, users.name AS name FROM users "
@@ -2852,9 +2794,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         )
 
         self.assert_compile(
-            sess.query(ualias)
-            .select_entity_from(sel)
-            .join(ualias, ualias.id > sel.c.id),
+            sess.query(ualias).select_from(ua).join(ualias, ualias.id > ua.id),
             "SELECT users_1.id AS users_1_id, users_1.name AS users_1_name "
             "FROM (SELECT users.id AS id, users.name AS name "
             "FROM users WHERE users.id IN ([POSTCOMPILE_id_1])) AS anon_1 "
@@ -2863,9 +2803,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         )
 
         self.assert_compile(
-            sess.query(ualias)
-            .select_entity_from(sel)
-            .join(ualias, ualias.id > User.id),
+            sess.query(ualias).select_from(ua).join(ualias, ualias.id > ua.id),
             "SELECT users_1.id AS users_1_id, users_1.name AS users_1_name "
             "FROM (SELECT users.id AS id, users.name AS name FROM "
             "users WHERE users.id IN ([POSTCOMPILE_id_1])) AS anon_1 "
@@ -2883,19 +2821,6 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
             check_post_param={"id_1": [7, 8]},
         )
 
-        self.assert_compile(
-            sess.query(ualias).select_entity_from(
-                join(sel, ualias, ualias.id > sel.c.id)
-            ),
-            "SELECT users_1.id AS users_1_id, users_1.name AS users_1_name "
-            "FROM "
-            "(SELECT users.id AS id, users.name AS name "
-            "FROM users WHERE users.id "
-            "IN ([POSTCOMPILE_id_1])) AS anon_1 "
-            "JOIN users AS users_1 ON users_1.id > anon_1.id",
-            check_post_param={"id_1": [7, 8]},
-        )
-
     def test_aliased_class_vs_nonaliased(self):
         User, users = self.classes.User, self.tables.users
         self.mapper_registry.map_imperatively(User, users)
@@ -2937,29 +2862,6 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
             "FROM users JOIN users AS users_1 ON users.name > users_1.name",
         )
 
-        # this is tested in many other places here, just adding it
-        # here for comparison
-        self.assert_compile(
-            sess.query(User.name).select_entity_from(
-                users.select().where(users.c.id > 5).subquery()
-            ),
-            "SELECT anon_1.name AS anon_1_name FROM (SELECT users.id AS id, "
-            "users.name AS name FROM users WHERE users.id > :id_1) AS anon_1",
-        )
-
-    def test_join_no_order_by(self):
-        User, users = self.classes.User, self.tables.users
-
-        self.mapper_registry.map_imperatively(User, users)
-
-        sel = users.select().where(users.c.id.in_([7, 8]))
-        sess = fixture_session()
-
-        eq_(
-            sess.query(User).select_entity_from(sel.subquery()).all(),
-            [User(name="jack", id=7), User(name="ed", id=8)],
-        )
-
     def test_join_relname_from_selected_from(self):
         User, Address = self.classes.User, self.classes.Address
         users, addresses = self.tables.users, self.tables.addresses
@@ -3044,12 +2946,12 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         sel = users.select().where(users.c.id.in_([7, 8]))
         sess = fixture_session()
 
+        ua = aliased(User, sel.subquery())
         eq_(
-            sess.query(User)
-            .select_entity_from(sel.subquery())
-            .join(User.addresses)
+            sess.query(ua)
+            .join(ua.addresses)
             .add_entity(Address)
-            .order_by(User.id)
+            .order_by(ua.id)
             .order_by(Address.id)
             .all(),
             [
@@ -3073,12 +2975,12 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         )
 
         adalias = aliased(Address)
+        ua = aliased(User, sel.subquery())
         eq_(
-            sess.query(User)
-            .select_entity_from(sel.subquery())
-            .join(adalias, User.addresses)
+            sess.query(ua)
+            .join(ua.addresses.of_type(adalias))
             .add_entity(adalias)
-            .order_by(User.id)
+            .order_by(ua.id)
             .order_by(adalias.id)
             .all(),
             [
@@ -3155,10 +3057,10 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         sess = fixture_session()
         sel = users.select().where(users.c.id.in_([7, 8]))
 
+        ua = aliased(User, sel.subquery())
         eq_(
-            sess.query(User)
-            .select_entity_from(sel.subquery())
-            .join(User.orders)
+            sess.query(ua)
+            .join(ua.orders)
             .join(Order.items)
             .join(Item.keywords)
             .filter(Keyword.name.in_(["red", "big", "round"]))
@@ -3219,17 +3121,17 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         sess = fixture_session()
 
         sel = users.select().where(users.c.id.in_([7, 8]))
+        ua = aliased(User, sel.subquery())
 
         def go():
             eq_(
-                sess.query(User)
-                .select_entity_from(sel.subquery())
+                sess.query(ua)
                 .options(
-                    joinedload(User.orders)
+                    joinedload(ua.orders)
                     .joinedload(Order.items)
                     .joinedload(Item.keywords)
                 )
-                .join(User.orders)
+                .join(ua.orders)
                 .join(Order.items)
                 .join(Item.keywords)
                 .filter(Keyword.name.in_(["red", "big", "round"]))
@@ -3301,13 +3203,13 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
 
         sess.expunge_all()
         sel2 = orders.select().where(orders.c.id.in_([1, 2, 3]))
+        oa = aliased(Order, sel2.subquery())
         eq_(
-            sess.query(Order)
-            .select_entity_from(sel2.subquery())
-            .join(Order.items)
+            sess.query(oa)
+            .join(oa.items)
             .join(Item.keywords)
             .filter(Keyword.name == "red")
-            .order_by(Order.id)
+            .order_by(oa.id)
             .all(),
             [
                 Order(description="order 1", id=1),
@@ -3335,12 +3237,13 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
         sel = users.select().where(users.c.id.in_([7, 8]))
         sess = fixture_session()
 
+        ua = aliased(User, sel.subquery())
+
         def go():
             eq_(
-                sess.query(User)
-                .options(joinedload(User.addresses))
-                .select_entity_from(sel.subquery())
-                .order_by(User.id)
+                sess.query(ua)
+                .options(joinedload(ua.addresses))
+                .order_by(ua.id)
                 .all(),
                 [
                     User(id=7, addresses=[Address(id=1)]),
@@ -3360,11 +3263,10 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
 
         def go():
             eq_(
-                sess.query(User)
-                .options(joinedload(User.addresses))
-                .select_entity_from(sel.subquery())
-                .filter(User.id == 8)
-                .order_by(User.id)
+                sess.query(ua)
+                .options(joinedload(ua.addresses))
+                .filter(ua.id == 8)
+                .order_by(ua.id)
                 .all(),
                 [
                     User(
@@ -3383,10 +3285,12 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL):
 
         def go():
             eq_(
-                sess.query(User)
-                .options(joinedload(User.addresses))
-                .select_entity_from(sel.subquery())
-                .order_by(User.id)[1],
+                sess.query(ua)
+                .options(joinedload(ua.addresses))
+                .order_by(ua.id)
+                .offset(1)
+                .limit(1)
+                .scalar(),
                 User(
                     id=8,
                     addresses=[Address(id=2), Address(id=3), Address(id=4)],
@@ -3561,11 +3465,7 @@ class ExternalColumnsTest(QueryTest):
             Address(id=4, user=User(id=8, concat=16, count=3)),
             Address(id=5, user=User(id=9, concat=18, count=1)),
         ]
-        # TODO: ISSUE: BUG:  cached metadata is confusing the user.id
-        # column here with the anon_1 for some reason, when we
-        # use compiled cache.  this bug may even be present in
-        # regular main / 1.3.  right now the caching of result
-        # metadata is disabled.
+
         eq_(sess.query(Address).all(), address_result)
 
         # run the eager version twice to test caching of aliased clauses
@@ -3623,7 +3523,7 @@ class ExternalColumnsTest(QueryTest):
         ua = aliased(User)
         eq_(
             sess.query(Address, ua.concat, ua.count)
-            .select_entity_from(join(Address, ua, "user"))
+            .join(Address.user.of_type(ua))
             .options(joinedload(Address.user))
             .order_by(Address.id)
             .all(),
@@ -3654,7 +3554,7 @@ class ExternalColumnsTest(QueryTest):
         eq_(
             list(
                 sess.query(Address, ua)
-                .select_entity_from(join(Address, ua, Address.user))
+                .join(Address.user.of_type(ua))
                 .with_entities(Address.id, ua.id, ua.concat, ua.count)
             ),
             [
index 42f9b9aa16c94a216f8f8e12c40b3429807bd540..b9f036b1fea214e6d4e7ef7b828cf59471d1246f 100644 (file)
@@ -1271,10 +1271,9 @@ class JoinTest(QueryTest, AssertsCompiledSQL):
         )
 
     def test_clause_onclause(self):
-        Item, Order, users, order_items, User = (
+        Item, Order, order_items, User = (
             self.classes.Item,
             self.classes.Order,
-            self.tables.users,
             self.tables.order_items,
             self.classes.User,
         )
@@ -1322,17 +1321,6 @@ class JoinTest(QueryTest, AssertsCompiledSQL):
             [User(name="fred")],
         )
 
-        # same with an explicit select_from()
-        eq_(
-            sess.query(User)
-            .select_entity_from(
-                select(users).order_by(User.id).offset(2).alias()
-            )
-            .join(Order, User.id == Order.user_id)
-            .all(),
-            [User(name="fred")],
-        )
-
     def test_aliased_classes(self):
         User, Address = self.classes.User, self.classes.Address
 
@@ -3053,26 +3041,24 @@ class JoinLateralTest(fixtures.MappedTest, AssertsCompiledSQL):
             "WHERE people.people_id = books.book_owner_id) AS anon_1 ON true",
         )
 
-    # sef == select_entity_from
-    def test_select_subquery_sef_implicit_correlate(self):
+    # "aas" == "aliased against select"
+    def test_select_subquery_aas_implicit_correlate(self):
         Person, Book = self.classes("Person", "Book")
 
         s = fixture_session()
 
         stmt = s.query(Person).subquery()
 
+        pa = aliased(Person, stmt)
+
         subq = (
             s.query(Book.book_id)
-            .filter(Person.people_id == Book.book_owner_id)
+            .filter(pa.people_id == Book.book_owner_id)
             .subquery()
             .lateral()
         )
 
-        stmt = (
-            s.query(Person, subq.c.book_id)
-            .select_entity_from(stmt)
-            .join(subq, true())
-        )
+        stmt = s.query(pa, subq.c.book_id).join(subq, true())
 
         self.assert_compile(
             stmt,
@@ -3087,25 +3073,23 @@ class JoinLateralTest(fixtures.MappedTest, AssertsCompiledSQL):
             "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
         )
 
-    def test_select_subquery_sef_implicit_correlate_coreonly(self):
+    def test_select_subquery_aas_implicit_correlate_coreonly(self):
         Person, Book = self.classes("Person", "Book")
 
         s = fixture_session()
 
         stmt = s.query(Person).subquery()
 
+        pa = aliased(Person, stmt)
+
         subq = (
             select(Book.book_id)
-            .where(Person.people_id == Book.book_owner_id)
+            .where(pa.people_id == Book.book_owner_id)
             .subquery()
             .lateral()
         )
 
-        stmt = (
-            s.query(Person, subq.c.book_id)
-            .select_entity_from(stmt)
-            .join(subq, true())
-        )
+        stmt = s.query(pa, subq.c.book_id).join(subq, true())
 
         self.assert_compile(
             stmt,
@@ -3120,26 +3104,24 @@ class JoinLateralTest(fixtures.MappedTest, AssertsCompiledSQL):
             "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
         )
 
-    def test_select_subquery_sef_explicit_correlate_coreonly(self):
+    def test_select_subquery_aas_explicit_correlate_coreonly(self):
         Person, Book = self.classes("Person", "Book")
 
         s = fixture_session()
 
         stmt = s.query(Person).subquery()
 
+        pa = aliased(Person, stmt)
+
         subq = (
             select(Book.book_id)
-            .correlate(Person)
-            .where(Person.people_id == Book.book_owner_id)
+            .correlate(pa)
+            .where(pa.people_id == Book.book_owner_id)
             .subquery()
             .lateral()
         )
 
-        stmt = (
-            s.query(Person, subq.c.book_id)
-            .select_entity_from(stmt)
-            .join(subq, true())
-        )
+        stmt = s.query(pa, subq.c.book_id).join(subq, true())
 
         self.assert_compile(
             stmt,
@@ -3154,26 +3136,23 @@ class JoinLateralTest(fixtures.MappedTest, AssertsCompiledSQL):
             "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
         )
 
-    def test_select_subquery_sef_explicit_correlate(self):
+    def test_select_subquery_aas_explicit_correlate(self):
         Person, Book = self.classes("Person", "Book")
 
         s = fixture_session()
 
         stmt = s.query(Person).subquery()
+        pa = aliased(Person, stmt)
 
         subq = (
             s.query(Book.book_id)
-            .correlate(Person)
-            .filter(Person.people_id == Book.book_owner_id)
+            .correlate(pa)
+            .filter(pa.people_id == Book.book_owner_id)
             .subquery()
             .lateral()
         )
 
-        stmt = (
-            s.query(Person, subq.c.book_id)
-            .select_entity_from(stmt)
-            .join(subq, true())
-        )
+        stmt = s.query(pa, subq.c.book_id).join(subq, true())
 
         self.assert_compile(
             stmt,
@@ -3206,17 +3185,19 @@ class JoinLateralTest(fixtures.MappedTest, AssertsCompiledSQL):
             "bookcases.bookcase_shelves) AS anon_1 ON true",
         )
 
-    def test_from_function_select_entity_from(self):
+    def test_from_function_aas(self):
         Bookcase = self.classes.Bookcase
 
         s = fixture_session()
 
         subq = s.query(Bookcase).subquery()
 
-        srf = lateral(func.generate_series(1, Bookcase.bookcase_shelves))
+        ba = aliased(Bookcase, subq)
+
+        srf = lateral(func.generate_series(1, ba.bookcase_shelves))
 
         self.assert_compile(
-            s.query(Bookcase).select_entity_from(subq).join(srf, true()),
+            s.query(ba).join(srf, true()),
             "SELECT anon_1.bookcase_id AS anon_1_bookcase_id, "
             "anon_1.bookcase_owner_id AS anon_1_bookcase_owner_id, "
             "anon_1.bookcase_shelves AS anon_1_bookcase_shelves, "
index c9353f5511231d14cd3021bd1b7729a594c25b44..2320124cddcc42bb8c70f677fb87b089c15f8c0d 100644 (file)
@@ -6105,19 +6105,17 @@ class TextTest(QueryTest, AssertsCompiledSQL):
             [User(id=7), User(id=8), User(id=9), User(id=10)],
         )
 
-    def test_via_textasfrom_select_from(self):
+    def test_via_textasfrom_aliased(self):
         User = self.classes.User
         s = fixture_session()
 
+        ua = aliased(
+            User,
+            text("select * from users").columns(User.id, User.name).subquery(),
+        )
+
         eq_(
-            s.query(User)
-            .select_entity_from(
-                text("select * from users")
-                .columns(User.id, User.name)
-                .subquery()
-            )
-            .order_by(User.id)
-            .all(),
+            s.query(ua).order_by(ua.id).all(),
             [User(id=7), User(id=8), User(id=9), User(id=10)],
         )