runTransaction method

Future<TransactionResult?>? runTransaction(
  1. TransactionHandler? transactionHandler, {
  2. Duration? timeout = const Duration(seconds: 5),
})

Performs an optimistic-concurrency transactional update to the data at this Firebase Database location.

Implementation

Future<TransactionResult> runTransaction(
    TransactionHandler transactionHandler,
    {Duration timeout = const Duration(seconds: 5)}) async {
  assert(timeout.inMilliseconds > 0,
      'Transaction timeout must be more than 0 milliseconds.');

  final Completer<TransactionResult> completer =
      Completer<TransactionResult>();

  final int transactionKey = FirebaseDatabase._transactions.isEmpty
      ? 0
      : FirebaseDatabase._transactions.keys.last + 1;

  FirebaseDatabase._transactions[transactionKey] = transactionHandler;

  TransactionResult toTransactionResult(Map<dynamic, dynamic> map) {
    final DatabaseError databaseError =
        map['error'] != null ? DatabaseError._(map['error']) : null;
    final bool committed = map['committed'];
    final DataSnapshot dataSnapshot =
        map['snapshot'] != null ? DataSnapshot._(map['snapshot']) : null;

    FirebaseDatabase._transactions.remove(transactionKey);

    return TransactionResult._(databaseError, committed, dataSnapshot);
  }

  // TODO(rrousselGit) refactor to async/await
  // TODO(rrousselGit) what if invokeMethod fails?
  // ignore: unawaited_futures
  _database._channel.invokeMethod<void>(
      'DatabaseReference#runTransaction', <String, dynamic>{
    'app': _database.app?.name,
    'databaseURL': _database.databaseURL,
    'path': path,
    'transactionKey': transactionKey,
    'transactionTimeout': timeout.inMilliseconds
  }).then((dynamic response) {
    completer.complete(toTransactionResult(response));
  });

  return completer.future;
}