Fix crash when using a no-op transaction (#361)

This commit is contained in:
Simon Binder 2020-01-29 22:03:29 +01:00
parent 4df07359f3
commit 01326deb7b
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
7 changed files with 39 additions and 6 deletions

View File

@ -52,4 +52,9 @@ void transactionTests(TestExecutor executor) {
await db.close();
});
test('can use no-op transactions', () async {
final db = Database(executor.createExecutor());
await db.transaction(() => Future.value(null));
});
}

View File

@ -5,6 +5,7 @@
has been updated to explain how to use them.
- Support table-valued functions (like `json_each` and `json_tree`) in moor files
[#260](https://github.com/simolus3/moor/issues/260).
- Fix a crash when opening a transaction without using it ([#361](https://github.com/simolus3/moor/issues/361))
## 2.3.0

View File

@ -26,7 +26,7 @@ mixin QueryEngine on DatabaseConnectionUser {
/// Here, the `update` method would be called on the [GeneratedDatabase]
/// although it is very likely that the user meant to call it on the
/// [Transaction] t. We can detect this by calling the function passed to
/// `transaction` in a forked [Zone] storing the transaction in
/// `transaction` in a forked [Zone].
@protected
bool get topLevel => false;

View File

@ -104,9 +104,17 @@ class BatchedStatement {
abstract class TransactionExecutor extends QueryExecutor {
/// Completes the transaction. No further queries may be sent to to this
/// [QueryExecutor] after this method was called.
///
/// This may be called before [ensureOpen] was awaited, implementations must
/// support this. That state implies that no query was sent, so it should be
/// a no-op.
Future<void> send();
/// Cancels this transaction. No further queries may be sent ot this
/// [QueryExecutor] after this method was called.
///
/// This may be called before [ensureOpen] was awaited, implementations must
/// support this. That state implies that no query was sent, so it should be
/// a no-op.
Future<void> rollback();
}

View File

@ -176,6 +176,9 @@ class _TransactionExecutor extends TransactionExecutor
@override
Future<void> send() async {
// don't do anything if the transaction completes before it was opened
if (_openingCompleter == null) return;
if (_sendOnCommit != null) {
await runCustom(_sendOnCommit, const []);
_db.delegate.isInTransaction = false;
@ -186,6 +189,9 @@ class _TransactionExecutor extends TransactionExecutor
@override
Future<void> rollback() async {
// don't do anything if the transaction completes before it was opened
if (_openingCompleter == null) return;
if (_sendOnRollback != null) {
await runCustom(_sendOnRollback, const []);
_db.delegate.isInTransaction = false;

View File

@ -158,13 +158,19 @@ class _TransactionIsolateExecutor extends _BaseExecutor
}
@override
Future<void> rollback() {
return _sendAction(_TransactionControl.rollback);
Future<void> rollback() async {
// don't do anything if the transaction isn't open yet
if (_pendingOpen == null) return;
return await _sendAction(_TransactionControl.rollback);
}
@override
Future<void> send() {
return _sendAction(_TransactionControl.commit);
Future<void> send() async {
// don't do anything if the transaction isn't open yet
if (_pendingOpen == null) return;
return await _sendAction(_TransactionControl.commit);
}
}

View File

@ -114,7 +114,14 @@ void _runTests(
expect(result, isNotEmpty);
});
test('transactions have an isolate view on data', () async {
test('supports no-op transactions', () async {
final database = TodoDb.connect(isolateConnection);
await database.transaction(() {
return Future.value(null);
});
});
test('transactions have an isolated view on data', () async {
// regression test for https://github.com/simolus3/moor/issues/324
final db = TodoDb.connect(isolateConnection);