runTransaction<T> method

  1. @override
Future<T> runTransaction<T>(
  1. Future<T> delegate(
    1. DatabaseContext context
    )
)
override

Runs delegate inside a transaction.

If delegate returns without throwing an exception, the transaction is committed and the return value is passed through as return value of this method.

If delegate throws an exception, the transaction is rolled back and the exception is rethrown.

Implementation

@override
Future<T> runTransaction<T>(
    Future<T> Function(DatabaseContext context) delegate) async {
  if (Zone.current[#postgresTransactionConnection] == _connection &&
      Zone.current[#postgresTransactionContext] != null) {
    final context = await (Zone.current[#postgresTransactionContext]
            as Completer<DatabaseContext>)
        .future;
    return await delegate(context);
  }

  final completer = Completer<_Box<T>>();
  final contextCompleter = Completer<DatabaseContext>();
  runZonedGuarded(() {
    _connection
        .transaction((c) async {
          final context = PostgreSQLDatabaseContext(
              adapter as PostgreSQLDatabaseAdapter, c);
          contextCompleter.complete(context);
          return await delegate(context);
        })
        .then((r) => completer.complete(_Box<T>.value(r)))
        .catchError(
            (e, stack) => completer.complete(_Box<T>.error(e, stack)));
  }, (error, stack) {
    resolve<LogService?>()?.warn(
      'Unhandled error in postgres package.',
      error: error,
      trace: stack,
    );
  }, zoneValues: {
    #postgresTransactionConnection: _connection,
    #postgresTransactionContext: contextCompleter
  });
  return await (await completer.future).value;
}