eventstore: SortedMerge() helper for combining results from different eventstores.

This commit is contained in:
fiatjaf
2025-10-30 11:42:04 -03:00
parent e34ce6aa94
commit 20f06d9608
2 changed files with 113 additions and 0 deletions

61
eventstore/combine.go Normal file
View File

@@ -0,0 +1,61 @@
package eventstore
import (
"iter"
"fiatjaf.com/nostr"
)
func SortedMerge(it1, it2 iter.Seq[nostr.Event]) iter.Seq[nostr.Event] {
next1, done1 := iter.Pull(it1)
next2, done2 := iter.Pull(it2)
return func(yield func(nostr.Event) bool) {
defer done1()
defer done2()
evt1, ok1 := next1()
evt2, ok2 := next2()
both:
if ok1 && ok2 {
if evt2.CreatedAt > evt1.CreatedAt {
if !yield(evt2) {
return
}
evt2, ok2 = next2()
goto both
} else {
if !yield(evt1) {
return
}
evt1, ok1 = next1()
goto both
}
}
if !ok2 {
only1:
if ok1 {
if !yield(evt1) {
return
}
evt1, ok1 = next1()
goto only1
}
}
if !ok1 {
only2:
if ok2 {
if !yield(evt2) {
return
}
evt2, ok2 = next2()
goto only2
}
}
return
}
}

View File

@@ -0,0 +1,52 @@
package eventstore
import (
"cmp"
"slices"
"testing"
"fiatjaf.com/nostr"
)
func FuzzSortedMerge(f *testing.F) {
f.Add(uint(4), uint(4), uint(3), uint(7), uint8(2), uint8(1))
f.Add(uint(0), uint(4), uint(3), uint(7), uint8(2), uint8(1))
f.Fuzz(func(t *testing.T, len1, len2 uint, start1, start2 uint, diff1, diff2 uint8) {
maxxx := max(len1*uint(diff1), len2*uint(diff2))
start1 += maxxx
start2 += maxxx
merged := SortedMerge(
func(yield func(nostr.Event) bool) {
for range len1 {
if !yield(nostr.Event{CreatedAt: nostr.Timestamp(start1)}) {
return
}
start1 -= uint(diff1)
}
},
func(yield func(nostr.Event) bool) {
for range len2 {
if !yield(nostr.Event{CreatedAt: nostr.Timestamp(start2)}) {
return
}
start2 -= uint(diff2)
}
},
)
result := slices.Collect(merged)
// assert length
if len(result) != int(len1+len2) {
t.Fatalf("expected %d events, got %d", len1+len2, len(result))
}
// assert sorted descending
slices.IsSortedFunc(result, func(a, b nostr.Event) int { return -1 * cmp.Compare(a.CreatedAt, b.CreatedAt) })
for i := 1; i < len(result); i++ {
if result[i].CreatedAt > result[i-1].CreatedAt {
t.Fatalf("events not sorted descending at index %d: %d > %d", i, result[i].CreatedAt, result[i-1].CreatedAt)
}
}
})
}