diff --git a/drift/lib/src/runtime/manager/manager.dart b/drift/lib/src/runtime/manager/manager.dart index 0485f0f8..446e69b7 100644 --- a/drift/lib/src/runtime/manager/manager.dart +++ b/drift/lib/src/runtime/manager/manager.dart @@ -283,24 +283,28 @@ class TableManagerState< /// This is so that the state can be passed down to lower level managers @internal abstract class BaseTableManager< - DB extends GeneratedDatabase, - T extends Table, - DT extends DataClass, - FS extends FilterComposer, - OS extends OrderingComposer, - C extends ProcessedTableManager, - CI extends Function, - CU extends Function> { + DB extends GeneratedDatabase, + T extends Table, + DT extends DataClass, + FS extends FilterComposer, + OS extends OrderingComposer, + C extends ProcessedTableManager, + CI extends Function, + CU extends Function> + implements + MultiSelectable
, + SingleSelectable
, + SingleOrNullSelectable
{ /// The state for this manager final TableManagerState $state; /// Create a new [BaseTableManager] instance const BaseTableManager(this.$state); - /// Set the distinct flag on the statement to true - /// This will ensure that only distinct rows are returned - C distict() { - return $state._getChildManagerBuilder($state.copyWith(distinct: true)); + /// Add a limit to the statement + C limit(int limit, {int? offset}) { + return $state + ._getChildManagerBuilder($state.copyWith(limit: limit, offset: offset)); } /// Add ordering to the statement @@ -322,12 +326,6 @@ abstract class BaseTableManager< joinBuilders: $state.joinBuilders.union(filter.joinBuilders))); } - /// Add a limit to the statement - C limit(int limit, {int? offset}) { - return $state - ._getChildManagerBuilder($state.copyWith(limit: limit, offset: offset)); - } - /// Writes all non-null fields from the entity into the columns of all rows /// that match the [filter] clause. Warning: That also means that, when you're /// not setting a where clause explicitly, this method will update all rows in @@ -351,25 +349,6 @@ abstract class BaseTableManager< /// Checks whether any rows exist Future exists() => $state.exists(); -} - -/// A table manager that can be used to select rows from a table -abstract class ProcessedTableManager< - DB extends GeneratedDatabase, - T extends Table, - D extends DataClass, - FS extends FilterComposer, - OS extends OrderingComposer, - C extends ProcessedTableManager, - CI extends Function, - CU extends Function> - extends BaseTableManager - implements - MultiSelectable, - SingleSelectable, - SingleOrNullSelectable { - /// Create a new [ProcessedTableManager] instance - const ProcessedTableManager(super.$state); /// Deletes all rows matched by built statement /// @@ -390,25 +369,47 @@ abstract class ProcessedTableManager< /// /// See also: [getSingleOrNull], which returns `null` instead of /// throwing if the query completes with no rows. + /// + /// Uses the distinct flag to ensure that only distinct rows are returned @override - Future getSingle() => $state.buildSelectStatement().getSingle(); + Future
getSingle() => + $state.copyWith(distinct: true).buildSelectStatement().getSingle(); /// Creates an auto-updating stream of this statement, similar to /// [watch]. However, it is assumed that the query will only emit /// one result, so instead of returning a `Stream>`, this returns a /// `Stream`. If, at any point, the query emits no or more than one rows, /// an error will be added to the stream instead. + /// + /// Uses the distinct flag to ensure that only distinct rows are returned @override - Stream watchSingle() => $state.buildSelectStatement().watchSingle(); + Stream
watchSingle() => + $state.copyWith(distinct: true).buildSelectStatement().watchSingle(); /// Executes the statement and returns the first all rows as a list. + /// + /// Use [limit] and [offset] to limit the number of rows returned + /// An offset will only be applied if a limit is also set + /// Set [distinct] to true to ensure that only distinct rows are returned @override - Future> get() => $state.buildSelectStatement().get(); + Future> get({bool distinct = false, int? limit, int? offset}) => + $state + .copyWith(distinct: distinct, limit: limit, offset: offset) + .buildSelectStatement() + .get(); /// Creates an auto-updating stream of the result that emits new items /// whenever any table used in this statement changes. + /// + /// Use [limit] and [offset] to limit the number of rows returned + /// An offset will only be applied if a limit is also set + /// Set [distinct] to true to ensure that only distinct rows are returned @override - Stream> watch() => $state.buildSelectStatement().watch(); + Stream> watch({bool distinct = false, int? limit, int? offset}) => + $state + .copyWith(distinct: distinct, limit: limit, offset: offset) + .buildSelectStatement() + .watch(); /// Executes this statement, like [get], but only returns one /// value. If the result too many values, this method will throw. If no @@ -416,9 +417,11 @@ abstract class ProcessedTableManager< /// /// See also: [getSingle], which can be used if the query will /// always evaluate to exactly one row. + /// + /// Uses the distinct flag to ensure that only distinct rows are returned @override - Future getSingleOrNull() => - $state.buildSelectStatement().getSingleOrNull(); + Future getSingleOrNull() => + $state.copyWith(distinct: true).buildSelectStatement().getSingleOrNull(); /// Creates an auto-updating stream of this statement, similar to /// [watch]. However, it is assumed that the query will only @@ -427,9 +430,33 @@ abstract class ProcessedTableManager< /// some point, an error will be emitted to the stream instead. /// If the query emits zero rows at some point, `null` will be added /// to the stream instead. + /// + /// Uses the distinct flag to ensure that only distinct rows are returned @override - Stream watchSingleOrNull() => - $state.buildSelectStatement().watchSingleOrNull(); + Stream watchSingleOrNull() => $state + .copyWith(distinct: true) + .buildSelectStatement() + .watchSingleOrNull(); +} + +/// A table manager that exposes methods to a table manager that already has filters/orderings/limit applied +// As of now this is identical to [BaseTableManager] but it's kept seperate for future extensibility +class ProcessedTableManager< + DB extends GeneratedDatabase, + T extends Table, + D extends DataClass, + FS extends FilterComposer, + OS extends OrderingComposer, + C extends ProcessedTableManager, + CI extends Function, + CU extends Function> + extends BaseTableManager + implements + MultiSelectable, + SingleSelectable, + SingleOrNullSelectable { + /// Create a new [ProcessedTableManager] instance + const ProcessedTableManager(super.$state); } /// A table manager with top level function for creating, reading, updating, and deleting items @@ -445,16 +472,6 @@ abstract class RootTableManager< /// Create a new [RootTableManager] instance const RootTableManager(super.$state); - /// Deletes all rows matched by built statement - /// - /// Returns the amount of rows that were deleted by this statement directly - /// (not including additional rows that might be affected through triggers or - /// foreign key constraints). - Future delete() => $state.db.delete($state._tableAsTableInfo).go(); - - /// Select all rows from the table - C all() => $state._getChildManagerBuilder($state); - /// Creates a new row in the table using the given function /// /// By default, an exception will be thrown if another row with the same diff --git a/drift/test/manager/manager_filter_tests.dart b/drift/test/manager/manager_filter_test.dart similarity index 99% rename from drift/test/manager/manager_filter_tests.dart rename to drift/test/manager/manager_filter_test.dart index 4a074bca..38775d02 100644 --- a/drift/test/manager/manager_filter_tests.dart +++ b/drift/test/manager/manager_filter_test.dart @@ -533,7 +533,6 @@ void main() { db.managers.categories .filter((f) => f.todos((f) => f.category( (f) => f.todos((f) => f.title.equals("Math Homework"))))) - .distict() .getSingle() .then((value) => value.description), completion("School")); diff --git a/drift/test/manager/manager_order_tests.dart b/drift/test/manager/manager_order_test.dart similarity index 100% rename from drift/test/manager/manager_order_tests.dart rename to drift/test/manager/manager_order_test.dart diff --git a/drift/test/manager/manager_tests.dart b/drift/test/manager/manager_test.dart similarity index 89% rename from drift/test/manager/manager_tests.dart rename to drift/test/manager/manager_test.dart index 9f3a83c4..db0c2d01 100644 --- a/drift/test/manager/manager_tests.dart +++ b/drift/test/manager/manager_test.dart @@ -16,19 +16,19 @@ void main() { test('manager - create', () async { // Initial count should be 0 - expect(db.managers.categories.all().count(), completion(0)); + expect(db.managers.categories.count(), completion(0)); // Creating a row should return the id final create1 = db.managers.categories.create( (o) => o(priority: Value(CategoryPriority.high), description: "High")); expect(create1, completion(1)); - expect(db.managers.categories.all().count(), completion(1)); + expect(db.managers.categories.count(), completion(1)); // Creating another row should increment the id final create2 = db.managers.categories.create( (o) => o(priority: Value(CategoryPriority.low), description: "Low")); expect(create2, completion(2)); - expect(db.managers.categories.all().count(), completion(2)); + expect(db.managers.categories.count(), completion(2)); // Using an existing id should throw an exception final create3 = db.managers.categories.create((o) => o( @@ -47,7 +47,7 @@ void main() { onConflict: DoNothing()); // The is incorrect when using onConflict expect(create4, completion(2)); - expect(db.managers.categories.all().count(), completion(2)); + expect(db.managers.categories.count(), completion(2)); // Likewise, test that mode is passed to the create method final create5 = db.managers.categories.create( @@ -59,13 +59,13 @@ void main() { // The is incorrect when using mode expect(create5, completion(2)); - expect(db.managers.categories.all().count(), completion(2)); + expect(db.managers.categories.count(), completion(2)); // Test the other create methods final create6 = db.managers.categories.createReturning((o) => o(priority: Value(CategoryPriority.high), description: "Other High")); expect(create6, completion(isA())); - expect(db.managers.categories.all().count(), completion(3)); + expect(db.managers.categories.count(), completion(3)); // Will return null because the description is not unique final create7 = db.managers.categories.createReturningOrNull( @@ -84,7 +84,7 @@ void main() { priority: Value(CategoryPriority.medium), description: "Super Medium") ]); - expect(db.managers.categories.all().count(), completion(6)); + expect(db.managers.categories.count(), completion(6)); }); test('manager - update', () async { @@ -135,11 +135,11 @@ void main() { final delete1 = db.managers.categories.filter(((f) => f.id(obj1.id))).delete(); expect(delete1, completion(1)); - expect(db.managers.categories.all().count(), completion(1)); + expect(db.managers.categories.count(), completion(1)); // Delete all rows final delete2 = db.managers.categories.delete(); expect(delete2, completion(1)); - expect(db.managers.categories.all().count(), completion(0)); + expect(db.managers.categories.count(), completion(0)); }); } diff --git a/drift/test/manager/processed_manager_tests.dart b/drift/test/manager/processed_manager_test.dart similarity index 95% rename from drift/test/manager/processed_manager_tests.dart rename to drift/test/manager/processed_manager_test.dart index ee53fd93..8cf01e2b 100644 --- a/drift/test/manager/processed_manager_tests.dart +++ b/drift/test/manager/processed_manager_test.dart @@ -29,18 +29,16 @@ void main() { aReal: Value(3.0), aDateTime: Value(DateTime.now().add(Duration(days: 3))))); // Test count - expect(db.managers.tableWithEveryColumnType.all().count(), completion(3)); + expect(db.managers.tableWithEveryColumnType.count(), completion(3)); // Test get expect( db.managers.tableWithEveryColumnType - .all() .get() .then((value) => value.length), completion(3)); // Test getSingle with limit expect( db.managers.tableWithEveryColumnType - .all() .limit(1, offset: 1) .getSingle() .then((value) => value.id),