changes package - github.com/dotchain/dot/changes - Go Packages (original) (raw)
Package changes implements the core mutation types for OT.
The three basic types are Replace, Splice and Move. Replace replaces a value altogether while Splice replaces a sub-sequence in an array-like object and Move shuffles a sub-sequence.
Both Slice and Move work on strings as well. The actual type for Slice and Move is represented by the Collection interface (while Replace uses a much more lax Value interface)
Seehttps://godoc.org/github.com/dotchain/dot/changes/types#S16 for an implementation of an OT-compatible string type.
Composition ¶
ChangeSet allows a set of mutations to be grouped together.
PathChange allows a mutation to refer to a "path". For example, a field in a "struct type" can be thought of as having the path of "field name". An element of a collection can be thought of as having the path of the index in that array.
The type of the elements in the path is not specified but it is assumed that they are comparable for equality. Collections are required to use the index of type int for the path elements.
Custom Changes ¶
Custom change types can be defined. They should implement the Custom interface. Seehttps://godoc.org/github.com/dotchain/dot/changes/x/rt#Run for an example custom change type.
The general asssumption underlying OT is that the Merge method produces convergence:
if: c1, c2 = changes on top of "initial" and: c1x, c2x := c1.Merge(c2) then: initial + c1 + c1x == initial + c2 + c2x
Notes ¶
Replace and Splice change both expect the Before and After fields to be non-nil Value implementations. Replace can use changes.Nil to represent empty values for the case where a value is being deleted or created. Slices must make sure that the Before and After use the "empty" representations of the respective types.
Slices also should generally make sure that the Before and After types are compatible -- i.e. each should be able to be spliced within the other.
Value Interface ¶
Any custom Value implementation should implement the Value interface. See https://godoc.org/github.com/dotchain/dot/changes/typesfor a set of custom value types such as string, arrays and counters.
See https://godoc.org/github.com/dotchain/dot/x/rt for a custom type that has a specific custom change associated with it.
It is common to have a value type (say *Node) that is meant as an atomic value. In that case, one can use the Atomic{} type to hold such values.
- Variables
- type Atomic
- type Change
- type ChangeSet
- type Collection
- type Context
- type Custom
- type Meta
- type Move
- func (m *Move) Change() Change
- func (m Move) MapIndex(idx int) int
- func (m Move) Merge(other Change) (otherx, cx Change)
- func (m Move) MergeMove(o Move) (ox []Move, mx []Move)
- func (m Move) MergeReplace(other Replace) (other1 *Replace, m1 *Splice)
- func (m Move) MergeSplice(o Splice) (Change, Change)
- func (m Move) Normalize() Move
- func (m Move) Revert() Change
- type PathChange
- type Replace
- func (s *Replace) Change() Change
- func (s Replace) IsCreate() bool
- func (s Replace) IsDelete() bool
- func (s Replace) Merge(other Change) (otherx, cx Change)
- func (s Replace) MergeMove(other Move) (other1 *Move, s1 *Replace)
- func (s Replace) MergeReplace(other Replace) (other1, s1 *Replace)
- func (s Replace) MergeSplice(other Splice) (other1 *Splice, s1 *Replace)
- func (s Replace) Revert() Change
- type Splice
- func (s *Splice) Change() Change
- func (s Splice) MapIndex(idx int) (int, bool)
- func (s Splice) Merge(other Change) (otherx, cx Change)
- func (s Splice) MergeMove(o Move) (ox, sx Change)
- func (s Splice) MergeReplace(other Replace) (other1 *Replace, s1 *Splice)
- func (s Splice) MergeSplice(other Splice) (other1, s1 *Splice)
- func (s Splice) Revert() Change
- type Value
This section is empty.
Nil represents an empty value. It can be used with Replace or Splice to indicate that Before or After is empty. The only operation that can be applied is a Replace. Count and Slice cannot be called on it.
This section is empty.
type Atomic struct { Value interface{} }
Atomic is an atomic Value. It can wrap any particular value and can be used in the Before, After fields of Replace or Splice.
func (a Atomic) Apply(ctx Context, c Change) Value
Apply only accepts one type of change: one that Replace's the value.
type Change interface {
Merge(other [Change](#Change)) (otherx, cx [Change](#Change))
Revert() [Change](#Change)}
Change represents an OT-compatible mutation
The methods provided here are the core methods. Custom changes should implement the Custom interface in addition to this. Note that it is legal for a change to be nil (meaning the value isnt change at all)
func Merge(c1, c2 Change) (c1x, c2x Change)
Merge is effectively c1.Merge(c2) except that c1 can be nil.
As with individual merge implementations, applying c1+c1x is effectively the same as applying c2+c2x.
func Simplify(c Change) Change
Simplify converts a change to a simpler form if possible
ChangeSet represents a collection of changes. It implements the Change interface thereby allowing merging groups of changes against each other.
func (c ChangeSet) ApplyTo(ctx Context, v Value) Value
ApplyTo simply walks through the individual changes and applies them to the value.
func (c ChangeSet) Merge(other Change) (otherx, cx Change)
Merge implements Change.Merge.
func (c ChangeSet) ReverseMerge(other Change) (otherx, cx Change)
ReverseMerge is like merge except with receiver and args inverted
func (c ChangeSet) Revert() Change
Revert implements Change.Revert.
func (c ChangeSet) Simplify() Change
Simplify converts an empty or single element change-set into a simpler version
type Collection interface {
[Value](#Value)
ApplyCollection(ctx [Context](#Context), c [Change](#Change)) [Collection](#Collection)
Slice(offset, count [int](/builtin#int)) [Collection](#Collection)
Count() [int](/builtin#int)}
Collection represents an immutable array-like value
type Context interface { Value(key interface{}) interface{} }
Context defines the context in which a change is being applied. This is useful to capture data such as the "current user" or "virtual time" etc. For true convergence, the context itself should be derived from the change -- say via Meta.
Note that this interface is a subset of the standard golang "context.Context"
func MetaValue(ctx Context) (v interface{}, p Context)
MetaValue fetches the meta value and the previous context associated with the current change context.
type Custom interface { Change
ReverseMerge(c [Change](#Change)) ([Change](#Change), [Change](#Change))
ApplyTo(ctx [Context](#Context), v [Value](#Value)) [Value](#Value)}
Custom is the interface that custom change types should implement. This allows the "known" types to interact with custom types.
Custom changes might also need to implement the refs.PathMerger interface (see https://godoc.org/github.com/dotchain/dot/refs)
type Meta struct { Data interface{} Change }
Meta wraps a change with some metadata that is maintained as the change is merged. This is useful for carrying contexts with changes. One example is the current user making the change
func (m Meta) ApplyTo(ctx Context, v Value) Value
ApplyTo implements Custom.ApplyTo
func (m Meta) Merge(other Change) (otherx, cx Change)
Merge merges the change preserving the meta data
func (m Meta) ReverseMerge(c Change) (Change, Change)
ReverseMerge implements Custom.ReverseMerge
Revert reverts the change preserving the meta data
type Move struct { Offset, Count, Distance int }
Move represents a shuffling of some elements (specified by Offset and Count) over to a different spot (specified by Distance, which can be negative to indicate a move over to the left).
func (m *Move) Change() Change
Change returns either nil or the underlying Move as a change.
MapIndex maps a particular index to the new location of the index after the move
func (m Move) Merge(other Change) (otherx, cx Change)
Merge implements the Change.Merge method
func (m Move) MergeMove(o Move) (ox []Move, mx []Move)
MergeMove merges a move against another Move
func (m Move) MergeReplace(other Replace) (other1 *Replace, m1 *Splice)
MergeReplace merges a move against a Replace. The replace always wins
func (m Move) MergeSplice(o Splice) (Change, Change)
MergeSplice merges a splice with a move.
func (m Move) Normalize() Move
Normalize ensures that distance is always positive
Revert reverts the move.
type PathChange struct { Path []interface{} Change }
PathChange represents a change at the provided "path" which can consist of strings (for map-like objects) and integers for array-like objects. In particular, each element of the path should be a proper comparable value (so slices and such cannot be part of th path)
func (pc PathChange) ApplyTo(ctx Context, v Value) Value
ApplyTo is not relevant to PathChange. It only works when the path is empty. In all other cases, it panics.
func (pc PathChange) Merge(o Change) (Change, Change)
Merge implements Change.Merge
func (pc PathChange) ReverseMerge(o Change) (Change, Change)
ReverseMerge implements but with receiver and arg interchanged.
func (pc PathChange) Revert() Change
Revert implements Change.Revert
func (pc PathChange) Simplify() Change
Simplify returns a simpler version of this change removing empty paths or coalescing paths as needed
type Replace struct { Before, After Value }
Replace represents create, delete and update of a value based on whether Before is Nil, After is Nil and both are non-Nil respectively.
func (s *Replace) Change() Change
Change returns either nil or a Change
func (s Replace) IsCreate() bool
IsCreate identifies if the change is a create
func (s Replace) IsDelete() bool
IsDelete identifies if the change is a delete
func (s Replace) Merge(other Change) (otherx, cx Change)
Merge implements the Change.Merge method
func (s Replace) MergeMove(other Move) (other1 *Move, s1 *Replace)
MergeMove merges against a Move change. The replace wins
func (s Replace) MergeReplace(other Replace) (other1, s1 *Replace)
MergeReplace merges against another Replace change. The last writer wins here with the receiver assumed to be the earlier change
func (s Replace) MergeSplice(other Splice) (other1 *Splice, s1 *Replace)
MergeSplice merges against a Splice change. The replace wins
func (s Replace) Revert() Change
Revert inverts the effect of the replace
type Splice struct { Offset int Before, After Collection }
Splice represents an array edit change. A set of elements from the specified offset are removed and replaced with a new set of elements.
func (s *Splice) Change() Change
Change returns nil or the underlying Splice
MapIndex maps an index to the new location of the index after the splice. It also returns whether the item at that index has been modified by the splice change.
func (s Splice) Merge(other Change) (otherx, cx Change)
Merge implements the Change.Merge method
func (s Splice) MergeMove(o Move) (ox, sx Change)
MergeMove merges a splice against a move
func (s Splice) MergeReplace(other Replace) (other1 *Replace, s1 *Splice)
MergeReplace merges a move against a Replace. The replace always wins
func (s Splice) MergeSplice(other Splice) (other1, s1 *Splice)
MergeSplice merges a splice against another Splice.
func (s Splice) Revert() Change
Revert inverts the effect of the splice.
type Value interface {
Apply(ctx [Context](#Context), c [Change](#Change)) [Value](#Value)}
Value represents an immutable JSON object that can apply changes. Array like values should also implement Collection