]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Deprecate FromClause.count()
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 13 Jun 2016 19:18:13 +0000 (15:18 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Jun 2016 15:48:04 +0000 (11:48 -0400)
count() here is misleading in that it not only
counts from an arbitrary column in the table, it also
does not make accommodations for DISTINCT, JOIN, etc.
as the ORM-level function does.  Core should not be
attempting to provide a function like this.

Change-Id: I9916fc51ef744389a92c54660ab08e9695b8afc2
Fixes: #3724
21 files changed:
doc/build/changelog/changelog_10.rst
doc/build/changelog/changelog_11.rst
lib/sqlalchemy/sql/selectable.py
test/dialect/mssql/test_compiler.py
test/dialect/postgresql/test_query.py
test/engine/test_execute.py
test/orm/inheritance/test_basic.py
test/orm/inheritance/test_poly_persistence.py
test/orm/inheritance/test_polymorphic_rel.py
test/orm/inheritance/test_relationship.py
test/orm/test_association.py
test/orm/test_cascade.py
test/orm/test_dynamic.py
test/orm/test_mapper.py
test/orm/test_relationships.py
test/orm/test_transaction.py
test/orm/test_unitofwork.py
test/orm/test_unitofworkv2.py
test/sql/test_defaults.py
test/sql/test_metadata.py
test/sql/test_types.py

index 87ca1cb310a6c0720958e08a3c771c97d83ec89c..7a41731bff0eac7d97b9dad99c5b8744abba6d11 100644 (file)
 .. changelog::
     :version: 1.0.14
 
+    .. change::
+        :tags: bug, sql
+        :tickets: 3724
+
+        :meth:`.FromClause.count` is pending deprecation for 1.1.  This function
+        makes use of an arbitrary column in the table and is not reliable;
+        for Core use, ``func.count()`` should be preferred.
+
     .. change::
         :tags: bug, sql
         :tickets: 3722
index 8d20ef257d68f75c62e7efbbe67e4cd3d509a627..923148232d1f6af5fe9560d2fb1f92b64f8a0373 100644 (file)
 .. changelog::
     :version: 1.1.0b1
 
+    .. change::
+        :tags: bug, sql
+        :tickets: 3724
+
+        :meth:`.FromClause.count` is deprecated.  This function makes use of
+        an arbitrary column in the table and is not reliable; for Core use,
+        ``func.count()`` should be preferred.
+
     .. change::
         :tags: feature, postgresql
         :pullreq: bitbucket:84
index f75613e35e822d0b80a1c43133b6090271226fe3..ac955a60f718b70990f0866df3ebf087f9c4bcc0 100644 (file)
@@ -308,10 +308,34 @@ class FromClause(Selectable):
 
     _memoized_property = util.group_expirable_memoized_property(["_columns"])
 
+    @util.deprecated(
+        '1.1',
+        message="``FromClause.count()`` is deprecated. Counting "
+        "rows requires that the correct column expression and "
+        "accommodations for joins, DISTINCT, etc. must be made, "
+        "otherwise results may not be what's expected. "
+        "Please use an appropriate ``func.count()`` expression "
+        "directly.")
     @util.dependencies("sqlalchemy.sql.functions")
     def count(self, functions, whereclause=None, **params):
         """return a SELECT COUNT generated against this
-        :class:`.FromClause`."""
+        :class:`.FromClause`.
+
+        The function generates COUNT against the
+        first column in the primary key of the table, or against
+        the first column in the table overall.   Explicit use of
+        ``func.count()`` should be preferred::
+
+            row_count = conn.scalar(
+                select([func.count('*')]).select_from(table)
+            )
+
+
+        .. seealso::
+
+            :data:`.func`
+
+        """
 
         if self.primary_key:
             col = list(self.primary_key)[0]
@@ -1610,21 +1634,6 @@ class TableClause(Immutable, FromClause):
         else:
             return []
 
-    @util.dependencies("sqlalchemy.sql.functions")
-    def count(self, functions, whereclause=None, **params):
-        """return a SELECT COUNT generated against this
-        :class:`.TableClause`."""
-
-        if self.primary_key:
-            col = list(self.primary_key)[0]
-        else:
-            col = list(self.columns)[0]
-        return Select(
-            [functions.func.count(col).label('tbl_row_count')],
-            whereclause,
-            from_obj=[self],
-            **params)
-
     @util.dependencies("sqlalchemy.sql.dml")
     def insert(self, dml, values=None, inline=False, **kwargs):
         """Generate an :func:`.insert` construct against this
index 92ff1806933f3dc37f22427c5b370e3a9b4c06d2..0cf84c7d59cf357a84358c52c0971094994dca93 100644 (file)
@@ -9,7 +9,7 @@ from sqlalchemy import sql
 from sqlalchemy import Integer, String, Table, Column, select, MetaData,\
     update, delete, insert, extract, union, func, PrimaryKeyConstraint, \
     UniqueConstraint, Index, Sequence, literal
-
+from sqlalchemy import testing
 
 class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
     __dialect__ = mssql.dialect()
@@ -244,6 +244,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
                             '(SELECT sometable.somecolumn FROM '
                             'sometable)')
 
