diff --git a/doc/bucket.texi b/doc/bucket.texi index 0b4a810..9a581bb 100644 --- a/doc/bucket.texi +++ b/doc/bucket.texi @@ -28,7 +28,89 @@ @node Bucket Diff @section Bucket Diff @cindex Bucket diff -@helpwanted +Changes to the bucket are represented by an array with certain conventions: + +@enumerate +@item A change to some index@tie{}@math{k} is represented by the same + index@tie{}@math{k} in the diff. +@item A value of @code{undefined} indicates that the respective index + has not changed. + Holes in the array (indexes not assigned any value) are treated in + the same manner as @code{undefined}. +@item A @code{null} in the last index of the vector marks a + truncation@tie{}point; + it is used to delete one or more indexes. + The vector will be truncated at that point. + Any preceding @code{null} values are treated as if they were + @code{undefined}.@footnote{ + The reason for this seemingly redundant (and inconvenient) choice + is that JSON encodes @code{undefined} values as @code{null}. + Consequently, when serializing a diff, @code{undefined}s are lost. + To address this, + any @code{null} that is not in the tail position is treated as + @code{undefined}. + We cannot truncate at the first null, + because @samp{[null,null,null]} may actually represent + @samp{[undefined,undefined,null]}.} +@end enumerate + +Diffs are only tracked at the vector (array of scalars) level@mdash{ + }if there is a change to a nested structure assigned to an index, + that index of the outer vector will be tracked as modified. +It will, however, recursively compare nested changes to determine if a + modification @emph{has taken place}.@footnote{ + See @srcrefjs{bucket,StagingBucket} method @code{#_parseChanges}.} +Examples appear in @ref{f:diff-ex}. + +@float Figure, f:diff-ex +@multitable @columnfractions 0.30 0.30 0.40 +@headitem Original @tab Diff @tab Interpretation +@item @samp{["foo", "bar"]} + @tab @samp{["baz", "quux"]} + @tab Index@tie{}0 changed to @samp{baz}. + Index@tie{}1 changed to @samp{quux}. + +@item @samp{["foo", "bar"]} + @tab @samp{[undefined, "quux"]} + @tab Index@tie{}0 did not change. + Index@tie{}1 changed to @samp{quux}. + +@item @samp{["foo", "bar"]} + @tab @samp{[, "quux"]} + @tab Index@tie{}0 did not change. + Index@tie{}1 changed to @samp{quux}. + +@item @samp{["foo", "bar"]} + @tab @samp{["baz", null]} + @tab Index@tie{}0 changed to @samp{baz}. + Index@tie{}1 was removed. + +@item @samp{["foo", "bar", "baz"]} + @tab @samp{[undefined, null]} + @tab Index@tie{}0 was not changed. + Index@tie{}1 was removed. + Index@tie{}2 was removed. + +@item @samp{["foo", "bar", "baz"]} + @tab @samp{[null, undefined, null]} + @tab Index@tie{}0 was not changed. + Index@tie{}1 was not changed. + Index@tie{}2 was removed. + +@item @samp{["foo", "bar", "baz"]} + @tab @samp{[null, null, null]} + @tab Index@tie{}0 was not changed. + Index@tie{}1 was not changed. + Index@tie{}2 was removed. +@end multitable +@caption{Bucket diff examples.} +@end float + +Diffs are generated by @srcrefjs{bucket,StagingBucket}. +@code{null} truncation is understood both by @code{StagingBucket} + and by @srcrefjs{bucket,QuoteDataBucket}. +A diff is applied to the underlying bucket by invoking + @code{StagingBucket#commit}. @node Calculated Values