]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Add count(), scalar() to baked query
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 25 Jan 2017 18:30:47 +0000 (13:30 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 30 Jan 2017 18:02:29 +0000 (13:02 -0500)
Change-Id: I8af0d7b41ae2df384ce5d0ef274732352d81f376
Fixes: #3897
doc/build/changelog/changelog_11.rst
lib/sqlalchemy/ext/baked.py
test/ext/test_baked.py

index 906f570ff87bd0070551b2614cf5858852103e52..983f3eb406a4a857765c5f64777f9f5eb78adb6d 100644 (file)
         2000, as the necessary system view is not available prior to SQL Server
         2005.
 
+    .. change:: 3897
+        :tags: feature, ext
+        :tickets: 3896
+
+        Added :meth:`.baked.Result.scalar` and :meth:`.baked.Result.count`
+        to the "baked" query system.
+
     .. change:: 3893
         :tags: bug, orm
         :tickets: 3893
index c329eb47ba63c766ca91ed4c7ae6a68b5ca60c5e..0904666186a14cd176f1cf58464e3242404fd026 100644 (file)
@@ -17,7 +17,7 @@ from ..orm.query import Query
 from ..orm import strategies, attributes, properties, \
     strategy_options, util as orm_util, interfaces
 from .. import log as sqla_log
-from ..sql import util as sql_util
+from ..sql import util as sql_util, func, literal_column
 from ..orm import exc as orm_exc
 from .. import exc as sa_exc
 from .. import util
@@ -254,6 +254,40 @@ class Result(object):
         return context.query.params(self._params).\
             with_session(self.session)._execute_and_instances(context)
 
+    def count(self):
+        """return the 'count'.
+
+        Equivalent to :meth:`.Query.count`.
+
+        Note this uses a subquery to ensure an accurate count regardless
+        of the structure of the original statement.
+
+        .. versionadded:: 1.1.6
+
+        """
+
+        col = func.count(literal_column('*'))
+        bq = self.bq.with_criteria(lambda q: q.from_self(col))
+        return bq.for_session(self.session).scalar()
+
+    def scalar(self):
+        """Return the first element of the first result or None
+        if no rows present.  If multiple rows are returned,
+        raises MultipleResultsFound.
+
+        Equivalent to :meth:`.Query.scalar`.
+
+        .. versionadded:: 1.1.6
+
+        """
+        try:
+            ret = self.one()
+            if not isinstance(ret, tuple):
+                return ret
+            return ret[0]
+        except orm_exc.NoResultFound:
+            return None
+
     def first(self):
         """Return the first row.
 
index 818019de2b245b710d2be3bed54225a1ffe23a9c..337fd4a121521797466ec3a9594fd220c924cc28 100644 (file)
@@ -6,7 +6,7 @@ from sqlalchemy import testing
 from test.orm import _fixtures
 from sqlalchemy.ext.baked import BakedQuery, baked_lazyload, BakedLazyLoader
 from sqlalchemy.ext import baked
-from sqlalchemy import bindparam, func
+from sqlalchemy import bindparam, func, literal_column
 from sqlalchemy.orm import exc as orm_exc
 import itertools
 from sqlalchemy.testing import mock
@@ -241,6 +241,43 @@ class LikeQueryTest(BakedTest):
             eq_(u2.name, 'ed')
         self.assert_sql_count(testing.db, go, 1)
 
+    def test_scalar(self):
+        User = self.classes.User
+
+        bq = self.bakery(lambda s: s.query(User.id))
+
+        sess = Session()
+
+        bq += lambda q: q.filter(User.id == 7)
+
+        eq_(
+            bq(sess).scalar(), 7
+        )
+
+    def test_count(self):
+        User = self.classes.User
+
+        bq = self.bakery(lambda s: s.query(User))
+
+        sess = Session()
+
+        eq_(
+            bq(sess).count(),
+            4
+        )
+
+        bq += lambda q: q.filter(User.id.in_([8, 9]))
+
+        eq_(
+            bq(sess).count(), 2
+        )
+
+        # original query still works
+        eq_(
+            set([(u.id, u.name) for u in bq(sess).all()]),
+            set([(8, 'ed'), (9, 'fred')])
+        )
+
     def test_get_pk_w_null(self):
         """test the re-implementation of logic to do get with IS NULL."""