transaction method

  1. @override
Future<void> transaction(
  1. Future<void> action()
)
override

Implementation

@override
Future<void> transaction(Future<void> Function() action) async {
  // we want transactions to lock, however NOT if transactoins are run inside of each other.
  // to be able to do this, we use dart zones (https://dart.dev/articles/archive/zones).
  // _transactionZones holds a set of all zones which are currently running a transaction.
  // _transactionLock holds the lock.

  // first we try to determine if we are inside of a transaction currently
  var isInTransaction = false;
  Zone? zone = Zone.current;
  // for that we keep on iterating to the parent zone until there is either no zone anymore
  // or we have found a zone inside of _transactionZones.
  while (zone != null) {
    if (_transactionZones.contains(zone)) {
      isInTransaction = true;
      break;
    }
    zone = zone.parent;
  }
  // if we are inside a transaction....just run the action
  if (isInTransaction) {
    return await action();
  }
  // if we are *not* in a transaction, time to wait for the lock!
  while (_transactionLock != null) {
    await _transactionLock!.future;
  }
  // claim the lock
  final lock = Completer<void>();
  _transactionLock = lock;
  try {
    // run the action inside of a new zone
    return await runZoned(() async {
      try {
        // don't forget to add the new zone to _transactionZones!
        _transactionZones.add(Zone.current);
        return await action();
      } finally {
        // aaaand remove the zone from _transactionZones again
        _transactionZones.remove(Zone.current);
      }
    });
  } finally {
    // aaaand finally release the lock
    _transactionLock = null;
    lock.complete();
  }
}