Files
next.orly.dev/cmd/benchmark/relysqlite_wrapper.go
2025-11-23 08:15:06 +00:00

290 lines
11 KiB
Go

package main
import (
"context"
"fmt"
"io"
"time"
sqlite "github.com/vertex-lab/nostr-sqlite"
"next.orly.dev/pkg/database"
"next.orly.dev/pkg/database/indexes/types"
"git.mleku.dev/mleku/nostr/encoders/event"
"git.mleku.dev/mleku/nostr/encoders/filter"
"git.mleku.dev/mleku/nostr/encoders/tag"
"next.orly.dev/pkg/interfaces/store"
)
// RelySQLiteWrapper wraps the vertex-lab/nostr-sqlite store to implement
// the minimal database.Database interface needed for benchmarking
type RelySQLiteWrapper struct {
store *sqlite.Store
path string
ready chan struct{}
}
// NewRelySQLiteWrapper creates a new wrapper around nostr-sqlite
func NewRelySQLiteWrapper(dbPath string) (*RelySQLiteWrapper, error) {
store, err := sqlite.New(dbPath)
if err != nil {
return nil, fmt.Errorf("failed to create sqlite store: %w", err)
}
wrapper := &RelySQLiteWrapper{
store: store,
path: dbPath,
ready: make(chan struct{}),
}
// Close the ready channel immediately as SQLite is ready on creation
close(wrapper.ready)
return wrapper, nil
}
// SaveEvent saves an event to the database
func (w *RelySQLiteWrapper) SaveEvent(ctx context.Context, ev *event.E) (exists bool, err error) {
// Convert ORLY event to go-nostr event
nostrEv, err := convertToNostrEvent(ev)
if err != nil {
return false, fmt.Errorf("failed to convert event: %w", err)
}
// Use Replace for replaceable/addressable events, Save otherwise
if isReplaceableKind(int(ev.Kind)) || isAddressableKind(int(ev.Kind)) {
replaced, err := w.store.Replace(ctx, nostrEv)
return replaced, err
}
saved, err := w.store.Save(ctx, nostrEv)
return !saved, err // saved=true means it's new, exists=false
}
// QueryEvents queries events matching the filter
func (w *RelySQLiteWrapper) QueryEvents(ctx context.Context, f *filter.F) (evs event.S, err error) {
// Convert ORLY filter to go-nostr filter
nostrFilter, err := convertToNostrFilter(f)
if err != nil {
return nil, fmt.Errorf("failed to convert filter: %w", err)
}
// Query the store
nostrEvents, err := w.store.Query(ctx, nostrFilter)
if err != nil {
return nil, fmt.Errorf("query failed: %w", err)
}
// Convert back to ORLY events
events := make(event.S, 0, len(nostrEvents))
for _, ne := range nostrEvents {
ev, err := convertFromNostrEvent(&ne)
if err != nil {
continue // Skip events that fail to convert
}
events = append(events, ev)
}
return events, nil
}
// Close closes the database
func (w *RelySQLiteWrapper) Close() error {
if w.store != nil {
return w.store.Close()
}
return nil
}
// Ready returns a channel that closes when the database is ready
func (w *RelySQLiteWrapper) Ready() <-chan struct{} {
return w.ready
}
// Path returns the database path
func (w *RelySQLiteWrapper) Path() string {
return w.path
}
// Wipe clears all data from the database
func (w *RelySQLiteWrapper) Wipe() error {
// Close current store
if err := w.store.Close(); err != nil {
return err
}
// Delete the database file
// Note: This is a simplified approach - in production you'd want
// to handle this more carefully
return nil
}
// Stub implementations for unused interface methods
func (w *RelySQLiteWrapper) Init(path string) error { return nil }
func (w *RelySQLiteWrapper) Sync() error { return nil }
func (w *RelySQLiteWrapper) SetLogLevel(level string) {}
func (w *RelySQLiteWrapper) GetSerialsFromFilter(f *filter.F) (serials types.Uint40s, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) WouldReplaceEvent(ev *event.E) (bool, types.Uint40s, error) {
return false, nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) QueryAllVersions(c context.Context, f *filter.F) (evs event.S, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) QueryEventsWithOptions(c context.Context, f *filter.F, includeDeleteEvents bool, showAllVersions bool) (evs event.S, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) QueryDeleteEventsByTargetId(c context.Context, targetEventId []byte) (evs event.S, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) QueryForSerials(c context.Context, f *filter.F) (serials types.Uint40s, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) QueryForIds(c context.Context, f *filter.F) (idPkTs []*store.IdPkTs, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) CountEvents(c context.Context, f *filter.F) (count int, approximate bool, err error) {
return 0, false, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) FetchEventBySerial(ser *types.Uint40) (ev *event.E, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) FetchEventsBySerials(serials []*types.Uint40) (events map[uint64]*event.E, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetSerialById(id []byte) (ser *types.Uint40, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetSerialsByIds(ids *tag.T) (serials map[string]*types.Uint40, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetSerialsByIdsWithFilter(ids *tag.T, fn func(ev *event.E, ser *types.Uint40) bool) (serials map[string]*types.Uint40, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetSerialsByRange(idx database.Range) (serials types.Uint40s, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetFullIdPubkeyBySerial(ser *types.Uint40) (fidpk *store.IdPkTs, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetFullIdPubkeyBySerials(sers []*types.Uint40) (fidpks []*store.IdPkTs, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) DeleteEvent(c context.Context, eid []byte) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) DeleteEventBySerial(c context.Context, ser *types.Uint40, ev *event.E) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) DeleteExpired() {}
func (w *RelySQLiteWrapper) ProcessDelete(ev *event.E, admins [][]byte) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) CheckForDeleted(ev *event.E, admins [][]byte) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) Import(rr io.Reader) {}
func (w *RelySQLiteWrapper) Export(c context.Context, writer io.Writer, pubkeys ...[]byte) {
}
func (w *RelySQLiteWrapper) ImportEventsFromReader(ctx context.Context, rr io.Reader) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) ImportEventsFromStrings(ctx context.Context, eventJSONs []string, policyManager interface{ CheckPolicy(action string, ev *event.E, pubkey []byte, remote string) (bool, error) }) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetRelayIdentitySecret() (skb []byte, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) SetRelayIdentitySecret(skb []byte) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetOrCreateRelayIdentitySecret() (skb []byte, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) SetMarker(key string, value []byte) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetMarker(key string) (value []byte, err error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) HasMarker(key string) bool { return false }
func (w *RelySQLiteWrapper) DeleteMarker(key string) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetSubscription(pubkey []byte) (*database.Subscription, error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) IsSubscriptionActive(pubkey []byte) (bool, error) {
return false, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) ExtendSubscription(pubkey []byte, days int) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) RecordPayment(pubkey []byte, amount int64, invoice, preimage string) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetPaymentHistory(pubkey []byte) ([]database.Payment, error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) ExtendBlossomSubscription(pubkey []byte, tier string, storageMB int64, daysExtended int) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetBlossomStorageQuota(pubkey []byte) (quotaMB int64, err error) {
return 0, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) IsFirstTimeUser(pubkey []byte) (bool, error) {
return false, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) AddNIP43Member(pubkey []byte, inviteCode string) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) RemoveNIP43Member(pubkey []byte) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) IsNIP43Member(pubkey []byte) (isMember bool, err error) {
return false, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetNIP43Membership(pubkey []byte) (*database.NIP43Membership, error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetAllNIP43Members() ([][]byte, error) {
return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) StoreInviteCode(code string, expiresAt time.Time) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) ValidateInviteCode(code string) (valid bool, err error) {
return false, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) DeleteInviteCode(code string) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) PublishNIP43MembershipEvent(kind int, pubkey []byte) error {
return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) RunMigrations() {}
func (w *RelySQLiteWrapper) GetCachedJSON(f *filter.F) ([][]byte, bool) {
return nil, false
}
func (w *RelySQLiteWrapper) CacheMarshaledJSON(f *filter.F, marshaledJSON [][]byte) {
}
func (w *RelySQLiteWrapper) GetCachedEvents(f *filter.F) (event.S, bool) {
return nil, false
}
func (w *RelySQLiteWrapper) CacheEvents(f *filter.F, events event.S) {}
func (w *RelySQLiteWrapper) InvalidateQueryCache() {}
func (w *RelySQLiteWrapper) EventIdsBySerial(start uint64, count int) (evs []uint64, err error) {
return nil, fmt.Errorf("not implemented")
}
// Helper function to check if a kind is replaceable
func isReplaceableKind(kind int) bool {
return (kind >= 10000 && kind < 20000) || kind == 0 || kind == 3
}
// Helper function to check if a kind is addressable
func isAddressableKind(kind int) bool {
return kind >= 30000 && kind < 40000
}