Skip to content

Commit

Permalink
database: fix root event counter (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
ice-dionysos authored Dec 18, 2024
1 parent 3730736 commit 9028c2d
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 20 deletions.
19 changes: 11 additions & 8 deletions database/query/DDL.sql
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ create index if not exists idx_event_tags_id_key_value1_value2 on event_t
create index if not exists idx_event_tags_id_key_value1_value3 on event_tags(event_id, event_tag_key, event_tag_value1, event_tag_value3);
create index if not exists idx_event_tags_id_key_value1_value2_value3 on event_tags(event_id, event_tag_key, event_tag_value1, event_tag_value2, event_tag_value3);
--------
drop trigger if exists trigger_events_after_insert_generate_tags;
create trigger if not exists trigger_events_after_insert_generate_tags
after insert
on events
Expand Down Expand Up @@ -146,9 +147,9 @@ begin
coalesce(value ->> 20,''),
coalesce(value ->> 21,'')
from
(
select subzero_nostr_tag_reorder(coalesce(cast(value as text), '')) as value from json_each(jsonb(new.tags))
) where value ->> 0 is not null
json_each(jsonb(subzero_nostr_tags_reorder(coalesce(new.tags, ''))))
where
value ->> 0 is not null
on conflict do nothing;
end
;
Expand All @@ -163,6 +164,7 @@ begin
end
;
--------
drop trigger if exists trigger_events_after_update_generate_tags;
create trigger if not exists trigger_events_after_update_generate_tags
after update
on events
Expand Down Expand Up @@ -218,9 +220,9 @@ begin
coalesce(value ->> 20,''),
coalesce(value ->> 21,'')
from
(
select subzero_nostr_tag_reorder(coalesce(cast(value as text), '')) as value from json_each(jsonb(new.tags))
) where value ->> 0 is not null
json_each(jsonb(subzero_nostr_tags_reorder(coalesce(new.tags, ''))))
where
value ->> 0 is not null
on conflict do nothing;
end
;
Expand Down Expand Up @@ -358,7 +360,7 @@ begin
json_valid(e.tags) and json_extract(value, '$[0]') = 'e'
)
when e.kind in (1, 6, 16, 30023) and NEW.event_tag_key = 'e' and NEW.event_tag_value3 != '' then
NEW.event_tag_value3 in ('reply', 'root')
((NEW.event_tag_value3 = 'root' AND NEW.event_tag_value5 = '') OR (NEW.event_tag_value3 = 'reply'))
else
true
end
Expand All @@ -385,7 +387,8 @@ begin
and event_counters.reference_id = OLD.event_tag_value1
and event_counters.kind = e.kind
and event_counters.reference_type = case
when e.kind in (1, 6, 16, 30023) and OLD.event_tag_key = 'e' and OLD.event_tag_value3 in ('reply', 'root') then 'reply'
when e.kind in (1, 6, 16, 30023) and OLD.event_tag_key = 'e' and
((OLD.event_tag_value3 = 'root' AND OLD.event_tag_value5 = '') OR (OLD.event_tag_value3 = 'reply')) then OLD.event_tag_value3
when e.kind in (1, 6, 16, 30023) and OLD.event_tag_key = 'q' then 'quote'
when e.kind = 3 and OLD.event_tag_key = 'p' then 'follower'
when e.kind = 7 then e.content
Expand Down
4 changes: 2 additions & 2 deletions database/query/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ func init() {
Pure bool
}{
{
Name: "subzero_nostr_tag_reorder",
Ptr: sqlEventTagReorderJSON,
Name: "subzero_nostr_tags_reorder",
Ptr: sqlEventTagsReorderJSON,
Pure: true,
},
{
Expand Down
32 changes: 27 additions & 5 deletions database/query/client_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,40 @@ func sqlObehalfIsAllowed(masterJsonTags, onBehalfPubkey, masterPubkey string, ki
return model.OnBehalfIsAccessAllowed(tags, onBehalfPubkey, kind, nowUnix)
}

func sqlEventTagReorderJSON(jsonTag string) (string, error) {
var tag model.Tag
func sqlEventTagsReorderJSON(jsonTags string) (string, error) {
const (
replyMarkerIndex = 3 // event_tag_value3.
patchMarkerIndex = 5 // event_tag_value5.
)
var tags model.Tags

if jsonTag == "" {
if jsonTags == "" {
return "[]", nil
}

if err := json.Unmarshal([]byte(jsonTag), &tag); err != nil {
if err := tags.Scan(jsonTags); err != nil {
return "", errors.Wrap(err, "failed to unmarshal tags")
}

data, err := json.Marshal(eventTagsReorder(tag))
hasReply := false
for i := range tags {
tags[i] = eventTagsReorder(tags[i])
hasReply = hasReply || (tags[i].Key() == "e" && len(tags[i]) > replyMarkerIndex && strings.EqualFold(tags[i][replyMarkerIndex], "reply"))
}

if hasReply {
for i := range tags {
if tags[i].Key() == "e" && len(tags[i]) > replyMarkerIndex && strings.EqualFold(tags[i][replyMarkerIndex], "root") {
for len(tags[i]) < (patchMarkerIndex + 1) {
// Fill the missing indexes with empty strings.
tags[i] = append(tags[i], "")
}
tags[i][patchMarkerIndex] = "reply_of_root"
}
}
}

data, err := json.Marshal(tags)

return string(data), errors.Wrap(err, "failed to marshal tags")
}
Expand Down
4 changes: 2 additions & 2 deletions database/query/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ func TestSubZeroEventReorder(t *testing.T) {
defer db.Close()

var result string
err := db.QueryRowContext(context.Background(), `SELECT subzero_nostr_tag_reorder('["imeta", "foo", "bar", "", "m media", "url http://example.com"]')`).
err := db.QueryRowContext(context.Background(), `SELECT subzero_nostr_tags_reorder('[["imeta", "foo", "bar", "", "m media", "url http://example.com"]]')`).
Scan(&result)
require.NoError(t, err)
require.Equal(t, `["imeta","url http://example.com","m media","","bar","foo"]`, result)
require.Equal(t, `[["imeta","url http://example.com","m media","","bar","foo"]]`, result)
}

func TestSubZeroOnBehalfAllowed(t *testing.T) {
Expand Down
72 changes: 72 additions & 0 deletions database/query/query_count_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,75 @@ func TestEventMultiReactions(t *testing.T) {
require.NoError(t, db.AcceptEvents(context.Background(), &deleteEv))
helperMustBePrecalculatedCount(t, db, 0, model.Filter{IDs: []string{ev.ID}, Kinds: []int{nostr.KindReaction}})
}

func TestCounterRootReply(t *testing.T) {
t.Parallel()

db := helperNewDatabase(t)
defer db.Close()

var root model.Event
root.ID = "rootid"
root.Kind = nostr.KindTextNote
root.Content = "root"
root.PubKey = "rootpub"
root.CreatedAt = 1
require.NoError(t, db.AcceptEvents(context.Background(), &root))

var replyToRoot model.Event
replyToRoot.ID = "replytorootid"
replyToRoot.Kind = nostr.KindTextNote
replyToRoot.Content = "reply"
replyToRoot.PubKey = "replypub"
replyToRoot.CreatedAt = 2
replyToRoot.Tags = model.Tags{{"e", "rootid", "", "root"}}
require.NoError(t, db.AcceptEvents(context.Background(), &replyToRoot))

var replyToReply model.Event
replyToReply.ID = "replytoreplyid"
replyToReply.Kind = nostr.KindTextNote
replyToReply.Content = "reply"
replyToReply.PubKey = "replypub"
replyToReply.CreatedAt = 3
replyToReply.Tags = model.Tags{
{"e", "replytorootid", "", "reply"},
{"e", "rootid", "", "root"},
}
require.NoError(t, db.AcceptEvents(context.Background(), &replyToReply))

var replyToReplyToReply model.Event
replyToReplyToReply.ID = "replytoreplytoreplyid"
replyToReplyToReply.Kind = nostr.KindTextNote
replyToReplyToReply.Content = "reply"
replyToReplyToReply.PubKey = "replypub"
replyToReplyToReply.CreatedAt = 4
replyToReplyToReply.Tags = model.Tags{
{"e", "replytoreplyid", "", "reply"},
{"e", "rootid", "", "root"},
}
require.NoError(t, db.AcceptEvents(context.Background(), &replyToReplyToReply))

helperMustBePrecalculatedCount(t, db, 1, model.Filter{IDs: []string{root.ID}})
helperMustBePrecalculatedCount(t, db, 1, model.Filter{IDs: []string{replyToReply.ID}})
helperMustBePrecalculatedCount(t, db, 1, model.Filter{IDs: []string{replyToRoot.ID}})

events := helperSelectEvents(t, db, model.Filter{
Kinds: []int{nostr.KindTextNote, nostr.KindRepost},
Limit: 10,
Search: "references:false expiration:false include:dependencies:kind1>kind6400+kind1+group+root !emarker:reply",
})
require.Len(t, events, 2) // Root + DVM.
require.Equal(t, "rootid", events[0].ID)
require.Equal(t, model.KindDVMCountResponse, events[1].Kind)
require.Equal(t, "1", events[1].Content)

t.Run("Delete", func(t *testing.T) {
var deleteEv model.Event

deleteEv.Kind = nostr.KindDeletion
deleteEv.PubKey = "replypub"
deleteEv.Tags = model.Tags{{"e", replyToRoot.ID}}
require.NoError(t, db.AcceptEvents(context.Background(), &deleteEv))
helperMustBePrecalculatedCount(t, db, 0, model.Filter{IDs: []string{root.ID}})
})
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ require (
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIK
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
Expand Down

0 comments on commit 9028c2d

Please sign in to comment.