Skip to content

Commit

Permalink
database: extend expiration filter (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
ice-dionysos authored Dec 2, 2024
1 parent f451e0b commit e4c702d
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 4 deletions.
8 changes: 7 additions & 1 deletion database/query/query_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ func TestQueryFuzzNoUseTempBTREEOrScan(t *testing.T) {

t.Run("Fuzz", func(t *testing.T) {
for i, set := range sets {
sql, params, err := generateSelectEventsSQL(&model.Subscription{Filters: model.Filters{helperNewFilterFromElements(t, set)}}, 0, 100)
filter := helperNewFilterFromElements(t, set)
sql, params, err := generateSelectEventsSQL(&model.Subscription{Filters: model.Filters{filter}}, 0, 100)
require.NoErrorf(t, err, "failed to generate select events sql for set #%d (%#v)", i+1, set)

sql = "EXPLAIN QUERY PLAN " + sql
Expand All @@ -208,6 +209,11 @@ func TestQueryFuzzNoUseTempBTREEOrScan(t *testing.T) {
require.NoError(t, err)
op[s4]++
if s4 == "USE TEMP B-TREE FOR ORDER BY" || (strings.HasPrefix(s4, "SCAN ") && !strings.Contains(s4, "INDEX")) {
if strings.Contains(filter.Search, "Expiration:true") {
// It uses SCAN over CTE, which is expected.
continue
}
t.Logf("filter: %#v", filter)
t.Logf("set #%d: %s (%+v)", i+1, sql, params)
t.Log(s1, s2, s3, s4)
t.FailNow()
Expand Down
11 changes: 10 additions & 1 deletion database/query/query_where_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ func (w *whereBuilder) createWhereForDepFilter(filterID, cteName, field string,
}

func (w *whereBuilder) applyDepFilter(filterID, cteName string, filter *filterDependencies) {
if filter.Reduce.Kinds[0] == model.KindDVMCountResponse {
if len(filter.Reduce.Kinds) > 0 && filter.Reduce.Kinds[0] == model.KindDVMCountResponse {
w.WriteString(`
union all
select
Expand Down Expand Up @@ -572,6 +572,15 @@ where
w.WriteString(`) AND `)
}

if filter.Expiration != nil && *filter.Expiration {
w.WriteString(`e.master_pubkey IN (select master_pubkey from ` + cteName + `)
and e.hidden=0
and e.kind in (1, 30023)
and exists (select true from event_tags where event_id = e.id and event_tag_key = 'expiration' and cast(` + tagValueExpiration + ` as integer) > unixepoch())`)

return
}

switch filter.Reduce.Kinds[0] {
case nostr.KindTextNote, nostr.KindRepost, nostr.KindReaction, nostr.KindArticle, nostr.KindGenericRepost:
w.WriteString("e.kind = :")
Expand Down
6 changes: 6 additions & 0 deletions database/query/query_where_builder_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ func parseNostrFilter(filter model.Filter) (*databaseFilterSearch, error) {
return nil, err
}

if f.Expiration != nil && *f.Expiration {
f.Dependencies = append(f.Dependencies, &filterDependencies{
Expiration: f.Expiration,
})
}

f.Search = strings.TrimSpace(f.Search)

return f, nil
Expand Down
5 changes: 3 additions & 2 deletions database/query/query_where_dependencies_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ type (
}

filterDependencies struct {
Start filterDependenciesStart
Reduce filterDependenciesReduce
Start filterDependenciesStart
Reduce filterDependenciesReduce
Expiration *bool
}

filterSequence struct {
Expand Down
73 changes: 73 additions & 0 deletions database/query/query_where_dependencies_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ package query
import (
"context"
"encoding/json"
"strconv"
"testing"
"time"

"github.com/nbd-wtf/go-nostr"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -678,3 +680,74 @@ func TestSelectWithDependencies(t *testing.T) {
})
})
}

func TestSelectExpirationWithDependencies(t *testing.T) {
t.Parallel()
db := helperNewDatabase(t)
defer db.Close()

now := time.Now().Unix()
expiration := strconv.FormatInt(now+3600, 10)

t.Run("Insert", func(t *testing.T) {
require.NoError(t, db.AcceptEvents(context.Background(),
&model.Event{
Event: nostr.Event{
ID: "t1id1",
PubKey: "t1pk1",
Content: "content1",
Kind: nostr.KindTextNote,
CreatedAt: 1,
Tags: model.Tags{{"expiration", expiration}},
},
},
&model.Event{
Event: nostr.Event{
ID: "t1id2",
PubKey: "t1pk2",
Content: "content2",
Kind: nostr.KindTextNote,
CreatedAt: 2,
Tags: model.Tags{{"expiration", expiration}},
},
},
&model.Event{
Event: nostr.Event{
ID: "t1id3",
PubKey: "t1pk2",
Content: "content3",
Kind: nostr.KindTextNote,
CreatedAt: 3,
Tags: model.Tags{{"expiration", expiration}},
},
},
&model.Event{
Event: nostr.Event{
ID: "t1id4",
PubKey: "t1pk4",
Content: "content4",
Kind: nostr.KindTextNote,
CreatedAt: 4,
Tags: model.Tags{{"expiration", expiration}},
},
},
&model.Event{
Event: nostr.Event{
ID: "t1id5",
PubKey: "t1pk1",
Content: "content5",
Kind: nostr.KindTextNote,
CreatedAt: 5,
Tags: model.Tags{{"expiration", expiration}},
},
},
))
})

events := helperSelectEvents(t, db, model.Filter{Limit: 2, Search: "expiration:true"})
require.Len(t, events, 3) // main: (t1pk1 + t1pk4) + dep: (t1pk1 / t1id1).
for i, pubkey := range []string{"t1pk1", "t1pk4", "t1pk1"} {
t.Logf("event %d: %+v", i, events[i])
require.Equal(t, pubkey, events[i].PubKey)
}
}

0 comments on commit e4c702d

Please sign in to comment.