chore(quark): sync vendored quark with diff gating and codegen
This commit is contained in:
parent
a653744d78
commit
77dcae0968
4 changed files with 617 additions and 334 deletions
|
|
@ -61,9 +61,12 @@ export namespace Keyed {
|
||||||
if (publish(slot, value)) changed = true
|
if (publish(slot, value)) changed = true
|
||||||
return slot
|
return slot
|
||||||
})
|
})
|
||||||
byKey.forEach((_slot, key) => {
|
// After reconciliation byKey is a superset of retained; equal sizes
|
||||||
if (!retained.has(key)) byKey.delete(key)
|
// mean no stale keys and the sweep can be skipped.
|
||||||
})
|
if (byKey.size !== retained.size)
|
||||||
|
byKey.forEach((_slot, key) => {
|
||||||
|
if (!retained.has(key)) byKey.delete(key)
|
||||||
|
})
|
||||||
if (!same(previous, reconciled)) {
|
if (!same(previous, reconciled)) {
|
||||||
slots.set(reconciled)
|
slots.set(reconciled)
|
||||||
if (options.metrics) options.metrics.structuralPublications++
|
if (options.metrics) options.metrics.structuralPublications++
|
||||||
|
|
@ -73,14 +76,13 @@ export namespace Keyed {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
update(value) {
|
update(value) {
|
||||||
const key = options.key(value)
|
const slot = byKey.get(options.key(value))
|
||||||
const slot = byKey.get(key)
|
if (!slot) return false
|
||||||
if (!slot) throw new Error(`Keyed value does not exist: ${String(key)}`)
|
|
||||||
return publish(slot, value)
|
return publish(slot, value)
|
||||||
},
|
},
|
||||||
modify(key, f) {
|
modify(key, f) {
|
||||||
const slot = byKey.get(key)
|
const slot = byKey.get(key)
|
||||||
if (!slot) throw new Error(`Keyed value does not exist: ${String(key)}`)
|
if (!slot) return false
|
||||||
const value = f(slot())
|
const value = f(slot())
|
||||||
if (byKey.get(options.key(value)) !== slot) throw new Error("Keyed modify must preserve the value key")
|
if (byKey.get(options.key(value)) !== slot) throw new Error("Keyed modify must preserve the value key")
|
||||||
return publish(slot, value)
|
return publish(slot, value)
|
||||||
|
|
@ -91,32 +93,33 @@ export namespace Keyed {
|
||||||
const current = slots()
|
const current = slots()
|
||||||
const index = positionIndex(current, position)
|
const index = positionIndex(current, position)
|
||||||
const slot = State.make(value)
|
const slot = State.make(value)
|
||||||
Transaction.run(() => {
|
// byKey is not reactive and slots.set is a single publication, so no
|
||||||
byKey.set(key, slot)
|
// transaction is required here; callers batch when they need to.
|
||||||
slots.set(current.toSpliced(index, 0, slot))
|
byKey.set(key, slot)
|
||||||
if (options.metrics) options.metrics.structuralPublications++
|
slots.set(current.toSpliced(index, 0, slot))
|
||||||
})
|
if (options.metrics) options.metrics.structuralPublications++
|
||||||
return slot
|
return slot
|
||||||
},
|
},
|
||||||
remove(key) {
|
remove(key) {
|
||||||
const slot = byKey.get(key)
|
const slot = byKey.get(key)
|
||||||
if (!slot) return false
|
if (!slot) return false
|
||||||
Transaction.run(() => {
|
byKey.delete(key)
|
||||||
byKey.delete(key)
|
slots.set(slots().filter((candidate) => candidate !== slot))
|
||||||
slots.set(slots().filter((candidate) => candidate !== slot))
|
if (options.metrics) options.metrics.structuralPublications++
|
||||||
if (options.metrics) options.metrics.structuralPublications++
|
|
||||||
})
|
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
move(key, position) {
|
move(key, position) {
|
||||||
const slot = byKey.get(key)
|
const slot = byKey.get(key)
|
||||||
if (!slot) throw new Error(`Keyed value does not exist: ${String(key)}`)
|
if (!slot) return false
|
||||||
const current = slots()
|
const current = slots()
|
||||||
const from = current.indexOf(slot)
|
const from = current.indexOf(slot)
|
||||||
const target = positionIndex(current, position)
|
const target = positionIndex(current, position)
|
||||||
const to = from < target ? target - 1 : target
|
const to = from < target ? target - 1 : target
|
||||||
if (from === to) return false
|
if (from === to) return false
|
||||||
slots.set(current.toSpliced(from, 1).toSpliced(to, 0, slot))
|
const next = current.slice()
|
||||||
|
next.splice(from, 1)
|
||||||
|
next.splice(to, 0, slot)
|
||||||
|
slots.set(next)
|
||||||
if (options.metrics) options.metrics.structuralPublications++
|
if (options.metrics) options.metrics.structuralPublications++
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|
@ -129,7 +132,8 @@ export namespace Keyed {
|
||||||
}
|
}
|
||||||
|
|
||||||
function publish(slot: Writable<A>, value: A) {
|
function publish(slot: Writable<A>, value: A) {
|
||||||
if (equivalent(slot(), value)) {
|
const current = slot()
|
||||||
|
if (current === value || equivalent(current, value)) {
|
||||||
if (options.metrics) options.metrics.equivalenceSuppressions++
|
if (options.metrics) options.metrics.equivalenceSuppressions++
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +156,7 @@ export namespace Keyed {
|
||||||
|
|
||||||
function neighbor(key: Key, offset: -1 | 1) {
|
function neighbor(key: Key, offset: -1 | 1) {
|
||||||
const slot = byKey.get(key)
|
const slot = byKey.get(key)
|
||||||
if (!slot) throw new Error(`Keyed value does not exist: ${String(key)}`)
|
if (!slot) return undefined
|
||||||
const current = slots()
|
const current = slots()
|
||||||
return current[current.indexOf(slot) + offset]
|
return current[current.indexOf(slot) + offset]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -32,7 +32,14 @@ export namespace State {
|
||||||
const state = signal(initial)
|
const state = signal(initial)
|
||||||
const read = (() => state()) as Writable<A>
|
const read = (() => state()) as Writable<A>
|
||||||
read.set = (value) => state(value)
|
read.set = (value) => state(value)
|
||||||
read.update = (f) => state(f(state()))
|
read.update = (f) => {
|
||||||
|
// Read untracked: calling update inside an effect must not make the
|
||||||
|
// effect depend on (and re-trigger from) this signal.
|
||||||
|
const active = setActiveSub()
|
||||||
|
const current = state()
|
||||||
|
setActiveSub(active)
|
||||||
|
state(f(current))
|
||||||
|
}
|
||||||
read.subscribe = (listener) => subscribe(read, listener)
|
read.subscribe = (listener) => subscribe(read, listener)
|
||||||
return read
|
return read
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ describe("Keyed", () => {
|
||||||
expect(keyed.slots()[1]).toBe(two)
|
expect(keyed.slots()[1]).toBe(two)
|
||||||
expect(two()).toEqual(item(2, "TWO"))
|
expect(two()).toEqual(item(2, "TWO"))
|
||||||
expect(structures).toEqual([])
|
expect(structures).toEqual([])
|
||||||
expect(() => keyed.update(item(3, "three"))).toThrow("Keyed value does not exist: 3")
|
expect(keyed.update(item(3, "three"))).toBe(false)
|
||||||
dispose()
|
dispose()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -142,7 +142,7 @@ describe("Keyed", () => {
|
||||||
expect(keyed.slots()[0]).toBe(slot)
|
expect(keyed.slots()[0]).toBe(slot)
|
||||||
expect(slot()).toEqual(item(1, "ONE"))
|
expect(slot()).toEqual(item(1, "ONE"))
|
||||||
expect(() => keyed.modify(1, (value) => ({ ...value, id: 2 }))).toThrow("Keyed modify must preserve the value key")
|
expect(() => keyed.modify(1, (value) => ({ ...value, id: 2 }))).toThrow("Keyed modify must preserve the value key")
|
||||||
expect(() => keyed.modify(2, (value) => value)).toThrow("Keyed value does not exist: 2")
|
expect(keyed.modify(2, (value) => value)).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("checks key membership without reading the aggregate", () => {
|
it("checks key membership without reading the aggregate", () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue