mirror of
https://github.com/fiatjaf/khatru.git
synced 2025-03-18 05:42:19 +01:00
refactor(postgres): Unit test SaveEvent
Refactors SaveEvent so it's unit testable and adds tests to assert the current behavior.
This commit is contained in:
parent
f328910ab6
commit
a7dbf7c491
storage/postgresql
@ -9,30 +9,13 @@ import (
|
||||
)
|
||||
|
||||
func (b *PostgresBackend) SaveEvent(ctx context.Context, evt *nostr.Event) error {
|
||||
// react to different kinds of events
|
||||
if evt.Kind == nostr.KindSetMetadata || evt.Kind == nostr.KindContactList || (10000 <= evt.Kind && evt.Kind < 20000) {
|
||||
// delete past events from this user
|
||||
b.DB.ExecContext(ctx, `DELETE FROM event WHERE pubkey = $1 AND kind = $2`, evt.PubKey, evt.Kind)
|
||||
} else if evt.Kind == nostr.KindRecommendServer {
|
||||
// delete past recommend_server events equal to this one
|
||||
b.DB.ExecContext(ctx, `DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3`,
|
||||
evt.PubKey, evt.Kind, evt.Content)
|
||||
} else if evt.Kind >= 30000 && evt.Kind < 40000 {
|
||||
// NIP-33
|
||||
d := evt.Tags.GetFirst([]string{"d"})
|
||||
if d != nil {
|
||||
b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND tagvalues && ARRAY[$3]`,
|
||||
evt.PubKey, evt.Kind, d.Value())
|
||||
}
|
||||
deleteQuery, deleteParams, shouldDelete := deleteBeforeSaveSql(evt)
|
||||
if shouldDelete {
|
||||
_, _ = b.DB.ExecContext(ctx, deleteQuery, deleteParams...)
|
||||
}
|
||||
|
||||
// insert
|
||||
tagsj, _ := json.Marshal(evt.Tags)
|
||||
res, err := b.DB.ExecContext(ctx, `
|
||||
INSERT INTO event (id, pubkey, created_at, kind, tags, content, sig)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
ON CONFLICT (id) DO NOTHING
|
||||
`, evt.ID, evt.PubKey, evt.CreatedAt, evt.Kind, tagsj, evt.Content, evt.Sig)
|
||||
sql, params, _ := saveEventSql(evt)
|
||||
res, err := b.DB.ExecContext(ctx, sql, params...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -60,3 +43,47 @@ func (b *PostgresBackend) AfterSave(evt *nostr.Event) {
|
||||
ORDER BY created_at DESC OFFSET 100 LIMIT 1
|
||||
)`, evt.PubKey, evt.Kind)
|
||||
}
|
||||
|
||||
func deleteBeforeSaveSql(evt *nostr.Event) (string, []any, bool) {
|
||||
// react to different kinds of events
|
||||
var (
|
||||
query = ""
|
||||
params []any
|
||||
shouldDelete bool
|
||||
)
|
||||
if evt.Kind == nostr.KindSetMetadata || evt.Kind == nostr.KindContactList || (10000 <= evt.Kind && evt.Kind < 20000) {
|
||||
// delete past events from this user
|
||||
query = `DELETE FROM event WHERE pubkey = $1 AND kind = $2`
|
||||
params = []any{evt.PubKey, evt.Kind}
|
||||
shouldDelete = true
|
||||
} else if evt.Kind == nostr.KindRecommendServer {
|
||||
// delete past recommend_server events equal to this one
|
||||
query = `DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3`
|
||||
params = []any{evt.PubKey, evt.Kind, evt.Content}
|
||||
shouldDelete = true
|
||||
} else if evt.Kind >= 30000 && evt.Kind < 40000 {
|
||||
// NIP-33
|
||||
d := evt.Tags.GetFirst([]string{"d"})
|
||||
if d != nil {
|
||||
query = `DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND tagvalues && ARRAY[$3]`
|
||||
params = []any{evt.PubKey, evt.Kind, d.Value()}
|
||||
shouldDelete = true
|
||||
}
|
||||
}
|
||||
|
||||
return query, params, shouldDelete
|
||||
}
|
||||
|
||||
func saveEventSql(evt *nostr.Event) (string, []any, error) {
|
||||
const query = `INSERT INTO event (
|
||||
id, pubkey, created_at, kind, tags, content, sig)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
ON CONFLICT (id) DO NOTHING`
|
||||
|
||||
var (
|
||||
tagsj, _ = json.Marshal(evt.Tags)
|
||||
params = []any{evt.ID, evt.PubKey, evt.CreatedAt, evt.Kind, tagsj, evt.Content, evt.Sig}
|
||||
)
|
||||
|
||||
return query, params, nil
|
||||
}
|
||||
|
177
storage/postgresql/save_test.go
Normal file
177
storage/postgresql/save_test.go
Normal file
@ -0,0 +1,177 @@
|
||||
package postgresql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDeleteBeforeSave(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
event *nostr.Event
|
||||
query string
|
||||
params []any
|
||||
shouldDelete bool
|
||||
}{
|
||||
{
|
||||
name: "set metadata",
|
||||
event: &nostr.Event{
|
||||
Kind: nostr.KindSetMetadata,
|
||||
PubKey: "pk",
|
||||
},
|
||||
query: "DELETE FROM event WHERE pubkey = $1 AND kind = $2",
|
||||
params: []any{"pk", nostr.KindSetMetadata},
|
||||
shouldDelete: true,
|
||||
},
|
||||
{
|
||||
name: "contact list",
|
||||
event: &nostr.Event{
|
||||
Kind: nostr.KindContactList,
|
||||
PubKey: "pk",
|
||||
},
|
||||
query: "DELETE FROM event WHERE pubkey = $1 AND kind = $2",
|
||||
params: []any{"pk", nostr.KindContactList},
|
||||
shouldDelete: true,
|
||||
},
|
||||
{
|
||||
name: "recommend server",
|
||||
event: &nostr.Event{
|
||||
Kind: nostr.KindRecommendServer,
|
||||
PubKey: "pk",
|
||||
Content: "test",
|
||||
},
|
||||
query: "DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3",
|
||||
params: []any{"pk", nostr.KindRecommendServer, "test"},
|
||||
shouldDelete: true,
|
||||
},
|
||||
{
|
||||
name: "nip-33",
|
||||
event: &nostr.Event{
|
||||
Kind: 31000,
|
||||
PubKey: "pk",
|
||||
Tags: nostr.Tags{nostr.Tag{"d", "value"}},
|
||||
},
|
||||
query: "DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND tagvalues && ARRAY[$3]",
|
||||
params: []any{"pk", 31000, "value"},
|
||||
shouldDelete: true,
|
||||
},
|
||||
{
|
||||
name: "kind > 10000",
|
||||
event: &nostr.Event{
|
||||
Kind: 10001,
|
||||
PubKey: "pk",
|
||||
},
|
||||
query: "DELETE FROM event WHERE pubkey = $1 AND kind = $2",
|
||||
params: []any{"pk", 10001},
|
||||
shouldDelete: true,
|
||||
},
|
||||
{
|
||||
name: "kind < 20000",
|
||||
event: &nostr.Event{
|
||||
Kind: 19999,
|
||||
PubKey: "pk",
|
||||
},
|
||||
query: "DELETE FROM event WHERE pubkey = $1 AND kind = $2",
|
||||
params: []any{"pk", 19999},
|
||||
shouldDelete: true,
|
||||
},
|
||||
// Should not delete cases
|
||||
{
|
||||
name: "kind < 10000",
|
||||
event: &nostr.Event{
|
||||
Kind: 9999,
|
||||
PubKey: "pk",
|
||||
},
|
||||
query: "",
|
||||
params: nil,
|
||||
shouldDelete: false,
|
||||
},
|
||||
{
|
||||
name: "kind > 21000",
|
||||
event: &nostr.Event{
|
||||
Kind: 21000,
|
||||
PubKey: "pk",
|
||||
},
|
||||
query: "",
|
||||
params: nil,
|
||||
shouldDelete: false,
|
||||
},
|
||||
{
|
||||
name: "kind 1",
|
||||
event: &nostr.Event{
|
||||
Kind: nostr.KindTextNote,
|
||||
PubKey: "pk",
|
||||
},
|
||||
query: "",
|
||||
params: nil,
|
||||
shouldDelete: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
query, params, shouldDelete := deleteBeforeSaveSql(tt.event)
|
||||
assert.Equal(t, tt.query, query)
|
||||
assert.Equal(t, tt.params, params)
|
||||
assert.Equal(t, tt.shouldDelete, shouldDelete)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveEventSql(t *testing.T) {
|
||||
now := nostr.Now()
|
||||
var tests = []struct {
|
||||
name string
|
||||
event *nostr.Event
|
||||
query string
|
||||
params []any
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "basic",
|
||||
event: &nostr.Event{
|
||||
ID: "id",
|
||||
PubKey: "pk",
|
||||
CreatedAt: now,
|
||||
Kind: nostr.KindTextNote,
|
||||
Content: "test",
|
||||
Sig: "sig",
|
||||
},
|
||||
query: `INSERT INTO event (
|
||||
id, pubkey, created_at, kind, tags, content, sig)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
ON CONFLICT (id) DO NOTHING`,
|
||||
params: []any{"id", "pk", now, nostr.KindTextNote, []byte("null"), "test", "sig"},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "tags",
|
||||
event: &nostr.Event{
|
||||
ID: "id",
|
||||
PubKey: "pk",
|
||||
CreatedAt: now,
|
||||
Kind: nostr.KindTextNote,
|
||||
Tags: nostr.Tags{nostr.Tag{"foo", "bar"}},
|
||||
Content: "test",
|
||||
Sig: "sig",
|
||||
},
|
||||
query: `INSERT INTO event (
|
||||
id, pubkey, created_at, kind, tags, content, sig)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
ON CONFLICT (id) DO NOTHING`,
|
||||
params: []any{"id", "pk", now, nostr.KindTextNote, []byte("[[\"foo\",\"bar\"]]"), "test", "sig"},
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
query, params, err := saveEventSql(tt.event)
|
||||
assert.Equal(t, clean(tt.query), clean(query))
|
||||
assert.Equal(t, tt.params, params)
|
||||
assert.Equal(t, tt.err, err)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user