From: Mike Bayer Date: Sat, 8 Jun 2013 23:50:40 +0000 (-0400) Subject: ...and...its a behavioral improvement X-Git-Tag: rel_0_9_0b1~273 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f65ddee93a7143924b417e1c988802f10d0c7b11;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git ...and...its a behavioral improvement --- diff --git a/doc/build/changelog/migration_09.rst b/doc/build/changelog/migration_09.rst index cca910a31f..d6ec54af43 100644 --- a/doc/build/changelog/migration_09.rst +++ b/doc/build/changelog/migration_09.rst @@ -41,8 +41,94 @@ At the moment, the C extensions are still not fully ported to Python 3. -New ORM Features -================ + +.. _behavioral_changes_09: + +Behavioral Changes +================== + +.. _migration_2736: + +:meth:`.Query.select_from` no longer applies the clause to corresponding entities +--------------------------------------------------------------------------------- + +The :meth:`.Query.select_from` method has been popularized in recent versions +as a means of controlling the first thing that a :class:`.Query` object +"selects from", typically for the purposes of controlling how a JOIN will +render. + +Consider the following example against the usual ``User`` mapping:: + + select_stmt = select([User]).where(User.id == 7).alias() + + q = session.query(User).\ + join(select_stmt, User.id == select_stmt.c.id).\ + filter(User.name == 'ed') + +The above statement predictably renders SQL like the following:: + + SELECT "user".id AS user_id, "user".name AS user_name + FROM "user" JOIN (SELECT "user".id AS id, "user".name AS name + FROM "user" + WHERE "user".id = :id_1) AS anon_1 ON "user".id = anon_1.id + WHERE "user".name = :name_1 + +If we wanted to reverse the order of the left and right elements of the +JOIN, the documentation would lead us to believe we could use +:meth:`.Query.select_from` to do so:: + + q = session.query(User).\ + select_from(select_stmt).\ + join(User, User.id == select_stmt.c.id).\ + filter(User.name == 'ed') + +However, in version 0.8 and earlier, the above use of :meth:`.Query.select_from` +would apply the ``select_stmt`` to **replace** the ``User`` entity, as it +selects from the ``user`` table which is compatible with ``User``:: + + -- SQLAlchemy 0.8 and earlier... + SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name + FROM (SELECT "user".id AS id, "user".name AS name + FROM "user" + WHERE "user".id = :id_1) AS anon_1 JOIN "user" ON anon_1.id = anon_1.id + WHERE anon_1.name = :name_1 + +The above statement is a mess, the ON clause refers ``anon_1.id = anon_1.id``, +our WHERE clause has been replaced with ``anon_1`` as well. + +This behavior is quite intentional, but has a different use case from that +which has become popular for :meth:`.Query.select_from`. The above behavior +is now available by a new method known as :meth:`.Query.select_entity_from`. +This is a lesser used behavior that in modern SQLAlchemy is roughly equivalent +to selecting from a customized :func:`.aliased` construct:: + + select_stmt = select([User]).where(User.id == 7) + user_from_stmt = aliased(User, select_stmt.alias()) + + q = session.query(user_from_stmt).filter(user_from_stmt.name == 'ed') + +So with SQLAlchemy 0.9, our query that selects from ``select_stmt`` produces +the SQL we expect:: + + -- SQLAlchemy 0.9 + SELECT "user".id AS user_id, "user".name AS user_name + FROM (SELECT "user".id AS id, "user".name AS name + FROM "user" + WHERE "user".id = :id_1) AS anon_1 JOIN "user" ON "user".id = id + WHERE "user".name = :name_1 + +The :meth:`.Query.select_entity_from` method will be available in SQLAlchemy +**0.8.2**, so applications which rely on the old behavior can transition +to this method first, ensure all tests continue to function, then upgrade +to 0.9 without issue. + +:ticket:`2736` + +Behavioral Improvements +======================= + +Improvements that should produce no compatibility issues, but are good +to be aware of in case there are unexpected issues. .. _feature_joins_09: @@ -208,96 +294,6 @@ Generates (everywhere except SQLite):: :ticket:`2369` :ticket:`2587` - -.. _behavioral_changes_09: - -Behavioral Changes -================== - -.. _migration_2736: - -:meth:`.Query.select_from` no longer applies the clause to corresponding entities ---------------------------------------------------------------------------------- - -The :meth:`.Query.select_from` method has been popularized in recent versions -as a means of controlling the first thing that a :class:`.Query` object -"selects from", typically for the purposes of controlling how a JOIN will -render. - -Consider the following example against the usual ``User`` mapping:: - - select_stmt = select([User]).where(User.id == 7).alias() - - q = session.query(User).\ - join(select_stmt, User.id == select_stmt.c.id).\ - filter(User.name == 'ed') - -The above statement predictably renders SQL like the following:: - - SELECT "user".id AS user_id, "user".name AS user_name - FROM "user" JOIN (SELECT "user".id AS id, "user".name AS name - FROM "user" - WHERE "user".id = :id_1) AS anon_1 ON "user".id = anon_1.id - WHERE "user".name = :name_1 - -If we wanted to reverse the order of the left and right elements of the -JOIN, the documentation would lead us to believe we could use -:meth:`.Query.select_from` to do so:: - - q = session.query(User).\ - select_from(select_stmt).\ - join(User, User.id == select_stmt.c.id).\ - filter(User.name == 'ed') - -However, in version 0.8 and earlier, the above use of :meth:`.Query.select_from` -would apply the ``select_stmt`` to **replace** the ``User`` entity, as it -selects from the ``user`` table which is compatible with ``User``:: - - -- SQLAlchemy 0.8 and earlier... - SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name - FROM (SELECT "user".id AS id, "user".name AS name - FROM "user" - WHERE "user".id = :id_1) AS anon_1 JOIN "user" ON anon_1.id = anon_1.id - WHERE anon_1.name = :name_1 - -The above statement is a mess, the ON clause refers ``anon_1.id = anon_1.id``, -our WHERE clause has been replaced with ``anon_1`` as well. - -This behavior is quite intentional, but has a different use case from that -which has become popular for :meth:`.Query.select_from`. The above behavior -is now available by a new method known as :meth:`.Query.select_entity_from`. -This is a lesser used behavior that in modern SQLAlchemy is roughly equivalent -to selecting from a customized :func:`.aliased` construct:: - - select_stmt = select([User]).where(User.id == 7) - user_from_stmt = aliased(User, select_stmt.alias()) - - q = session.query(user_from_stmt).filter(user_from_stmt.name == 'ed') - -So with SQLAlchemy 0.9, our query that selects from ``select_stmt`` produces -the SQL we expect:: - - -- SQLAlchemy 0.9 - SELECT "user".id AS user_id, "user".name AS user_name - FROM (SELECT "user".id AS id, "user".name AS name - FROM "user" - WHERE "user".id = :id_1) AS anon_1 JOIN "user" ON "user".id = id - WHERE "user".name = :name_1 - -The :meth:`.Query.select_entity_from` method will be available in SQLAlchemy -**0.8.2**, so applications which rely on the old behavior can transition -to this method first, ensure all tests continue to function, then upgrade -to 0.9 without issue. - -:ticket:`2736` - - -Behavioral Improvements -======================= - -Improvements that should produce no compatibility issues, but are good -to be aware of in case there are unexpected issues. - Label constructs can now render as their name alone in an ORDER BY ------------------------------------------------------------------