Fix `computeWithDatabase` in transactions

This commit is contained in:
Simon Binder 2023-05-05 16:34:33 +02:00
parent 54f6eea205
commit 3ee1c1ccd4
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
3 changed files with 29 additions and 4 deletions

View File

@ -3,6 +3,7 @@
- Don't keep databases in an unusable state if the `setup` callback throws an
exception. Instead, drift will retry the next time the database is used.
- Allow targeting partial indices in `DoUpdate` ([#2394](https://github.com/simolus3/drift/issues/2394))
- Fix deadlocks when `computeWithDatabase` is called inside a `transaction()`.
## 2.7.0

View File

@ -221,13 +221,17 @@ extension ComputeWithDriftIsolate<DB extends DatabaseConnectionUser> on DB {
/// requiring a database is also available through [computeWithDatabase].
@experimental
Future<DriftIsolate> serializableConnection() async {
final currentlyInRootConnection = resolvedEngine is GeneratedDatabase;
// ignore: invalid_use_of_protected_member
final localConnection = connection;
final localConnection = resolvedEngine.connection;
final data = await localConnection.connectionData;
if (data is DriftIsolate) {
// The local database is already connected to an isolate, use that one
// directly.
// If we're connected to an isolate already, we can use that one directly
// instead of starting a short-lived drift server.
// However, this does not work if [serializableConnection] is called in a
// transaction zone, since the top-level connection could be blocked waiting
// for the transaction (as transactions can't be concurrent in sqlite3).
if (data is DriftIsolate && currentlyInRootConnection) {
return data;
} else {
// Set up a drift server acting as a proxy to the existing database

View File

@ -199,6 +199,26 @@ void main() {
// Make sure database still works after computeWithDatabase
// https://github.com/simolus3/drift/issues/2279#issuecomment-1455385439
await db.customSelect('SELECT 1').get();
// This should still work when computeWithDatabase is called in a
// transaction.
await db.transaction(() async {
await db.into(db.categories).insert(
CategoriesCompanion.insert(description: 'main / transaction'));
await db.computeWithDatabase(
computation: (db) async {
await db.batch((batch) {
batch.insert(
db.categories,
CategoriesCompanion.insert(description: 'nested remote batch!'),
);
});
},
connect: TodoDb.new,
);
});
await db.close();
}