write method

  1. @override
Set<String> write(
  1. String operation,
  2. List<Object> path,
  3. Object? value
)

Writes an optimistic/manual value at a path, creating containers as needed. Returns the dependency keys touched.

Implementation

@override
Set<String> write(String operation, List<Object> path, Object? value) {
  final touched = <String>{};
  if (path.isEmpty) return touched;

  var start = 0;
  String entityKey;
  if (path.first is Ref) {
    entityKey = (path.first as Ref).key;
    start = 1;
  } else {
    entityKey = rootKey(operation);
  }
  if (start >= path.length) return touched;

  Object? container = _entities.putIfAbsent(entityKey, () => {});
  String? topField;
  // The list [topField] held before this write (and its length then), and
  // the index of it the path goes through: which list keys to touch.
  List<Object?>? topList;
  var topLength = 0;
  int? topIndex;
  for (var i = start; i < path.length - 1; i++) {
    final key = path[i];
    final next = path[i + 1];
    if (container is Ref) {
      entityKey = container.key;
      container = _entities.putIfAbsent(entityKey, () => {});
      topField = null;
      topList = null;
      topIndex = null;
    }
    if (key is String) {
      final map = container as Map<String, Object?>;
      if (topField == null) {
        topField = key;
        final held = map[key];
        if (held is List<Object?>) {
          topList = held;
          topLength = held.length;
        }
      }
      container = map[key] ??= next is int
          ? <Object?>[]
          : <String, Object?>{};
    } else {
      final list = container as List<Object?>;
      final index = key as int;
      if (identical(list, topList)) topIndex = index;
      while (list.length <= index) {
        list.add(null);
      }
      container = list[index] ??= next is int
          ? <Object?>[]
          : <String, Object?>{};
    }
  }
  if (container is Ref) {
    entityKey = container.key;
    container = _entities.putIfAbsent(entityKey, () => {});
    topField = null;
    topList = null;
    topIndex = null;
  }

  final last = path.last;
  if (last is String) {
    final map = container as Map<String, Object?>;
    final previous = map[last];
    if (topField != null) {
      map[last] = _normalize(previous, value, touched);
    } else {
      // A field of the entity itself.
      topField = last;
      if (previous is List<Object?> && value is List<Object?>) {
        map[last] = _mergeList(entityKey, last, previous, value, touched);
      } else {
        if (previous is List<Object?>) {
          _touchList(entityKey, last, previous, 0, touched);
        }
        map[last] = _normalize(previous, value, touched);
      }
    }
  } else {
    final list = container as List<Object?>;
    final index = last as int;
    while (list.length <= index) {
      list.add(null);
    }
    final previous = list[index];
    list[index] = _normalize(previous, value, touched);
    if (identical(list, topList)) {
      // Readers of a ref element depend on the whole field.
      topIndex = previous is Ref ? null : index;
    }
  }
  if (topField != null) touched.add(depKey(entityKey, topField));
  if (topList != null) {
    final keys = _listDeps(entityKey, topField!);
    if (topList.length != topLength) touched.add(keys.length);
    if (topIndex != null && topIndex < topLength) {
      touched.add(keys.element(topIndex));
    }
  }
  _markChanged(entityKey);
  _emit(touched);
  return touched;
}