]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
heads up that execute(query).first() can't apply LIMIT 1
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 20 Aug 2021 14:28:16 +0000 (10:28 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 20 Aug 2021 15:27:47 +0000 (11:27 -0400)
Fixes: #6914
Change-Id: I5de9843dd3723c017b94b705fc009b883737ede1

doc/build/changelog/migration_20.rst
lib/sqlalchemy/engine/result.py

index 71939f44f62cda0172c7b728c0af315175064ac6..e6c9e29520d4e0b5aeaf40aefc045b45dce0b7ab 100644 (file)
@@ -1227,6 +1227,24 @@ following the table, and may include additional notes not summarized here.
 
         :meth:`_engine.Result.scalar_one`
 
+    * - ::
+
+          session.query(User).\
+          filter_by(name='some user').first()
+
+
+      - ::
+
+          session.execute(
+            select(User).
+            filter_by(name="some user").
+            limit(1)
+          ).scalars().first()
+
+      - :ref:`migration_20_unify_select`
+
+        :meth:`_engine.Result.first`
+
     * - ::
 
             session.query(User).options(
@@ -1361,6 +1379,9 @@ Legacy code examples are illustrated below::
     # becomes legacy use case
     user = session.query(User).filter_by(name='some user').one()
 
+    # becomes legacy use case
+    user = session.query(User).filter_by(name='some user').first()
+
     # becomes legacy use case
     user = session.query(User).get(5)
 
@@ -1422,6 +1443,11 @@ Below are some examples of how to migrate to :func:`_sql.select`::
         select(User).filter_by(name="some user")
     ).scalar_one()
 
+    # for first(), no LIMIT is applied automatically; add limit(1) if LIMIT
+    # is desired on the query
+    user = session.execute(
+        select(User).filter_by(name="some user").limit(1)
+    ).scalars().first()
 
     # get() moves to the Session directly
     user = session.get(User, 5)
@@ -1846,21 +1872,22 @@ As is the case described at :ref:`migration_20_query_from_self`, the
 
     from sqlalchemy.orm import aliased
 
-    subquery = session.query(User).filter(User.id == 5).subquery()
+    subquery = session.query(User).filter(User.name.like("%somename%")).subquery()
 
     ua = aliased(User, subquery)
 
-    user = session.query(ua).first()
+    user = session.query(ua).order_by(ua.id).first()
 
 Using :term:`2.0 style`::
 
     from sqlalchemy.orm import aliased
 
-    subquery = select(User).where(User.id == 5).subquery()
+    subquery = select(User).where(User.name.like("%somename%")).subquery()
 
     ua = aliased(User, subquery)
 
-    user = session.execute(select(ua)).scalars().first()
+    # note that LIMIT 1 is not automatically supplied, if needed
+    user = session.execute(select(ua).order_by(ua.id).limit(1)).scalars().first()
 
 **Discussion**
 
index 60474c0edc6d96af57dac8c15e5b6acf4545ff4f..3c2e682be6540a40c360721a6e98f039a78f19c7 100644 (file)
@@ -1054,6 +1054,17 @@ class Result(_WithKeys, ResultInternal):
            column of the first row, use the :meth:`.Result.scalar` method,
            or combine :meth:`.Result.scalars` and :meth:`.Result.first`.
 
+           Additionally, in contrast to the behavior of the legacy  ORM
+           :meth:`_orm.Query.first` method, **no limit is applied** to the
+           SQL query which was invoked to produce this :class:`_engine.Result`;
+           for a DBAPI driver that buffers results in memory before yielding
+           rows, all rows will be sent to the Python process and all but
+           the first row will be discarded.
+
+           .. seealso::
+
+                :ref:`migration_20_unify_select`
+
         :return: a :class:`.Row` object, or None
          if no rows remain.