diff --git a/storage/postgresql/init.go b/storage/postgresql/init.go index edc8c89..1bd6cdc 100644 --- a/storage/postgresql/init.go +++ b/storage/postgresql/init.go @@ -46,5 +46,9 @@ CREATE INDEX IF NOT EXISTS timeidx ON event (created_at DESC); CREATE INDEX IF NOT EXISTS kindidx ON event (kind); CREATE INDEX IF NOT EXISTS arbitrarytagvalues ON event USING gin (tagvalues); `) + + if b.QueryLimit < 1 { + b.QueryLimit = 100 + } return err } diff --git a/storage/postgresql/postgresql.go b/storage/postgresql/postgresql.go index aa55ddc..9329b45 100644 --- a/storage/postgresql/postgresql.go +++ b/storage/postgresql/postgresql.go @@ -7,4 +7,5 @@ import ( type PostgresBackend struct { *sqlx.DB DatabaseURL string + QueryLimit int } diff --git a/storage/postgresql/query.go b/storage/postgresql/query.go index 4798076..b949d2f 100644 --- a/storage/postgresql/query.go +++ b/storage/postgresql/query.go @@ -15,7 +15,7 @@ import ( func (b PostgresBackend) QueryEvents(ctx context.Context, filter *nostr.Filter) (ch chan *nostr.Event, err error) { ch = make(chan *nostr.Event) - query, params, err := queryEventsSql(filter, false) + query, params, err := b.queryEventsSql(filter, false) if err != nil { return nil, err } @@ -45,7 +45,7 @@ func (b PostgresBackend) QueryEvents(ctx context.Context, filter *nostr.Filter) } func (b PostgresBackend) CountEvents(ctx context.Context, filter *nostr.Filter) (int64, error) { - query, params, err := queryEventsSql(filter, true) + query, params, err := b.queryEventsSql(filter, true) if err != nil { return 0, err } @@ -57,7 +57,7 @@ func (b PostgresBackend) CountEvents(ctx context.Context, filter *nostr.Filter) return count, nil } -func queryEventsSql(filter *nostr.Filter, doCount bool) (string, []any, error) { +func (b PostgresBackend) queryEventsSql(filter *nostr.Filter, doCount bool) (string, []any, error) { var conditions []string var params []any @@ -172,8 +172,8 @@ func queryEventsSql(filter *nostr.Filter, doCount bool) (string, []any, error) { conditions = append(conditions, "true") } - if filter.Limit < 1 || filter.Limit > 100 { - params = append(params, 100) + if filter.Limit < 1 || filter.Limit > b.QueryLimit { + params = append(params, b.QueryLimit) } else { params = append(params, filter.Limit) } diff --git a/storage/postgresql/query_test.go b/storage/postgresql/query_test.go index 226acbd..9c8c08d 100644 --- a/storage/postgresql/query_test.go +++ b/storage/postgresql/query_test.go @@ -12,21 +12,52 @@ import ( func TestQueryEventsSql(t *testing.T) { var tests = []struct { - name string - filter *nostr.Filter - query string - params []any - err error + name string + backend PostgresBackend + filter *nostr.Filter + query string + params []any + err error }{ { - name: "empty filter", - filter: &nostr.Filter{}, + name: "empty filter", + backend: PostgresBackend{QueryLimit: 100}, + filter: &nostr.Filter{}, + query: "SELECT id, pubkey, created_at, kind, tags, content, sig FROM event WHERE true ORDER BY created_at DESC LIMIT $1", + params: []any{100}, + err: nil, + }, + { + name: "large query limit", + backend: PostgresBackend{QueryLimit: 1000}, + filter: &nostr.Filter{}, + query: "SELECT id, pubkey, created_at, kind, tags, content, sig FROM event WHERE true ORDER BY created_at DESC LIMIT $1", + params: []any{1000}, + err: nil, + }, + { + name: "valid filter limit", + backend: PostgresBackend{QueryLimit: 100}, + filter: &nostr.Filter{ + Limit: 50, + }, + query: "SELECT id, pubkey, created_at, kind, tags, content, sig FROM event WHERE true ORDER BY created_at DESC LIMIT $1", + params: []any{50}, + err: nil, + }, + { + name: "too large filter limit", + backend: PostgresBackend{QueryLimit: 100}, + filter: &nostr.Filter{ + Limit: 2000, + }, query: "SELECT id, pubkey, created_at, kind, tags, content, sig FROM event WHERE true ORDER BY created_at DESC LIMIT $1", params: []any{100}, err: nil, }, { - name: "ids filter", + name: "ids filter", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ IDs: []string{"083ec57f36a7b39ab98a57bedab4f85355b2ee89e4b205bed58d7c3ef9edd294"}, }, @@ -38,7 +69,8 @@ func TestQueryEventsSql(t *testing.T) { err: nil, }, { - name: "kind filter", + name: "kind filter", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Kinds: []int{1, 2, 3}, }, @@ -50,7 +82,8 @@ func TestQueryEventsSql(t *testing.T) { err: nil, }, { - name: "authors filter", + name: "authors filter", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Authors: []string{"7bdef7bdebb8721f77927d0e77c66059360fa62371fdf15f3add93923a613229"}, }, @@ -63,14 +96,16 @@ func TestQueryEventsSql(t *testing.T) { }, // errors { - name: "nil filter", - filter: nil, - query: "", - params: nil, - err: fmt.Errorf("filter cannot be null"), + name: "nil filter", + backend: PostgresBackend{QueryLimit: 100}, + filter: nil, + query: "", + params: nil, + err: fmt.Errorf("filter cannot be null"), }, { - name: "too many ids", + name: "too many ids", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ IDs: strSlice(501), }, @@ -80,7 +115,8 @@ func TestQueryEventsSql(t *testing.T) { err: nil, }, { - name: "invalid ids", + name: "invalid ids", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ IDs: []string{"stuff"}, }, @@ -90,7 +126,8 @@ func TestQueryEventsSql(t *testing.T) { err: nil, }, { - name: "too many authors", + name: "too many authors", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Authors: strSlice(501), }, @@ -100,7 +137,8 @@ func TestQueryEventsSql(t *testing.T) { err: nil, }, { - name: "invalid authors", + name: "invalid authors", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Authors: []string{"stuff"}, }, @@ -110,7 +148,8 @@ func TestQueryEventsSql(t *testing.T) { err: nil, }, { - name: "too many kinds", + name: "too many kinds", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Kinds: intSlice(11), }, @@ -120,7 +159,8 @@ func TestQueryEventsSql(t *testing.T) { err: nil, }, { - name: "no kinds", + name: "no kinds", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Kinds: []int{}, }, @@ -130,7 +170,8 @@ func TestQueryEventsSql(t *testing.T) { err: nil, }, { - name: "tags of empty array", + name: "tags of empty array", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Tags: nostr.TagMap{ "#e": []string{}, @@ -142,7 +183,8 @@ func TestQueryEventsSql(t *testing.T) { err: nil, }, { - name: "too many tag values", + name: "too many tag values", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Tags: nostr.TagMap{ "#e": strSlice(11), @@ -157,7 +199,7 @@ func TestQueryEventsSql(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - query, params, err := queryEventsSql(tt.filter, false) + query, params, err := tt.backend.queryEventsSql(tt.filter, false) assert.Equal(t, tt.err, err) if err != nil { return @@ -191,21 +233,24 @@ func strSlice(n int) []string { func TestCountEventsSql(t *testing.T) { var tests = []struct { - name string - filter *nostr.Filter - query string - params []any - err error + name string + backend PostgresBackend + filter *nostr.Filter + query string + params []any + err error }{ { - name: "empty filter", - filter: &nostr.Filter{}, - query: "SELECT COUNT(*) FROM event WHERE true ORDER BY created_at DESC LIMIT $1", - params: []any{100}, - err: nil, + name: "empty filter", + backend: PostgresBackend{QueryLimit: 100}, + filter: &nostr.Filter{}, + query: "SELECT COUNT(*) FROM event WHERE true ORDER BY created_at DESC LIMIT $1", + params: []any{100}, + err: nil, }, { - name: "ids filter", + name: "ids filter", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ IDs: []string{"083ec57f36a7b39ab98a57bedab4f85355b2ee89e4b205bed58d7c3ef9edd294"}, }, @@ -217,7 +262,8 @@ func TestCountEventsSql(t *testing.T) { err: nil, }, { - name: "kind filter", + name: "kind filter", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Kinds: []int{1, 2, 3}, }, @@ -229,7 +275,8 @@ func TestCountEventsSql(t *testing.T) { err: nil, }, { - name: "authors filter", + name: "authors filter", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Authors: []string{"7bdef7bdebb8721f77927d0e77c66059360fa62371fdf15f3add93923a613229"}, }, @@ -242,14 +289,16 @@ func TestCountEventsSql(t *testing.T) { }, // errors { - name: "nil filter", - filter: nil, - query: "", - params: nil, - err: fmt.Errorf("filter cannot be null"), + name: "nil filter", + backend: PostgresBackend{QueryLimit: 100}, + filter: nil, + query: "", + params: nil, + err: fmt.Errorf("filter cannot be null"), }, { - name: "too many ids", + name: "too many ids", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ IDs: strSlice(501), }, @@ -259,7 +308,8 @@ func TestCountEventsSql(t *testing.T) { err: nil, }, { - name: "invalid ids", + name: "invalid ids", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ IDs: []string{"stuff"}, }, @@ -269,7 +319,8 @@ func TestCountEventsSql(t *testing.T) { err: nil, }, { - name: "too many authors", + name: "too many authors", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Authors: strSlice(501), }, @@ -279,7 +330,8 @@ func TestCountEventsSql(t *testing.T) { err: nil, }, { - name: "invalid authors", + name: "invalid authors", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Authors: []string{"stuff"}, }, @@ -289,7 +341,8 @@ func TestCountEventsSql(t *testing.T) { err: nil, }, { - name: "too many kinds", + name: "too many kinds", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Kinds: intSlice(11), }, @@ -299,7 +352,8 @@ func TestCountEventsSql(t *testing.T) { err: nil, }, { - name: "no kinds", + name: "no kinds", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Kinds: []int{}, }, @@ -309,7 +363,8 @@ func TestCountEventsSql(t *testing.T) { err: nil, }, { - name: "tags of empty array", + name: "tags of empty array", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Tags: nostr.TagMap{ "#e": []string{}, @@ -321,7 +376,8 @@ func TestCountEventsSql(t *testing.T) { err: nil, }, { - name: "too many tag values", + name: "too many tag values", + backend: PostgresBackend{QueryLimit: 100}, filter: &nostr.Filter{ Tags: nostr.TagMap{ "#e": strSlice(11), @@ -336,7 +392,7 @@ func TestCountEventsSql(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - query, params, err := queryEventsSql(tt.filter, true) + query, params, err := tt.backend.queryEventsSql(tt.filter, true) assert.Equal(t, tt.err, err) if err != nil { return