crdts
Version:
A library of Conflict-Free Replicated Data Types for JavaScript.
65 lines (52 loc) • 1.52 kB
JavaScript
import { deepEqual } from './utils.js'
const sum = (acc, val) => acc + val
/**
* G-Counter
*
* Operation-based Increment-Only Counter CRDT
*
* Sources:
* "A comprehensive study of Convergent and Commutative Replicated Data Types"
* http://hal.upmc.fr/inria-00555588/document, "3.1.1 Op-based counter and 3.1.2 State-based increment-only Counter (G-Counter)"
*/
export default class GCounter {
constructor (id, counter) {
this.id = id
this._counters = counter ? counter : {}
this._counters[this.id] = this._counters[this.id] ? this._counters[this.id] : 0
}
get value () {
return Object.values(this._counters).reduce(sum, 0)
}
increment (amount) {
if (amount && amount < 1)
return
if (amount === undefined || amount === null)
amount = 1
this._counters[this.id] = this._counters[this.id] + amount
}
merge (other) {
// Go through each counter in the other counter
Object.entries(other._counters).forEach(([id, value]) => {
// Take the maximum of the counter value we have or the counter value they have
this._counters[id] = Math.max(this._counters[id] || 0, value)
})
}
toJSON () {
return {
id: this.id,
counters: this._counters
}
}
isEqual (other) {
return GCounter.isEqual(this, other)
}
static from (json) {
return new GCounter(json.id, json.counters)
}
static isEqual (a, b) {
if(a.id !== b.id)
return false
return deepEqual(a._counters, b._counters)
}
}