diff --git a/moor/lib/src/utils/synchronized.dart b/moor/lib/src/utils/synchronized.dart index b4e52d52..aebe8b6b 100644 --- a/moor/lib/src/utils/synchronized.dart +++ b/moor/lib/src/utils/synchronized.dart @@ -8,11 +8,13 @@ class Lock { /// then calls [block] before further [synchronized] calls are allowed. Future synchronized(FutureOr Function() block) { final previous = _last; - // We can use synchronous futures for _last since we always complete through - // callBlockAndComplete(), which is asynchronous. - final blockCompleted = Completer.sync(); + // This controller may not be sync: It must complete just after + // callBlockAndComplete completes. + final blockCompleted = Completer(); _last = blockCompleted.future; + // Note: We can't use async/await here because this future must complete + // just before the blockCompleted completer. Future callBlockAndComplete() async { try { return await block(); diff --git a/moor/test/integration_tests/regress_1232_test.dart b/moor/test/integration_tests/regress_1232_test.dart new file mode 100644 index 00000000..6702e0f4 --- /dev/null +++ b/moor/test/integration_tests/regress_1232_test.dart @@ -0,0 +1,32 @@ +@TestOn('vm') +import 'package:moor/ffi.dart'; +import 'package:moor/moor.dart'; +import 'package:test/test.dart'; + +import '../data/tables/todos.dart'; + +void main() { + test('regression test for #1232', () async { + // replace with generated table + final db = TodoDb(VmDatabase.memory()); + final someTables = {db.todosTable}; + + await db.customStatement('create table tbl (x int)'); + await db.customInsert('insert into tbl values(1)'); + + Stream watchValue() => db + .customSelect('select * from tbl', readsFrom: someTables) + .map((row) => row.read('x')) + .watchSingle(); + + expect(await watchValue().first, 1); + await Future.delayed(Duration.zero); + + watchValue().listen(null); + + await db.customUpdate('update tbl set x = 2', + updates: someTables, updateKind: UpdateKind.update); + + expect(await watchValue().first, 2); + }); +} diff --git a/moor/test/utils/synchronized_test.dart b/moor/test/utils/synchronized_test.dart index 74c90663..531fdd01 100644 --- a/moor/test/utils/synchronized_test.dart +++ b/moor/test/utils/synchronized_test.dart @@ -5,9 +5,14 @@ void main() { test('synchronized runs code in sequence', () async { final lock = Lock(); var i = 0; - final futures = List.generate(100, (index) => lock.synchronized(() => i++)); + final completionOrder = []; + final futures = List.generate( + 100, + (index) => lock.synchronized(() => i++) + ..whenComplete(() => completionOrder.add(index))); final results = await Future.wait(futures); expect(results, List.generate(100, (index) => index)); + expect(completionOrder, List.generate(100, (index) => index)); }); }