Files
nostrlib/eventstore/mmm/count.go
2025-04-15 08:51:25 -03:00

92 lines
2.2 KiB
Go

package mmm
import (
"bytes"
"context"
"encoding/binary"
"slices"
"github.com/PowerDNS/lmdb-go/lmdb"
"fiatjaf.com/nostr/eventstore/mmm/betterbinary"
"fiatjaf.com/nostr"
)
func (il *IndexingLayer) CountEvents(ctx context.Context, filter nostr.Filter) (int64, error) {
var count int64 = 0
queries, extraAuthors, extraKinds, extraTagKey, extraTagValues, since, err := il.prepareQueries(filter)
if err != nil {
return 0, err
}
err = il.lmdbEnv.View(func(txn *lmdb.Txn) error {
// actually iterate
for _, q := range queries {
cursor, err := txn.OpenCursor(q.dbi)
if err != nil {
continue
}
it := &iterator{cursor: cursor}
it.seek(q.startingPoint)
for {
// we already have a k and a v and an err from the cursor setup, so check and use these
if it.err != nil ||
len(it.key) != q.keySize ||
!bytes.HasPrefix(it.key, q.prefix) {
// either iteration has errored or we reached the end of this prefix
break // stop this cursor and move to the next one
}
// "id" indexes don't contain a timestamp
if q.timestampSize == 4 {
createdAt := binary.BigEndian.Uint32(it.key[len(it.key)-4:])
if createdAt < since {
break
}
}
if extraAuthors == nil && extraKinds == nil && extraTagValues == nil {
count++
} else {
// fetch actual event
pos := positionFromBytes(it.posb)
bin := il.mmmm.mmapf[pos.start : pos.start+uint64(pos.size)]
// check it against pubkeys without decoding the entire thing
if extraAuthors != nil && !slices.Contains(extraAuthors, [32]byte(bin[39:71])) {
it.next()
continue
}
// check it against kinds without decoding the entire thing
if extraKinds != nil && !slices.Contains(extraKinds, [2]byte(bin[1:3])) {
it.next()
continue
}
// decode the entire thing (TODO: do a conditional decode while also checking the extra tag)
event := &nostr.Event{}
if err := betterbinary.Unmarshal(bin, event); err != nil {
it.next()
continue
}
// if there is still a tag to be checked, do it now
if !event.Tags.ContainsAny(extraTagKey, extraTagValues) {
it.next()
continue
}
count++
}
}
}
return nil
})
return count, err
}