Rollback if commit fails (#1589)

This commit is contained in:
Simon Binder 2021-12-19 19:45:20 +01:00
parent 36b23942f4
commit 41825e058e
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
5 changed files with 70 additions and 8 deletions

View File

@ -1,3 +1,7 @@
## unreleased
- Rollback transactions when a commit fails.
## 1.1.0
- Add the `references` method to `BuildColumn` to reference a column declared

View File

@ -434,8 +434,13 @@ abstract class DatabaseConnectionUser {
rethrow;
} finally {
if (success) {
// complete() will also take care of committing the transaction
try {
await transaction.complete();
} catch (e) {
// Couldn't commit -> roll back then.
await transactionExecutor.rollback();
rethrow;
}
}
await transaction.disposeChildStreams();
}

View File

@ -13,12 +13,8 @@ class Lock {
final blockCompleted = Completer<void>();
_last = blockCompleted.future;
Future<T> callBlockAndComplete() async {
try {
return await block();
} finally {
blockCompleted.complete();
}
Future<T> callBlockAndComplete() {
return Future.sync(block).whenComplete(blockCompleted.complete);
}
if (previous != null) {

View File

@ -0,0 +1,53 @@
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:test/test.dart';
void main() {
test('a failing commit does not block the whole database', () async {
final db = _Database(NativeDatabase.memory());
addTearDown(db.close);
await db.customStatement('''
CREATE TABLE IF NOT EXISTS todo_items (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL, content TEXT NULL,
category_id INTEGER NOT NULL
REFERENCES todo_categories (id) DEFERRABLE INITIALLY DEFERRED,
generated_text TEXT NULL
GENERATED ALWAYS AS (title || ' (' || content || ')') VIRTUAL
);
''');
await db.customStatement('''
CREATE TABLE IF NOT EXISTS todo_categories (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL
);
''');
await db.customStatement('PRAGMA foreign_keys = ON;');
await expectLater(
db.transaction(() async {
// Thanks to the deferrable clause, this statement will only cause a
// failing COMMIT.
await db.customStatement(
'INSERT INTO todo_items (title, category_id) VALUES (?, ?);',
['a', 100]);
}),
throwsA(isA<SqliteException>()),
);
expect(
db.customSelect('SELECT * FROM todo_items').get(), completion(isEmpty));
});
}
class _Database extends GeneratedDatabase {
_Database(QueryExecutor executor)
: super(SqlTypeSystem.defaultInstance, executor);
@override
Iterable<TableInfo<Table, dynamic>> get allTables => const Iterable.empty();
@override
int get schemaVersion => 1;
}

View File

@ -1,3 +1,7 @@
## unreleased
- Improve error handling around custom row classes.
## 1.1.0
- Consider `drift`-named files when generating schema migrations ([#1486](https://github.com/simolus3/moor/issues/1486))