diff --git a/drift/lib/src/runtime/manager/manager.dart b/drift/lib/src/runtime/manager/manager.dart index 83f85135..cc1b321c 100644 --- a/drift/lib/src/runtime/manager/manager.dart +++ b/drift/lib/src/runtime/manager/manager.dart @@ -230,7 +230,10 @@ class TableManagerState< final count = countAll(); final result = _buildSelectStatement(targetColumns: [count]) as _JoinedResult; - return result.statement.map((row) => row.read(count)!).getSingle(); + return result.statement + .map((row) => row.read(count)!) + .get() + .then((value) => value.firstOrNull ?? 0); } /// Check if any rows exists using the built statement @@ -331,7 +334,7 @@ abstract class BaseTableManager< /// /// See also: [RootTableManager.replace], which does not require [filter] statements and /// supports setting fields back to null. - Future write(Insertable
Function(CU o) f) => + Future update(Insertable
Function(CU o) f) => $state.buildUpdateStatement().write(f($state._getUpdateCompanionBuilder)); } @@ -441,8 +444,7 @@ abstract class RootTableManager< /// 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(Insertable entity) => - $state.db.delete($state._tableAsTableInfo).delete(entity); + Future delete() => $state.db.delete($state._tableAsTableInfo).go(); /// Select all rows from the table C all() => $state._getChildManagerBuilder($state); @@ -532,7 +534,7 @@ abstract class RootTableManager< /// If [entity] has absent values (set to null on the [DataClass] or /// explicitly to absent on the [UpdateCompanion]), and a default value for /// the field exists, that default value will be used. Otherwise, the field - /// will be reset to null. This behavior is different to [write], which simply + /// will be reset to null. This behavior is different to [update], which simply /// ignores such fields without changing them in the database. /// /// Returns true if a row was affected by this operation. diff --git a/drift/test/manager/filter_composer_test.dart b/drift/test/manager/filter_composer_test.dart deleted file mode 100644 index 9c20b3d9..00000000 --- a/drift/test/manager/filter_composer_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:test/test.dart'; - -import '../generated/todos.dart'; -import '../test_utils/matchers.dart'; -import '../test_utils/mocks.dart'; - -void main() { - driftRuntimeOptions.dontWarnAboutMultipleDatabases = true; - - late TodoDb db; - late MockExecutor executor; - - setUp(() { - executor = MockExecutor(); - db = TodoDb(executor); - }); - - test('manager - generates parentheses for OR in AND', () { - final filterComposer = $$CategoriesTableFilterComposer(db, db.categories); - final expr = (filterComposer.idValue(1) | filterComposer.idValue(2)) & - (filterComposer.idValue(3) | filterComposer.idValue(4)); - expect( - expr.expression, - generates( - '("id" = ? OR "id" = ?) AND ("id" = ? OR "id" = ?)', [1, 2, 3, 4])); - }); - - test('manager - equals', () { - final filterComposer = $$CategoriesTableFilterComposer(db, db.categories); - // Numeric - expect(filterComposer.idValue.equals(3).expression, - generates('"id" = ?', [3])); - expect(filterComposer.idValue(3).expression, generates('"id" = ?', [3])); - expect( - filterComposer.idValue.isNull().expression, generates('"id" IS NULL')); - // Text - expect(filterComposer.description.equals("Hi").expression, - generates('"desc" = ?', ["Hi"])); - expect(filterComposer.description("Hi").expression, - generates('"desc" = ?', ["Hi"])); - expect(filterComposer.description.isNull().expression, - generates('"desc" IS NULL')); - }); - - // test('manager - combine query with AND ', () { - // e.expression.hashCode; - - // expect( - // countAll(filter: e.expression), - // generates('WHERE "id" = FILTER (WHERE foo >= ?)', [1, 2]), - // ); - // }); -} diff --git a/drift/test/manager/manager_filter_tests.dart b/drift/test/manager/manager_filter_tests.dart new file mode 100644 index 00000000..cccf1770 --- /dev/null +++ b/drift/test/manager/manager_filter_tests.dart @@ -0,0 +1,16 @@ +import 'package:drift/drift.dart'; +import 'package:test/test.dart'; + +import '../generated/todos.dart'; +import '../test_utils/test_utils.dart'; + +void main() { + driftRuntimeOptions.dontWarnAboutMultipleDatabases = true; + late TodoDb db; + + setUp(() { + db = TodoDb(testInMemoryDatabase()); + }); + + tearDown(() => db.close()); +} diff --git a/drift/test/manager/manager_tests.dart b/drift/test/manager/manager_tests.dart new file mode 100644 index 00000000..9f3a83c4 --- /dev/null +++ b/drift/test/manager/manager_tests.dart @@ -0,0 +1,145 @@ +import 'package:drift/drift.dart'; +import 'package:test/test.dart'; + +import '../generated/todos.dart'; +import '../test_utils/test_utils.dart'; + +void main() { + driftRuntimeOptions.dontWarnAboutMultipleDatabases = true; + late TodoDb db; + + setUp(() { + db = TodoDb(testInMemoryDatabase()); + }); + + tearDown(() => db.close()); + + test('manager - create', () async { + // Initial count should be 0 + expect(db.managers.categories.all().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)); + + // 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)); + + // Using an existing id should throw an exception + final create3 = db.managers.categories.create((o) => o( + priority: Value(CategoryPriority.medium), + description: "Medium", + id: Value(RowId(1)))); + expect(create3, throwsException); + + // Using on conflict should not throw an exception + // Only using DoNothing test that onConflict is being passed to the create method + final create4 = db.managers.categories.create( + (o) => o( + priority: Value(CategoryPriority.medium), + description: "Medium", + id: Value(RowId(1))), + onConflict: DoNothing()); + // The is incorrect when using onConflict + expect(create4, completion(2)); + expect(db.managers.categories.all().count(), completion(2)); + + // Likewise, test that mode is passed to the create method + final create5 = db.managers.categories.create( + (o) => o( + priority: Value(CategoryPriority.medium), + description: "Medium", + id: Value(RowId(1))), + mode: InsertMode.insertOrIgnore); + + // The is incorrect when using mode + expect(create5, completion(2)); + expect(db.managers.categories.all().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)); + + // Will return null because the description is not unique + final create7 = db.managers.categories.createReturningOrNull( + (o) => o( + priority: Value(CategoryPriority.high), + description: "High", + ), + mode: InsertMode.insertOrIgnore); + expect(create7, completion(null)); + + // Test batch create + await db.managers.categories.bulkCreate((o) => [ + o(priority: Value(CategoryPriority.high), description: "Super High"), + o(priority: Value(CategoryPriority.low), description: "Super Low"), + o( + priority: Value(CategoryPriority.medium), + description: "Super Medium") + ]); + expect(db.managers.categories.all().count(), completion(6)); + }); + + test('manager - update', () async { + // Create a row + final obj1 = await db.managers.categories.createReturning( + (o) => o(priority: Value(CategoryPriority.low), description: "Low")); + final obj2 = await db.managers.categories.createReturning((o) => + o(priority: Value(CategoryPriority.low), description: "Other Low")); + + // Replace the row + final update1 = + db.managers.categories.replace(obj1.copyWith(description: "Hello")); + expect(update1, completion(true)); + expect( + db.managers.categories + .filter(((f) => f.id(obj1.id))) + .getSingle() + .then((value) => value.description), + completion("Hello")); + + // Update All Rows + final update2 = db.managers.categories + .update((o) => o(priority: Value(CategoryPriority.high))); + expect(update2, completion(2)); + + // Update a single row + final update3 = db.managers.categories + .filter(((f) => f.id(obj2.id))) + .update((o) => o(description: Value("World"))); + expect(update3, completion(1)); + expect( + db.managers.categories + .filter(((f) => f.id(obj2.id))) + .getSingle() + .then((value) => value.description), + completion("World")); + }); + + test('manager - delete', () async { + // Create a row + final obj1 = await db.managers.categories.createReturning( + (o) => o(priority: Value(CategoryPriority.low), description: "Low")); + // ignore: unused_local_variable + final obj2 = await db.managers.categories.createReturning((o) => + o(priority: Value(CategoryPriority.low), description: "Other Low")); + + // Delete a single row + final delete1 = + db.managers.categories.filter(((f) => f.id(obj1.id))).delete(); + expect(delete1, completion(1)); + expect(db.managers.categories.all().count(), completion(1)); + + // Delete all rows + final delete2 = db.managers.categories.delete(); + expect(delete2, completion(1)); + expect(db.managers.categories.all().count(), completion(0)); + }); +}