- /*
- * The user has issued an empty merge operation. In this case we do not perform
- * a data tree mutation, do not pass GO, and do not collect useless garbage.
- */
- final Collection<ModifiedNode> children = modification.getChildren();
- if (children.isEmpty()) {
- modification.resolveModificationType(ModificationType.UNMODIFIED);
- newMeta.setData(currentMeta.getData());
- return newMeta.seal();
+ switch (modification.getOperation()) {
+ case NONE:
+ // Fresh node, just record a MERGE with a value
+ recursivelyVerifyStructure(value);
+ modification.updateValue(LogicalOperation.MERGE, value);
+ return;
+ case TOUCH:
+
+ mergeChildrenIntoModification(modification, children, version);
+ // We record empty merge value, since real children merges
+ // are already expanded. This is needed to satisfy non-null for merge
+ // original merge value can not be used since it mean different
+ // order of operation - parent changes are always resolved before
+ // children ones, and having node in TOUCH means children was modified
+ // before.
+ modification.updateValue(LogicalOperation.MERGE, createEmptyValue(value));
+ return;
+ case MERGE:
+ // Merging into an existing node. Merge data children modifications (maybe recursively) and mark as MERGE,
+ // invalidating cached snapshot
+ mergeChildrenIntoModification(modification, children, version);
+ modification.updateOperationType(LogicalOperation.MERGE);
+ return;
+ case DELETE:
+ // Delete performs a data dependency check on existence of the node. Performing a merge on DELETE means we
+ // are really performing a write. One thing that ruins that are any child modifications. If there are any,
+ // we will perform a read() to get the current state of affairs, turn this into into a WRITE and then
+ // append any child entries.
+ if (!modification.getChildren().isEmpty()) {
+ // Version does not matter here as we'll throw it out
+ final Optional<TreeNode> current = apply(modification, modification.getOriginal(), Version.initial());
+ if (current.isPresent()) {
+ modification.updateValue(LogicalOperation.WRITE, current.get().getData());
+ mergeChildrenIntoModification(modification, children, version);
+ return;
+ }
+ }
+
+ modification.updateValue(LogicalOperation.WRITE, value);
+ return;
+ case WRITE:
+ // We are augmenting a previous write. We'll just walk value's children, get the corresponding ModifiedNode
+ // and run recursively on it
+ mergeChildrenIntoModification(modification, children, version);
+ modification.updateOperationType(LogicalOperation.WRITE);
+ return;