function viewProcessorGenerateEventCacheAfterServerEvent()

in packages/database/src/core/view/ViewProcessor.ts [220:345]


function viewProcessorGenerateEventCacheAfterServerEvent(
  viewProcessor: ViewProcessor,
  viewCache: ViewCache,
  changePath: Path,
  writesCache: WriteTreeRef,
  source: CompleteChildSource,
  accumulator: ChildChangeAccumulator
): ViewCache {
  const oldEventSnap = viewCache.eventCache;
  if (writeTreeRefShadowingWrite(writesCache, changePath) != null) {
    // we have a shadowing write, ignore changes
    return viewCache;
  } else {
    let newEventCache, serverNode;
    if (pathIsEmpty(changePath)) {
      // TODO: figure out how this plays with "sliding ack windows"
      assert(
        viewCache.serverCache.isFullyInitialized(),
        'If change path is empty, we must have complete server data'
      );
      if (viewCache.serverCache.isFiltered()) {
        // We need to special case this, because we need to only apply writes to complete children, or
        // we might end up raising events for incomplete children. If the server data is filtered deep
        // writes cannot be guaranteed to be complete
        const serverCache = viewCacheGetCompleteServerSnap(viewCache);
        const completeChildren =
          serverCache instanceof ChildrenNode
            ? serverCache
            : ChildrenNode.EMPTY_NODE;
        const completeEventChildren = writeTreeRefCalcCompleteEventChildren(
          writesCache,
          completeChildren
        );
        newEventCache = viewProcessor.filter.updateFullNode(
          viewCache.eventCache.getNode(),
          completeEventChildren,
          accumulator
        );
      } else {
        const completeNode = writeTreeRefCalcCompleteEventCache(
          writesCache,
          viewCacheGetCompleteServerSnap(viewCache)
        );
        newEventCache = viewProcessor.filter.updateFullNode(
          viewCache.eventCache.getNode(),
          completeNode,
          accumulator
        );
      }
    } else {
      const childKey = pathGetFront(changePath);
      if (childKey === '.priority') {
        assert(
          pathGetLength(changePath) === 1,
          "Can't have a priority with additional path components"
        );
        const oldEventNode = oldEventSnap.getNode();
        serverNode = viewCache.serverCache.getNode();
        // we might have overwrites for this priority
        const updatedPriority = writeTreeRefCalcEventCacheAfterServerOverwrite(
          writesCache,
          changePath,
          oldEventNode,
          serverNode
        );
        if (updatedPriority != null) {
          newEventCache = viewProcessor.filter.updatePriority(
            oldEventNode,
            updatedPriority
          );
        } else {
          // priority didn't change, keep old node
          newEventCache = oldEventSnap.getNode();
        }
      } else {
        const childChangePath = pathPopFront(changePath);
        // update child
        let newEventChild;
        if (oldEventSnap.isCompleteForChild(childKey)) {
          serverNode = viewCache.serverCache.getNode();
          const eventChildUpdate =
            writeTreeRefCalcEventCacheAfterServerOverwrite(
              writesCache,
              changePath,
              oldEventSnap.getNode(),
              serverNode
            );
          if (eventChildUpdate != null) {
            newEventChild = oldEventSnap
              .getNode()
              .getImmediateChild(childKey)
              .updateChild(childChangePath, eventChildUpdate);
          } else {
            // Nothing changed, just keep the old child
            newEventChild = oldEventSnap.getNode().getImmediateChild(childKey);
          }
        } else {
          newEventChild = writeTreeRefCalcCompleteChild(
            writesCache,
            childKey,
            viewCache.serverCache
          );
        }
        if (newEventChild != null) {
          newEventCache = viewProcessor.filter.updateChild(
            oldEventSnap.getNode(),
            childKey,
            newEventChild,
            childChangePath,
            source,
            accumulator
          );
        } else {
          // no complete child available or no change
          newEventCache = oldEventSnap.getNode();
        }
      }
    }
    return viewCacheUpdateEventSnap(
      viewCache,
      newEventCache,
      oldEventSnap.isFullyInitialized() || pathIsEmpty(changePath),
      viewProcessor.filter.filtersNodes()
    );
  }
}