crdts
Version:
A library of Conflict-Free Replicated Data Types for JavaScript.
96 lines (88 loc) • 2.67 kB
JavaScript
import CRDTSet from './CmRDT-Set.js'
import GSet from './G-Set.js'
/**
* 2P-Set
*
* Operation-based Two-Phase Set CRDT
*
* See base class CmRDT-Set.js for the rest of the API
* https://github.com/orbitdb/crdts/blob/master/src/CmRDT-Set.js
*
* Sources:
* "A comprehensive study of Convergent and Commutative Replicated Data Types"
* http://hal.upmc.fr/inria-00555588/document, "3.3.2 2P-Set"
*/
export default class TwoPSet extends CRDTSet {
/**
* Create a new TwoPSet instance
* @param {[Iterable]} added [Added values]
* @param {[Iterable]} removed [Removed values]
*/
constructor (added, removed) {
super()
// We track the operations and state differently
// than the base class: use two GSets for operations
this._added = new GSet(added)
this._removed = new GSet(removed)
}
/**
* Return all values added to the Set
* @override
* @return {[Iterator]} [Iterator for values in the Set]
*/
values () {
// A value is included in the set if it's present in
// the add set and not present in the remove set. We can
// determine this by calculating the difference between
// adds and removes.
const difference = GSet.difference(this._added, this._removed)
return difference.values()
}
/**
* Add a value to the Set
* @param {[Any]} value [Value to add to the Set]
*/
add (element) {
this._added.add(element)
}
/**
* Remove a value from the Set
* @override
* @param {[Any]} element [Value to remove from the Set]
*/
remove (element) {
// Only add the value to the remove set if it exists in the add set
if (this._added.has(element)) {
this._removed.add(element)
}
}
/**
* Merge the Set with another Set
* @override
* @param {[TwoPSet]} other [Set to merge with]
*/
merge (other) {
this._added = new GSet(this._added.toArray().concat(other._added.toArray()))
this._removed = new GSet(this._removed.toArray().concat(other._removed.toArray()))
}
/**
* TwoPSet as an Object that can be JSON.stringified
* @return {[Object]} [Object in the shape of `{ values: { added: [<values>], removed: [<values>] } }`]
*/
toJSON () {
return {
values: {
added: this._added.toArray(),
removed: this._removed.toArray(),
},
}
}
/**
* Create TwoPSet from a json object
* @param {[Object]} json [Input object to create the GSet from. Needs to be: '{ values: { added: [...], removed: [...] } }']
* @return {[TwoPSet]} [new TwoPSet instance]
*/
static from (json) {
return new TwoPSet(json.values.added, json.values.removed)
}
}