write method
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;
}