diffTTCRDT function

TTGraphData? diffTTCRDT(
  1. TTGraphData updatedGraph,
  2. TTGraphData existingGraph, {
  3. CrdtOption? opts,
})

Implementation

TTGraphData? diffTTCRDT(TTGraphData updatedGraph, TTGraphData existingGraph,
    {CrdtOption? opts}) {
  opts ??= CrdtOption(lexical: jsonEncode, futureGrace: 10 * 60 * 1000);

  var machineState = DateTime.now().millisecondsSinceEpoch,
      futureGrace = opts.futureGrace,
      lexical = opts.lexical!;

  final maxState = machineState + futureGrace!;

  final TTGraphData allUpdates = TTGraphData();

  for (final soul in updatedGraph.entries) {
    final TTNode? existing = existingGraph[soul.key];
    final TTNode? updated = soul.value;

    final TTNodeState existingState =
        existing?.nodeMetaData?.forward ?? TTNodeState();
    final TTNodeState updatedState =
        updated?.nodeMetaData?.forward ?? TTNodeState();

    if (updated == null) {
      if (existing == null) {
        allUpdates[soul.key] = updated;
      }
      continue;
    }

    var hasUpdates = false;

    final TTNode updates =
        TTNode(nodeMetaData: TTNodeMeta(key: soul.key, forward: TTNodeState()));

    for (final key in updatedState.keys) {
      final existingKeyState = existingState[key];
      final updatedKeyState = updatedState[key];

      if (updatedKeyState == null || updatedKeyState > maxState) {
        continue;
      }
      if (existingKeyState != null && existingKeyState >= updatedKeyState) {
        continue;
      }

      if (existingKeyState == updatedKeyState) {
        final existingVal = existing?[key];
        final updatedVal = updated[key];
        // This follows the original GUN conflict resolution logic
        if (lexical(updatedVal) <= lexical(existingVal)) {
          continue;
        }
      }

      updates[key] = updated[key];
      updates.nodeMetaData?.forward![key] = updatedKeyState;
      hasUpdates = true;
    }

    if (hasUpdates) {
      allUpdates[soul.key] = updates;
    }
  }

  return allUpdates.isNotEmpty ? allUpdates : null;
}