+    @testing.uses_deprecated
     def test_count(self):
         t = table('sometable', column('somecolumn'))
         self.assert_compile(t.count(),
index c031e43def9e161f5b84a00628cd55f6d781051b..538312a6a97b63d3959c1e632bb04632a29711de 100644 (file)
@@ -689,28 +689,28 @@ class ServerSideCursorsTest(fixtures.TestBase, AssertsExecutionResults):
         result = engine.execute(s)
         assert result.cursor.name
 
+    @testing.provide_metadata
     def test_roundtrip(self):
+        md = self.metadata
+
         engine = self._fixture(True)
-        test_table = Table('test_table', MetaData(engine),
+        test_table = Table('test_table', md,
                            Column('id', Integer, primary_key=True),
                            Column('data', String(50)))
         test_table.create(checkfirst=True)
-        try:
-            test_table.insert().execute(data='data1')
-            nextid = engine.execute(Sequence('test_table_id_seq'))
-            test_table.insert().execute(id=nextid, data='data2')
-            eq_(test_table.select().execute().fetchall(), [(1, 'data1'
-                                                            ), (2, 'data2')])
-            test_table.update().where(
-                test_table.c.id == 2).values(
-                data=test_table.c.data +
-                ' updated').execute()
-            eq_(test_table.select().execute().fetchall(),
-                [(1, 'data1'), (2, 'data2 updated')])
-            test_table.delete().execute()
-            eq_(test_table.count().scalar(), 0)
-        finally:
-            test_table.drop(checkfirst=True)
+        test_table.insert().execute(data='data1')
+        nextid = engine.execute(Sequence('test_table_id_seq'))
+        test_table.insert().execute(id=nextid, data='data2')
+        eq_(test_table.select().execute().fetchall(), [(1, 'data1'
+                                                        ), (2, 'data2')])
+        test_table.update().where(
+            test_table.c.id == 2).values(
+            data=test_table.c.data +
+            ' updated').execute()
+        eq_(test_table.select().execute().fetchall(),
+            [(1, 'data1'), (2, 'data2 updated')])
+        test_table.delete().execute()
+        eq_(select([func.count('*')]).select_from(test_table).scalar(), 0)
 
 
 class MatchTest(fixtures.TestBase, AssertsCompiledSQL):
index b1c8673d11ddf6b316f74e28f87936a1bd54b0c7..8e553307fdf1dfc6565a2eec8740cca2078fd00a 100644 (file)
@@ -599,7 +599,8 @@ class ConvenienceExecuteTest(fixtures.TablesTest):
 
     def _assert_no_data(self):
         eq_(
-            testing.db.scalar(self.table.count()), 0
+            testing.db.scalar(
+                select([func.count('*')]).select_from(self.table)), 0
         )
 
     def _assert_fn(self, x, value=None):
index 3717fafa0c64f83413bcd000d7336a073c3a2296..42959a6e3694203c810160e9189d6aef89924f1c 100644 (file)
@@ -1104,7 +1104,7 @@ class FlushTest(fixtures.MappedTest):
         sess.add(a)
         sess.flush()
 
-        assert user_roles.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(user_roles).scalar(), 1)
 
     def test_two(self):
         admins, users, roles, user_roles = (self.tables.admins,
@@ -1146,7 +1146,7 @@ class FlushTest(fixtures.MappedTest):
 
         a.password = 'sadmin'
         sess.flush()
-        assert user_roles.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(user_roles).scalar(), 1)
 
 
 class PassiveDeletesTest(fixtures.MappedTest):
index 361377de8eaeed3590e2bc8694bb117d145e8979..9a89a39708503623ee864dec48c5d262209e0d1f 100644 (file)
@@ -335,7 +335,7 @@ def _generate_round_trip_test(include_base, lazy_relationship,
         session.delete(c)
         session.flush()
 
-        eq_(people.count().scalar(), 0)
+        eq_(select([func.count('*')]).select_from(people).scalar(), 0)
 
     test_roundtrip = function_named(
         test_roundtrip, "test_%s%s%s_%s" % (
index 79278ba3e3eb9a916da542294d5bb2d242a5e5df..5e810bb3cb6abaae102a120a94df84bcd6791254 100644 (file)
@@ -1,4 +1,4 @@
-from sqlalchemy import func, desc
+from sqlalchemy import func, desc, select
 from sqlalchemy.orm import interfaces, create_session, joinedload, joinedload_all, \
     subqueryload, subqueryload_all, aliased,\
     class_mapper, with_polymorphic
@@ -86,11 +86,13 @@ class _PolymorphicTestBase(object):
                 all_employees[1:3])
         self.assert_sql_count(testing.db, go, 3)
 
-        eq_(sess.query(Person).with_polymorphic('*')
+        eq_(
+            select([func.count('*')]).select_from(
+                sess.query(Person).with_polymorphic('*')
                 .options(joinedload(Engineer.machines))
-                .limit(2).offset(1).with_labels()
-                .subquery().count().scalar(),
-            2)
+                .limit(2).offset(1).with_labels().subquery()
+            ).scalar(),
+        2)
 
     def test_get_one(self):
         """
index 01167b23e665e3e8b88692eefc02de95be7813ae..379d8f7e46a198ec0856bd454c0da2afbda30bef 100644 (file)
@@ -2,7 +2,7 @@ from sqlalchemy.orm import create_session, relationship, mapper, \
     contains_eager, joinedload, subqueryload, subqueryload_all,\
     Session, aliased, with_polymorphic, joinedload_all
 
-from sqlalchemy import Integer, String, ForeignKey
+from sqlalchemy import Integer, String, ForeignKey, select, func
 from sqlalchemy.engine import default
 
 from sqlalchemy.testing import AssertsCompiledSQL, fixtures
@@ -587,7 +587,12 @@ class SelfReferentialM2MTest(fixtures.MappedTest, AssertsCompiledSQL):
         )
 
         # another way to check
-        assert q.limit(1).with_labels().subquery().count().scalar() == 1
+        eq_(
+            select([func.count('*')]).select_from(
+                q.limit(1).with_labels().subquery()
+            ).scalar(),
+            1
+        )
         assert q.first() is c1
 
     def test_subquery_load(self):
index bcd2131fb5d0707cd2615123d379b08ae61635e8..f02064a359c448573d4f48026f85bce4f44239cc 100644 (file)
@@ -1,6 +1,6 @@
 
 from sqlalchemy import testing
-from sqlalchemy import Integer, String, ForeignKey
+from sqlalchemy import Integer, String, ForeignKey, func, select
 from sqlalchemy.testing.schema import Table, Column
 from sqlalchemy.orm import mapper, relationship, create_session
 from sqlalchemy.testing import fixtures
@@ -153,11 +153,11 @@ class AssociationTest(fixtures.MappedTest):
         item2.keywords.append(KeywordAssociation(Keyword('green'), 'green_assoc'))
         sess.add_all((item1, item2))
         sess.flush()
-        eq_(item_keywords.count().scalar(), 3)
+        eq_(select([func.count('*')]).select_from(item_keywords).scalar(), 3)
 
         sess.delete(item1)
         sess.delete(item2)
         sess.flush()
-        eq_(item_keywords.count().scalar(), 0)
+        eq_(select([func.count('*')]).select_from(item_keywords).scalar(), 0)
 
 
index f104ee34c0b756aef7f1c0f3337d3e635f17df01..2522ab918e35a2c5886da0ed5d144bd115ce0d14 100644 (file)
@@ -1,8 +1,8 @@
 import copy
 
 from sqlalchemy.testing import assert_raises, assert_raises_message
-from sqlalchemy import Integer, String, ForeignKey, Sequence, \
-    exc as sa_exc, util
+from sqlalchemy import Integer, String, ForeignKey, \
+    exc as sa_exc, util, select, func
 from sqlalchemy.testing.schema import Table, Column
 from sqlalchemy.orm import mapper, relationship, create_session, \
     sessionmaker, class_mapper, backref, Session, util as orm_util,\
@@ -284,8 +284,8 @@ class O2MCascadeDeleteOrphanTest(fixtures.MappedTest):
 
         sess.delete(u)
         sess.flush()
-        assert users.count().scalar() == 0
-        assert orders.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(users).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(orders).scalar(), 0)
 
     def test_delete_unloaded_collections(self):
         """Unloaded collections are still included in a delete-cascade
@@ -303,16 +303,16 @@ class O2MCascadeDeleteOrphanTest(fixtures.MappedTest):
         sess.add(u)
         sess.flush()
         sess.expunge_all()
-        assert addresses.count().scalar() == 2
-        assert users.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(addresses).scalar(), 2)
+        eq_(select([func.count('*')]).select_from(users).scalar(), 1)
 
         u = sess.query(User).get(u.id)
 
         assert 'addresses' not in u.__dict__
         sess.delete(u)
         sess.flush()
-        assert addresses.count().scalar() == 0
-        assert users.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(addresses).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(users).scalar(), 0)
 
     def test_cascades_onlycollection(self):
         """Cascade only reaches instances that are still part of the
@@ -342,8 +342,8 @@ class O2MCascadeDeleteOrphanTest(fixtures.MappedTest):
         sess.add(u2)
         sess.flush()
         sess.expunge_all()
-        assert users.count().scalar() == 1
-        assert orders.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(users).scalar(), 1)
+        eq_(select([func.count('*')]).select_from(orders).scalar(), 1)
         eq_(sess.query(User).all(),
             [User(name='newuser',
                   orders=[Order(description='someorder')])])
@@ -391,14 +391,14 @@ class O2MCascadeDeleteOrphanTest(fixtures.MappedTest):
                          Order(description='someotherorder')])
         sess.add(u)
         sess.flush()
-        assert users.count().scalar() == 1
-        assert orders.count().scalar() == 2
+        eq_(select([func.count('*')]).select_from(users).scalar(), 1)
+        eq_(select([func.count('*')]).select_from(orders).scalar(), 2)
 
         del u.orders[0]
         sess.delete(u)
         sess.flush()
-        assert users.count().scalar() == 0
-        assert orders.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(users).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(orders).scalar(), 0)
 
     def test_collection_orphans(self):
         User, users, orders, Order = (self.classes.User,
@@ -413,15 +413,15 @@ class O2MCascadeDeleteOrphanTest(fixtures.MappedTest):
         sess.add(u)
         sess.flush()
 
-        assert users.count().scalar() == 1
-        assert orders.count().scalar() == 2
+        eq_(select([func.count('*')]).select_from(users).scalar(), 1)
+        eq_(select([func.count('*')]).select_from(orders).scalar(), 2)
 
         u.orders[:] = []
 
         sess.flush()
 
-        assert users.count().scalar() == 1
-        assert orders.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(users).scalar(), 1)
+        eq_(select([func.count('*')]).select_from(orders).scalar(), 0)
 
 class O2MCascadeTest(fixtures.MappedTest):
     run_inserts = None
@@ -532,14 +532,14 @@ class O2MCascadeDeleteNoOrphanTest(fixtures.MappedTest):
                          Order(description='someotherorder')])
         sess.add(u)
         sess.flush()
-        assert users.count().scalar() == 1
-        assert orders.count().scalar() == 2
+        eq_(select([func.count('*')]).select_from(users).scalar(), 1)
+        eq_(select([func.count('*')]).select_from(orders).scalar(), 2)
 
         del u.orders[0]
         sess.delete(u)
         sess.flush()
-        assert users.count().scalar() == 0
-        assert orders.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(users).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(orders).scalar(), 1)
 
 class O2OSingleParentTest(_fixtures.FixtureTest):
     run_inserts = None
@@ -1289,13 +1289,13 @@ class M2OCascadeDeleteOrphanTestOne(fixtures.MappedTest):
                                 self.tables.extra)
 
         sess = create_session()
-        assert prefs.count().scalar() == 3
-        assert extra.count().scalar() == 3
+        eq_(select([func.count('*')]).select_from(prefs).scalar(), 3)
+        eq_(select([func.count('*')]).select_from(extra).scalar(), 3)
         jack = sess.query(User).filter_by(name="jack").one()
         jack.pref = None
         sess.flush()
-        assert prefs.count().scalar() == 2
-        assert extra.count().scalar() == 2
+        eq_(select([func.count('*')]).select_from(prefs).scalar(), 2)
+        eq_(select([func.count('*')]).select_from(extra).scalar(), 2)
 
     def test_cascade_on_deleted(self):
         """test a bug introduced by r6711"""
@@ -1365,8 +1365,8 @@ class M2OCascadeDeleteOrphanTestOne(fixtures.MappedTest):
         assert p in sess
         assert e in sess
         sess.flush()
-        assert prefs.count().scalar() == 2
-        assert extra.count().scalar() == 2
+        eq_(select([func.count('*')]).select_from(prefs).scalar(), 2)
+        eq_(select([func.count('*')]).select_from(extra).scalar(), 2)
 
     def test_pending_expunge(self):
         Pref, User = self.classes.Pref, self.classes.User
@@ -1755,9 +1755,9 @@ class M2MCascadeTest(fixtures.MappedTest):
 
         a1.bs.remove(b1)
         sess.flush()
-        assert atob.count().scalar() ==0
-        assert b.count().scalar() == 0
-        assert a.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(atob).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(b).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(a).scalar(), 1)
 
     def test_delete_orphan_dynamic(self):
         a, A, B, b, atob = (self.tables.a,
@@ -1780,9 +1780,9 @@ class M2MCascadeTest(fixtures.MappedTest):
 
         a1.bs.remove(b1)
         sess.flush()
-        assert atob.count().scalar() == 0
-        assert b.count().scalar() == 0
-        assert a.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(atob).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(b).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(a).scalar(), 1)
 
     def test_delete_orphan_cascades(self):
         a, A, c, b, C, B, atob = (self.tables.a,
@@ -1811,10 +1811,10 @@ class M2MCascadeTest(fixtures.MappedTest):
 
         a1.bs.remove(b1)
         sess.flush()
-        assert atob.count().scalar() ==0
-        assert b.count().scalar() == 0
-        assert a.count().scalar() == 1
-        assert c.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(atob).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(b).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(a).scalar(), 1)
+        eq_(select([func.count('*')]).select_from(c).scalar(), 0)
 
     def test_cascade_delete(self):
         a, A, B, b, atob = (self.tables.a,
@@ -1836,9 +1836,9 @@ class M2MCascadeTest(fixtures.MappedTest):
 
         sess.delete(a1)
         sess.flush()
-        assert atob.count().scalar() ==0
-        assert b.count().scalar() == 0
-        assert a.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(atob).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(b).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(a).scalar(), 0)
 
     def test_single_parent_error(self):
         a, A, B, b, atob = (self.tables.a,
index 950ff19539b50ad4b73195cf63f669b8d45f0cd4..a1d6217884ba4ce010ed95dd9d4b8e386d3a0901 100644 (file)
@@ -564,8 +564,14 @@ class UOWTest(
         )
         sess.add(u)
         sess.commit()
-        eq_(testing.db.scalar(addresses.count(addresses.c.user_id == None)), 0)
-        eq_(testing.db.scalar(addresses.count(addresses.c.user_id != None)), 6)
+        eq_(
+            testing.db.scalar(
+                select([func.count('*')]).where(addresses.c.user_id == None)),
+            0)
+        eq_(
+            testing.db.scalar(
+                select([func.count('*')]).where(addresses.c.user_id != None)),
+            6)
 
         sess.delete(u)
 
@@ -574,12 +580,26 @@ class UOWTest(
         if expected:
             eq_(
                 testing.db.scalar(
-                    addresses.count(addresses.c.user_id == None)), 6)
+                    select([func.count('*')]).where(
+                        addresses.c.user_id == None
+                    )
+                ),
+                6
+            )
             eq_(
                 testing.db.scalar(
-                    addresses.count(addresses.c.user_id != None)), 0)
+                    select([func.count('*')]).where(
+                        addresses.c.user_id != None
+                    )
+                ),
+                0
+            )
         else:
-            eq_(testing.db.scalar(addresses.count()), 0)
+            eq_(
+                testing.db.scalar(
+                    select([func.count('*')]).select_from(addresses)
+                ),
+                0)
 
     def test_delete_nocascade(self):
         self._test_delete_cascade(True)
index e357a7e256470bf30cd62463ee8deac41dfc0012..bc5f24fb2cfe4ce3ae92b3b467472f2cc5e8a677 100644 (file)
@@ -3,7 +3,8 @@
 from sqlalchemy.testing import assert_raises, assert_raises_message
 import sqlalchemy as sa
 from sqlalchemy import testing
-from sqlalchemy import MetaData, Integer, String, ForeignKey, func, util
+from sqlalchemy import MetaData, Integer, String, \
+    ForeignKey, func, util, select
 from sqlalchemy.testing.schema import Table, Column
 from sqlalchemy.engine import default
 from sqlalchemy.orm import mapper, relationship, backref, \
@@ -1070,8 +1071,10 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
         sess.add(a)
         sess.flush()
 
-        eq_(addresses.count().scalar(), 6)
-        eq_(email_bounces.count().scalar(), 5)
+        eq_(
+            select([func.count('*')]).select_from(addresses).scalar(), 6)
+        eq_(
+            select([func.count('*')]).select_from(email_bounces).scalar(), 5)
 
     def test_mapping_to_outerjoin(self):
         """Mapping to an outer join with a nullable composite primary key."""
@@ -2996,7 +2999,9 @@ class RequirementsTest(fixtures.MappedTest):
         h1.h1s.append(H1())
 
         s.flush()
-        eq_(ht1.count().scalar(), 4)
+        eq_(
+            select([func.count('*')]).select_from(ht1)
+                .scalar(), 4)
 
         h6 = H6()
         h6.h1a = h1
index 00d41604ca234b1cd2c440bae34a7cf1b0abb463..429e0f3083e5619116d0642514dcceb34374a8c9 100644 (file)
@@ -2,7 +2,8 @@ from sqlalchemy.testing import assert_raises, assert_raises_message
 import datetime
 import sqlalchemy as sa
 from sqlalchemy import testing
-from sqlalchemy import Integer, String, ForeignKey, MetaData, and_
+from sqlalchemy import Integer, String, ForeignKey, MetaData, and_, \
+    select, func
 from sqlalchemy.testing.schema import Table, Column
 from sqlalchemy.orm import mapper, relationship, relation, \
     backref, create_session, configure_mappers, \
@@ -1980,12 +1981,12 @@ class TypedAssociationTable(fixtures.MappedTest):
         sess.add(a)
         sess.flush()
 
-        assert t3.count().scalar() == 2
+        eq_(select([func.count('*')]).select_from(t3).scalar(), 2)
 
         a.t2s.remove(c)
         sess.flush()
 
-        assert t3.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(t3).scalar(), 1)
 
 
 class CustomOperatorTest(fixtures.MappedTest, AssertsCompiledSQL):
index e4ada2292ecfab155e51c681fe83349663c51675..85125e2b7d8e50e8a60b61fb2cba94037a71ea61 100644 (file)
@@ -209,8 +209,8 @@ class SessionTransactionTest(FixtureTest):
         sess.commit()
         sess.close()
         engine2.dispose()
-        assert users.count().scalar() == 1
-        assert addresses.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(users).scalar(), 1)
+        eq_(select([func.count('*')]).select_from(addresses).scalar(), 1)
 
     @testing.requires.independent_connections
     def test_invalidate(self):
@@ -932,10 +932,11 @@ class AutoExpireTest(_LocalFixture):
         # because the identity map would switch it
         u1 = s.query(User).filter_by(name='ed').one()
         assert u1_state not in s.identity_map.all_states()
-        assert s.scalar(users.count()) == 1
+
+        eq_(s.scalar(select([func.count('*')]).select_from(users)), 1)
         s.delete(u1)
         s.flush()
-        assert s.scalar(users.count()) == 0
+        eq_(s.scalar(select([func.count('*')]).select_from(users)), 0)
         s.commit()
 
     def test_trans_deleted_cleared_on_rollback(self):
index 21cb1dd12c06e86fbb943fde1f650eacf185eeda..72b913b1a6dcf4dea00963709c056887d4ca7812 100644 (file)
@@ -8,8 +8,7 @@ from sqlalchemy.orm import mapper as orm_mapper
 import sqlalchemy as sa
 from sqlalchemy.util import u, ue, b
 from sqlalchemy import Integer, String, ForeignKey, \
-    literal_column, event, Boolean
-from sqlalchemy.testing import engines
+    literal_column, event, Boolean, select, func
 from sqlalchemy import testing
 from sqlalchemy.testing.schema import Table
 from sqlalchemy.testing.schema import Column
@@ -370,9 +369,10 @@ class ForeignPKTest(fixtures.MappedTest):
         session.add(p)
         session.flush()
 
-        p_count = people.count(people.c.person=='im the key').scalar()
+        p_count = select([func.count('*')]).where(
+            people.c.person=='im the key').scalar()
         eq_(p_count, 1)
-        eq_(peoplesites.count(peoplesites.c.person=='im the key').scalar(), 1)
+        eq_(select([func.count('*')]).where(peoplesites.c.person=='im the key').scalar(), 1)
 
 
 class ClauseAttributesTest(fixtures.MappedTest):
@@ -531,13 +531,13 @@ class PassiveDeletesTest(fixtures.MappedTest):
         session.flush()
         session.expunge_all()
 
-        assert myothertable.count().scalar() == 4
+        eq_(select([func.count('*')]).select_from(myothertable).scalar(), 4)
         mc = session.query(MyClass).get(mc.id)
         session.delete(mc)
         session.flush()
 
-        assert mytable.count().scalar() == 0
-        assert myothertable.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(mytable).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(myothertable).scalar(), 0)
 
     @testing.emits_warning(r".*'passive_deletes' is normally configured on one-to-many")
     def test_backwards_pd(self):
@@ -565,16 +565,16 @@ class PassiveDeletesTest(fixtures.MappedTest):
         session.add(mco)
         session.flush()
 
-        assert mytable.count().scalar() == 1
-        assert myothertable.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(mytable).scalar(), 1)
+        eq_(select([func.count('*')]).select_from(myothertable).scalar(), 1)
 
         session.expire(mco, ['myclass'])
         session.delete(mco)
         session.flush()
 
         # mytable wasn't deleted, is the point.
-        assert mytable.count().scalar() == 1
-        assert myothertable.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(mytable).scalar(), 1)
+        eq_(select([func.count('*')]).select_from(myothertable).scalar(), 0)
 
     def test_aaa_m2o_emits_warning(self):
         myothertable, MyClass, MyOtherClass, mytable = (self.tables.myothertable,
@@ -681,7 +681,7 @@ class ExtraPassiveDeletesTest(fixtures.MappedTest):
         session.flush()
         session.expunge_all()
 
-        assert myothertable.count().scalar() == 4
+        eq_(select([func.count('*')]).select_from(myothertable).scalar(), 4)
         mc = session.query(MyClass).get(mc.id)
         session.delete(mc)
         assert_raises(sa.exc.DBAPIError, session.flush)
@@ -705,7 +705,7 @@ class ExtraPassiveDeletesTest(fixtures.MappedTest):
         session.flush()
         session.expunge_all()
 
-        assert myothertable.count().scalar() == 1
+        eq_(select([func.count('*')]).select_from(myothertable).scalar(), 1)
 
         mc = session.query(MyClass).get(mc.id)
         session.delete(mc)
@@ -1589,8 +1589,8 @@ class SaveTest(_fixtures.FixtureTest):
         u = session.query(User).get(u.id)
         session.delete(u)
         session.flush()
-        assert users.count().scalar() == 0
-        assert addresses.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(users).scalar(), 0)
+        eq_(select([func.count('*')]).select_from(addresses).scalar(), 0)
 
     def test_batch_mode(self):
         """The 'batch=False' flag on mapper()"""
@@ -1966,10 +1966,10 @@ class ManyToManyTest(_fixtures.FixtureTest):
         session.add(i)
         session.flush()
 
-        assert item_keywords.count().scalar() == 2
+        eq_(select([func.count('*')]).select_from(item_keywords).scalar(), 2)
         i.keywords = []
         session.flush()
-        assert item_keywords.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(item_keywords).scalar(), 0)
 
     def test_scalar(self):
         """sa.dependency won't delete an m2m relationship referencing None."""
@@ -2173,10 +2173,10 @@ class SaveTest3(fixtures.MappedTest):
         session.add(i)
         session.flush()
 
-        assert assoc.count().scalar() == 2
+        eq_(select([func.count('*')]).select_from(assoc).scalar(), 2)
         i.keywords = []
         session.flush()
-        assert assoc.count().scalar() == 0
+        eq_(select([func.count('*')]).select_from(assoc).scalar(), 0)
 
 
 class BooleanColTest(fixtures.MappedTest):
index c8ce13c913ca43d355e170abb008d14f49a16f5b..bfc050e35a49c2b379e3206dd2d29c273a13fc90 100644 (file)
@@ -6,7 +6,7 @@ from test.orm import _fixtures
 from sqlalchemy import exc, util
 from sqlalchemy.testing import fixtures, config
 from sqlalchemy import Integer, String, ForeignKey, func, \
-    literal, FetchedValue, text
+    literal, FetchedValue, text, select
 from sqlalchemy.orm import mapper, relationship, backref, \
     create_session, unitofwork, attributes,\
     Session, exc as orm_exc
@@ -1306,7 +1306,9 @@ class RowswitchAccountingTest(fixtures.MappedTest):
         eq_(p1.id, 5)
         sess.flush()
 
-        eq_(sess.scalar(self.tables.parent.count()), 0)
+        eq_(
+            select([func.count('*')]).select_from(self.tables.parent).scalar(),
+            0)
 
 
 class RowswitchM2OTest(fixtures.MappedTest):
index e21b21ab22d1a21d4513929f3afa616c1aad4e18..db19e145bd0b40c66d03cd500397539f5b9e23ff 100644 (file)
@@ -775,7 +775,8 @@ class AutoIncrementTest(fixtures.TablesTest):
 
         testing.db.execute(dataset_no_autoinc.insert())
         eq_(
-            testing.db.scalar(dataset_no_autoinc.count()), 1
+            testing.db.scalar(
+                select([func.count('*')]).select_from(dataset_no_autoinc)), 1
         )
 
 
index 344cfefa5eae7ef65034409d9ea1156431b67859..92d35e6e5346a33982b5c9077af3394d96e889d9 100644 (file)
@@ -23,18 +23,6 @@ from sqlalchemy import util
 
 class MetaDataTest(fixtures.TestBase, ComparesTables):
 
-    def test_metadata_connect(self):
-        metadata = MetaData()
-        t1 = Table('table1', metadata,
-                   Column('col1', Integer, primary_key=True),
-                   Column('col2', String(20)))
-        metadata.bind = testing.db
-        metadata.create_all()
-        try:
-            assert t1.count().scalar() == 0
-        finally:
-            metadata.drop_all()
-
     def test_metadata_contains(self):
         metadata = MetaData()
         t1 = Table('t1', metadata, Column('x', Integer))
index 3d527b261d6d951780fb6c275156af65ce720a8c..67d20871c2a345c44291ae5d432f1e3fe7b2c255 100644 (file)
@@ -1477,8 +1477,8 @@ class BinaryTest(fixtures.TestBase, AssertsExecutionResults):
         data = os.urandom(32)
         binary_table.insert().execute(data=data)
         eq_(
-            binary_table.select().where(binary_table.c.data == data).alias().
-            count().scalar(), 1)
+            select([func.count('*')]).select_from(binary_table).
+            where(binary_table.c.data == data).scalar(), 1)
 
     @testing.requires.binary_literals
     def test_literal_roundtrip(self):