refactor save event method to expose whether it replaced an event

This commit is contained in:
2025-10-10 22:16:07 +01:00
parent 0cdf44c2c9
commit bc5177e0ec
25 changed files with 368 additions and 289 deletions

View File

@@ -55,7 +55,7 @@ func TestExport(t *testing.T) {
}
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event: %v", err)
}

View File

@@ -58,7 +58,7 @@ func TestFetchEventBySerial(t *testing.T) {
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -52,11 +52,11 @@ func TestGetSerialById(t *testing.T) {
t.Fatal(err)
}
ev.Free()
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -63,7 +63,7 @@ func TestGetSerialsByRange(t *testing.T) {
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -59,7 +59,7 @@ func (d *D) Import(rr io.Reader) {
continue
}
if _, _, err = d.SaveEvent(d.ctx, ev); err != nil {
if err, _ = d.SaveEvent(d.ctx, ev); err != nil {
// return the pooled buffer on error paths too
ev.Free()
continue

View File

@@ -43,7 +43,7 @@ func TestMultipleParameterizedReplaceableEvents(t *testing.T) {
baseEvent.Sign(sign)
// Save the base parameterized replaceable event
if _, _, err := db.SaveEvent(ctx, baseEvent); err != nil {
if err, _ := db.SaveEvent(ctx, baseEvent); err != nil {
t.Fatalf("Failed to save base parameterized replaceable event: %v", err)
}
@@ -61,7 +61,7 @@ func TestMultipleParameterizedReplaceableEvents(t *testing.T) {
newerEvent.Sign(sign)
// Save the newer parameterized replaceable event
if _, _, err := db.SaveEvent(ctx, newerEvent); err != nil {
if err, _ := db.SaveEvent(ctx, newerEvent); err != nil {
t.Fatalf(
"Failed to save newer parameterized replaceable event: %v", err,
)
@@ -81,7 +81,7 @@ func TestMultipleParameterizedReplaceableEvents(t *testing.T) {
newestEvent.Sign(sign)
// Save the newest parameterized replaceable event
if _, _, err := db.SaveEvent(ctx, newestEvent); err != nil {
if err, _ := db.SaveEvent(ctx, newestEvent); err != nil {
t.Fatalf(
"Failed to save newest parameterized replaceable event: %v", err,
)

View File

@@ -1,194 +1,196 @@
package database
import (
"context"
"os"
"testing"
"time"
"context"
"os"
"testing"
"time"
"lol.mleku.dev/chk"
"next.orly.dev/pkg/crypto/p256k"
"next.orly.dev/pkg/encoders/event"
"next.orly.dev/pkg/encoders/filter"
"next.orly.dev/pkg/encoders/kind"
"next.orly.dev/pkg/encoders/tag"
"next.orly.dev/pkg/encoders/timestamp"
"lol.mleku.dev/chk"
"next.orly.dev/pkg/crypto/p256k"
"next.orly.dev/pkg/encoders/event"
"next.orly.dev/pkg/encoders/filter"
"next.orly.dev/pkg/encoders/kind"
"next.orly.dev/pkg/encoders/tag"
"next.orly.dev/pkg/encoders/timestamp"
)
// helper to create a fresh DB
func newTestDB(t *testing.T) (*D, context.Context, context.CancelFunc, string) {
t.Helper()
tempDir, err := os.MkdirTemp("", "search-db-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
db, err := New(ctx, cancel, tempDir, "error")
if err != nil {
cancel()
os.RemoveAll(tempDir)
t.Fatalf("Failed to init DB: %v", err)
}
return db, ctx, cancel, tempDir
t.Helper()
tempDir, err := os.MkdirTemp("", "search-db-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
db, err := New(ctx, cancel, tempDir, "error")
if err != nil {
cancel()
os.RemoveAll(tempDir)
t.Fatalf("Failed to init DB: %v", err)
}
return db, ctx, cancel, tempDir
}
// TestQueryEventsBySearchTerms creates a small set of events with content and tags,
// saves them, then queries using filter.Search to ensure the word index works.
func TestQueryEventsBySearchTerms(t *testing.T) {
db, ctx, cancel, tempDir := newTestDB(t)
defer func() {
// cancel context first to stop background routines cleanly
cancel()
db.Close()
os.RemoveAll(tempDir)
}()
db, ctx, cancel, tempDir := newTestDB(t)
defer func() {
// cancel context first to stop background routines cleanly
cancel()
db.Close()
os.RemoveAll(tempDir)
}()
// signer for all events
sign := new(p256k.Signer)
if err := sign.Generate(); chk.E(err) {
t.Fatalf("signer generate: %v", err)
}
// signer for all events
sign := new(p256k.Signer)
if err := sign.Generate(); chk.E(err) {
t.Fatalf("signer generate: %v", err)
}
now := timestamp.Now().V
now := timestamp.Now().V
// Events to cover tokenizer rules:
// - regular words
// - URLs ignored
// - 64-char hex ignored
// - nostr: URIs ignored
// - #[n] mentions ignored
// - tag fields included in search
// Events to cover tokenizer rules:
// - regular words
// - URLs ignored
// - 64-char hex ignored
// - nostr: URIs ignored
// - #[n] mentions ignored
// - tag fields included in search
// 1. Contains words: "alpha beta", plus URL and hex (ignored)
ev1 := event.New()
ev1.Kind = kind.TextNote.K
ev1.Pubkey = sign.Pub()
ev1.CreatedAt = now - 5
ev1.Content = []byte("Alpha beta visit https://example.com deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
ev1.Tags = tag.NewS()
ev1.Sign(sign)
if _, _, err := db.SaveEvent(ctx, ev1); err != nil {
t.Fatalf("save ev1: %v", err)
}
// 1. Contains words: "alpha beta", plus URL and hex (ignored)
ev1 := event.New()
ev1.Kind = kind.TextNote.K
ev1.Pubkey = sign.Pub()
ev1.CreatedAt = now - 5
ev1.Content = []byte("Alpha beta visit https://example.com deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
ev1.Tags = tag.NewS()
ev1.Sign(sign)
if err, _ := db.SaveEvent(ctx, ev1); err != nil {
t.Fatalf("save ev1: %v", err)
}
// 2. Contains overlap word "beta" and unique "gamma" and nostr: URI ignored
ev2 := event.New()
ev2.Kind = kind.TextNote.K
ev2.Pubkey = sign.Pub()
ev2.CreatedAt = now - 4
ev2.Content = []byte("beta and GAMMA with nostr:nevent1qqqqq")
ev2.Tags = tag.NewS()
ev2.Sign(sign)
if _, _, err := db.SaveEvent(ctx, ev2); err != nil {
t.Fatalf("save ev2: %v", err)
}
// 2. Contains overlap word "beta" and unique "gamma" and nostr: URI ignored
ev2 := event.New()
ev2.Kind = kind.TextNote.K
ev2.Pubkey = sign.Pub()
ev2.CreatedAt = now - 4
ev2.Content = []byte("beta and GAMMA with nostr:nevent1qqqqq")
ev2.Tags = tag.NewS()
ev2.Sign(sign)
if err, _ := db.SaveEvent(ctx, ev2); err != nil {
t.Fatalf("save ev2: %v", err)
}
// 3. Contains only a URL (should not create word tokens) and mention #[1] (ignored)
ev3 := event.New()
ev3.Kind = kind.TextNote.K
ev3.Pubkey = sign.Pub()
ev3.CreatedAt = now - 3
ev3.Content = []byte("see www.example.org #[1]")
ev3.Tags = tag.NewS()
ev3.Sign(sign)
if _, _, err := db.SaveEvent(ctx, ev3); err != nil {
t.Fatalf("save ev3: %v", err)
}
// 3. Contains only a URL (should not create word tokens) and mention #[1] (ignored)
ev3 := event.New()
ev3.Kind = kind.TextNote.K
ev3.Pubkey = sign.Pub()
ev3.CreatedAt = now - 3
ev3.Content = []byte("see www.example.org #[1]")
ev3.Tags = tag.NewS()
ev3.Sign(sign)
if err, _ := db.SaveEvent(ctx, ev3); err != nil {
t.Fatalf("save ev3: %v", err)
}
// 4. No content words, but tag value has searchable words: "delta epsilon"
ev4 := event.New()
ev4.Kind = kind.TextNote.K
ev4.Pubkey = sign.Pub()
ev4.CreatedAt = now - 2
ev4.Content = []byte("")
ev4.Tags = tag.NewS()
*ev4.Tags = append(*ev4.Tags, tag.NewFromAny("t", "delta epsilon"))
ev4.Sign(sign)
if _, _, err := db.SaveEvent(ctx, ev4); err != nil {
t.Fatalf("save ev4: %v", err)
}
// 4. No content words, but tag value has searchable words: "delta epsilon"
ev4 := event.New()
ev4.Kind = kind.TextNote.K
ev4.Pubkey = sign.Pub()
ev4.CreatedAt = now - 2
ev4.Content = []byte("")
ev4.Tags = tag.NewS()
*ev4.Tags = append(*ev4.Tags, tag.NewFromAny("t", "delta epsilon"))
ev4.Sign(sign)
if err, _ := db.SaveEvent(ctx, ev4); err != nil {
t.Fatalf("save ev4: %v", err)
}
// 5. Another event with both content and tag tokens for ordering checks
ev5 := event.New()
ev5.Kind = kind.TextNote.K
ev5.Pubkey = sign.Pub()
ev5.CreatedAt = now - 1
ev5.Content = []byte("alpha DELTA mixed-case and link http://foo.bar")
ev5.Tags = tag.NewS()
*ev5.Tags = append(*ev5.Tags, tag.NewFromAny("t", "zeta"))
ev5.Sign(sign)
if _, _, err := db.SaveEvent(ctx, ev5); err != nil {
t.Fatalf("save ev5: %v", err)
}
// 5. Another event with both content and tag tokens for ordering checks
ev5 := event.New()
ev5.Kind = kind.TextNote.K
ev5.Pubkey = sign.Pub()
ev5.CreatedAt = now - 1
ev5.Content = []byte("alpha DELTA mixed-case and link http://foo.bar")
ev5.Tags = tag.NewS()
*ev5.Tags = append(*ev5.Tags, tag.NewFromAny("t", "zeta"))
ev5.Sign(sign)
if err, _ := db.SaveEvent(ctx, ev5); err != nil {
t.Fatalf("save ev5: %v", err)
}
// Small sleep to ensure created_at ordering is the only factor
time.Sleep(5 * time.Millisecond)
// Small sleep to ensure created_at ordering is the only factor
time.Sleep(5 * time.Millisecond)
// Helper to run a search and return IDs
run := func(q string) ([]*event.E, error) {
f := &filter.F{Search: []byte(q)}
return db.QueryEvents(ctx, f)
}
// Helper to run a search and return IDs
run := func(q string) ([]*event.E, error) {
f := &filter.F{Search: []byte(q)}
return db.QueryEvents(ctx, f)
}
// Single-term search: alpha -> should match ev1 and ev5 ordered by created_at desc (ev5 newer)
if evs, err := run("alpha"); err != nil {
t.Fatalf("search alpha: %v", err)
} else {
if len(evs) != 2 {
t.Fatalf("alpha expected 2 results, got %d", len(evs))
}
if !(evs[0].CreatedAt >= evs[1].CreatedAt) {
t.Fatalf("results not ordered by created_at desc")
}
}
// Single-term search: alpha -> should match ev1 and ev5 ordered by created_at desc (ev5 newer)
if evs, err := run("alpha"); err != nil {
t.Fatalf("search alpha: %v", err)
} else {
if len(evs) != 2 {
t.Fatalf("alpha expected 2 results, got %d", len(evs))
}
if !(evs[0].CreatedAt >= evs[1].CreatedAt) {
t.Fatalf("results not ordered by created_at desc")
}
}
// Overlap term beta -> ev1 and ev2
if evs, err := run("beta"); err != nil {
t.Fatalf("search beta: %v", err)
} else if len(evs) != 2 {
t.Fatalf("beta expected 2 results, got %d", len(evs))
}
// Overlap term beta -> ev1 and ev2
if evs, err := run("beta"); err != nil {
t.Fatalf("search beta: %v", err)
} else if len(evs) != 2 {
t.Fatalf("beta expected 2 results, got %d", len(evs))
}
// Unique term gamma -> only ev2
if evs, err := run("gamma"); err != nil {
t.Fatalf("search gamma: %v", err)
} else if len(evs) != 1 {
t.Fatalf("gamma expected 1 result, got %d", len(evs))
}
// Unique term gamma -> only ev2
if evs, err := run("gamma"); err != nil {
t.Fatalf("search gamma: %v", err)
} else if len(evs) != 1 {
t.Fatalf("gamma expected 1 result, got %d", len(evs))
}
// URL terms should be ignored: example -> appears only as URL in ev1/ev3/ev5; tokenizer ignores URLs so expect 0
if evs, err := run("example"); err != nil {
t.Fatalf("search example: %v", err)
} else if len(evs) != 0 {
t.Fatalf("example expected 0 results (URL tokens ignored), got %d", len(evs))
}
// URL terms should be ignored: example -> appears only as URL in ev1/ev3/ev5; tokenizer ignores URLs so expect 0
if evs, err := run("example"); err != nil {
t.Fatalf("search example: %v", err)
} else if len(evs) != 0 {
t.Fatalf(
"example expected 0 results (URL tokens ignored), got %d", len(evs),
)
}
// Tag words searchable: delta should match ev4 and ev5 (delta in tag for ev4, in content for ev5)
if evs, err := run("delta"); err != nil {
t.Fatalf("search delta: %v", err)
} else if len(evs) != 2 {
t.Fatalf("delta expected 2 results, got %d", len(evs))
}
// Tag words searchable: delta should match ev4 and ev5 (delta in tag for ev4, in content for ev5)
if evs, err := run("delta"); err != nil {
t.Fatalf("search delta: %v", err)
} else if len(evs) != 2 {
t.Fatalf("delta expected 2 results, got %d", len(evs))
}
// Very short token ignored: single-letter should yield 0
if evs, err := run("a"); err != nil {
t.Fatalf("search short token: %v", err)
} else if len(evs) != 0 {
t.Fatalf("single-letter expected 0 results, got %d", len(evs))
}
// Very short token ignored: single-letter should yield 0
if evs, err := run("a"); err != nil {
t.Fatalf("search short token: %v", err)
} else if len(evs) != 0 {
t.Fatalf("single-letter expected 0 results, got %d", len(evs))
}
// 64-char hex should be ignored
hex64 := "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
if evs, err := run(hex64); err != nil {
t.Fatalf("search hex64: %v", err)
} else if len(evs) != 0 {
t.Fatalf("hex64 expected 0 results, got %d", len(evs))
}
// 64-char hex should be ignored
hex64 := "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
if evs, err := run(hex64); err != nil {
t.Fatalf("search hex64: %v", err)
} else if len(evs) != 0 {
t.Fatalf("hex64 expected 0 results, got %d", len(evs))
}
// nostr: scheme ignored
if evs, err := run("nostr:nevent1qqqqq"); err != nil {
t.Fatalf("search nostr: %v", err)
} else if len(evs) != 0 {
t.Fatalf("nostr: expected 0 results, got %d", len(evs))
}
// nostr: scheme ignored
if evs, err := run("nostr:nevent1qqqqq"); err != nil {
t.Fatalf("search nostr: %v", err)
} else if len(evs) != 0 {
t.Fatalf("nostr: expected 0 results, got %d", len(evs))
}
}

View File

@@ -64,7 +64,7 @@ func setupTestDB(t *testing.T) (
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}
@@ -204,7 +204,7 @@ func TestReplaceableEventsAndDeletion(t *testing.T) {
replaceableEvent.Tags = tag.NewS()
replaceableEvent.Sign(sign)
// Save the replaceable event
if _, _, err := db.SaveEvent(ctx, replaceableEvent); err != nil {
if err, _ := db.SaveEvent(ctx, replaceableEvent); err != nil {
t.Errorf("Failed to save replaceable event: %v", err)
}
@@ -217,7 +217,7 @@ func TestReplaceableEventsAndDeletion(t *testing.T) {
newerEvent.Tags = tag.NewS()
newerEvent.Sign(sign)
// Save the newer event
if _, _, err := db.SaveEvent(ctx, newerEvent); err != nil {
if err, _ := db.SaveEvent(ctx, newerEvent); err != nil {
t.Errorf("Failed to save newer event: %v", err)
}
@@ -286,7 +286,7 @@ func TestReplaceableEventsAndDeletion(t *testing.T) {
)
// Save the deletion event
if _, _, err = db.SaveEvent(ctx, deletionEvent); err != nil {
if err, _ = db.SaveEvent(ctx, deletionEvent); err != nil {
t.Fatalf("Failed to save deletion event: %v", err)
}
@@ -371,7 +371,7 @@ func TestParameterizedReplaceableEventsAndDeletion(t *testing.T) {
paramEvent.Sign(sign)
// Save the parameterized replaceable event
if _, _, err := db.SaveEvent(ctx, paramEvent); err != nil {
if err, _ := db.SaveEvent(ctx, paramEvent); err != nil {
t.Fatalf("Failed to save parameterized replaceable event: %v", err)
}
@@ -397,7 +397,7 @@ func TestParameterizedReplaceableEventsAndDeletion(t *testing.T) {
paramDeletionEvent.Sign(sign)
// Save the parameterized deletion event
if _, _, err := db.SaveEvent(ctx, paramDeletionEvent); err != nil {
if err, _ := db.SaveEvent(ctx, paramDeletionEvent); err != nil {
t.Fatalf("Failed to save parameterized deletion event: %v", err)
}
@@ -430,7 +430,7 @@ func TestParameterizedReplaceableEventsAndDeletion(t *testing.T) {
paramDeletionEvent2.Sign(sign)
// Save the parameterized deletion event with e-tag
if _, _, err := db.SaveEvent(ctx, paramDeletionEvent2); err != nil {
if err, _ := db.SaveEvent(ctx, paramDeletionEvent2); err != nil {
t.Fatalf(
"Failed to save parameterized deletion event with e-tag: %v", err,
)

View File

@@ -58,7 +58,7 @@ func TestQueryForAuthorsTags(t *testing.T) {
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -60,7 +60,7 @@ func TestQueryForIds(t *testing.T) {
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -59,7 +59,7 @@ func TestQueryForKindsAuthorsTags(t *testing.T) {
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -59,7 +59,7 @@ func TestQueryForKindsAuthors(t *testing.T) {
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -59,7 +59,7 @@ func TestQueryForKindsTags(t *testing.T) {
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -58,7 +58,7 @@ func TestQueryForKinds(t *testing.T) {
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -61,7 +61,7 @@ func TestQueryForSerials(t *testing.T) {
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -58,7 +58,7 @@ func TestQueryForTags(t *testing.T) {
events = append(events, ev)
// Save the event to the database
if _, _, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/dgraph-io/badger/v4"
"lol.mleku.dev/chk"
"lol.mleku.dev/log"
"next.orly.dev/pkg/database/indexes"
"next.orly.dev/pkg/database/indexes/types"
"next.orly.dev/pkg/encoders/event"
@@ -103,7 +102,9 @@ func (d *D) WouldReplaceEvent(ev *event.E) (bool, types.Uint40s, error) {
}
// SaveEvent saves an event to the database, generating all the necessary indexes.
func (d *D) SaveEvent(c context.Context, ev *event.E) (kc, vc int, err error) {
func (d *D) SaveEvent(c context.Context, ev *event.E) (
err error, replaced bool,
) {
if ev == nil {
err = errors.New("nil event")
return
@@ -136,10 +137,9 @@ func (d *D) SaveEvent(c context.Context, ev *event.E) (kc, vc int, err error) {
}
// check for replacement (separated check vs deletion)
if kind.IsReplaceable(ev.Kind) || kind.IsParameterizedReplaceable(ev.Kind) {
var wouldReplace bool
var sers types.Uint40s
var werr error
if wouldReplace, sers, werr = d.WouldReplaceEvent(ev); werr != nil {
if replaced, sers, werr = d.WouldReplaceEvent(ev); werr != nil {
if errors.Is(werr, ErrOlderThanExisting) {
if kind.IsReplaceable(ev.Kind) {
err = errors.New("blocked: event is older than existing replaceable event")
@@ -156,7 +156,7 @@ func (d *D) SaveEvent(c context.Context, ev *event.E) (kc, vc int, err error) {
// any other error
return
}
if wouldReplace {
if replaced {
for _, s := range sers {
var oldEv *event.E
if oldEv, err = d.FetchEventBySerial(s); chk.E(err) {
@@ -178,10 +178,6 @@ func (d *D) SaveEvent(c context.Context, ev *event.E) (kc, vc int, err error) {
if idxs, err = GetIndexesForEvent(ev, serial); chk.E(err) {
return
}
// log.I.S(idxs)
for _, k := range idxs {
kc += len(k)
}
// Start a transaction to save the event and all its indexes
err = d.Update(
func(txn *badger.Txn) (err error) {
@@ -209,23 +205,11 @@ func (d *D) SaveEvent(c context.Context, ev *event.E) (kc, vc int, err error) {
v := new(bytes.Buffer)
ev.MarshalBinary(v)
kb, vb := k.Bytes(), v.Bytes()
kc += len(kb)
vc += len(vb)
// log.I.S(kb, vb)
if err = txn.Set(kb, vb); chk.E(err) {
return
}
return
},
)
log.T.F(
"total data written: %d bytes keys %d bytes values for event ID %s", kc,
vc, hex.Enc(ev.ID),
)
// log.T.C(
// func() string {
// return fmt.Sprintf("event:\n%s\n", ev.Serialize())
// },
// )
return
}

View File

@@ -65,7 +65,7 @@ func TestSaveEvents(t *testing.T) {
// Save the event to the database
var k, v int
if k, v, err = db.SaveEvent(ctx, ev); err != nil {
if err, _ = db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event #%d: %v", eventCount+1, err)
}
kc += k
@@ -125,7 +125,7 @@ func TestDeletionEventWithETagRejection(t *testing.T) {
regularEvent.Sign(sign)
// Save the regular event
if _, _, err := db.SaveEvent(ctx, regularEvent); err != nil {
if err, _ := db.SaveEvent(ctx, regularEvent); err != nil {
t.Fatalf("Failed to save regular event: %v", err)
}
@@ -151,7 +151,7 @@ func TestDeletionEventWithETagRejection(t *testing.T) {
err = errorf.E("deletion events referencing other events with 'e' tag are not allowed")
} else {
// Try to save the deletion event
_, _, err = db.SaveEvent(ctx, deletionEvent)
err, _ = db.SaveEvent(ctx, deletionEvent)
}
if err == nil {
@@ -204,12 +204,12 @@ func TestSaveExistingEvent(t *testing.T) {
ev.Sign(sign)
// Save the event for the first time
if _, _, err := db.SaveEvent(ctx, ev); err != nil {
if err, _ := db.SaveEvent(ctx, ev); err != nil {
t.Fatalf("Failed to save event: %v", err)
}
// Try to save the same event again, it should be rejected
_, _, err = db.SaveEvent(ctx, ev)
err, _ = db.SaveEvent(ctx, ev)
if err == nil {
t.Fatal("Expected error when saving an existing event, but got nil")
}