diff --git a/drift/CHANGELOG.md b/drift/CHANGELOG.md index 99e9d7c4..de636f0b 100644 --- a/drift/CHANGELOG.md +++ b/drift/CHANGELOG.md @@ -1,6 +1,7 @@ ## 2.14.0-dev - Add the `QueryInterceptor` to easily monitor all database calls made by drift. +- Add the `count()` extension on tables to easily count rows in tables or views. ## 2.13.1 diff --git a/drift/lib/src/runtime/query_builder/on_table.dart b/drift/lib/src/runtime/query_builder/on_table.dart index 156dad3a..b9038e87 100644 --- a/drift/lib/src/runtime/query_builder/on_table.dart +++ b/drift/lib/src/runtime/query_builder/on_table.dart @@ -12,6 +12,23 @@ extension TableOrViewStatements return select(); } + /// Counts the rows in this table. + /// + /// The optional [where] clause can be used to only count rows matching the + /// condition, similar to [SimpleSelectStatement.where]. + /// + /// The returned [Selectable] can be run once with [Selectable.getSingle] to + /// get the count once, or be watched as a stream with [Selectable.watchSingle]. + Selectable count({Expression Function(Tbl row)? where}) { + final count = countAll(); + final stmt = selectOnly()..addColumns([count]); + if (where != null) { + stmt.where(where(asDslTable)); + } + + return stmt.map((row) => row.read(count)!); + } + /// Composes a `SELECT` statement on the captured table or view. /// /// This is equivalent to calling [DatabaseConnectionUser.select]. diff --git a/drift/test/database/statements/select_test.dart b/drift/test/database/statements/select_test.dart index d8c602b6..52cc3748 100644 --- a/drift/test/database/statements/select_test.dart +++ b/drift/test/database/statements/select_test.dart @@ -256,4 +256,33 @@ void main() { [r'$.foo'], )); }); + + group('count', () { + test('all', () async { + when(executor.runSelect(any, any)).thenAnswer((_) async => [ + {'c0': 3} + ]); + + final result = await db.todosTable.count().getSingle(); + expect(result, 3); + + verify(executor.runSelect( + 'SELECT COUNT(*) AS "c0" FROM "todos";', argThat(isEmpty))); + }); + + test('with filter', () async { + when(executor.runSelect(any, any)).thenAnswer((_) async => [ + {'c0': 2} + ]); + + final result = await db.todosTable + .count(where: (row) => row.id.isBiggerThanValue(12)) + .getSingle(); + expect(result, 2); + + verify(executor.runSelect( + 'SELECT COUNT(*) AS "c0" FROM "todos" WHERE "todos"."id" > ?;', + [12])); + }); + }); }