feat: filter thread listings

This commit is contained in:
Vincent Koc 2026-04-26 23:54:38 -07:00
parent 6967963729
commit 931aa91214
No known key found for this signature in database
3 changed files with 68 additions and 5 deletions

View File

@ -252,8 +252,10 @@ func (a *App) runThreads(ctx context.Context, args []string) error {
fs := flag.NewFlagSet("threads", flag.ContinueOnError)
fs.SetOutput(io.Discard)
includeClosed := fs.Bool("include-closed", false, "include locally closed rows")
numbersRaw := fs.String("numbers", "", "comma-separated issue or pull request numbers")
limitRaw := fs.String("limit", "", "maximum thread rows")
jsonOut := fs.Bool("json", false, "write JSON output")
if err := fs.Parse(normalizeCommandArgs(args, nil)); err != nil {
if err := fs.Parse(normalizeCommandArgs(args, map[string]bool{"numbers": true, "limit": true})); err != nil {
return usageErr(err)
}
a.applyCommandJSON(*jsonOut)
@ -264,6 +266,14 @@ func (a *App) runThreads(ctx context.Context, args []string) error {
if err != nil {
return usageErr(err)
}
numbers, err := parseOptionalPositiveIntList(*numbersRaw)
if err != nil {
return usageErr(err)
}
limit, err := parseOptionalPositiveInt(*limitRaw)
if err != nil {
return usageErr(err)
}
cfg, err := config.Load(a.configPath)
if err != nil {
@ -279,7 +289,12 @@ func (a *App) runThreads(ctx context.Context, args []string) error {
if err != nil {
return err
}
threads, err := st.ListThreads(ctx, repo.ID, *includeClosed)
threads, err := st.ListThreadsFiltered(ctx, store.ThreadListOptions{
RepoID: repo.ID,
IncludeClosed: *includeClosed,
Numbers: numbers,
Limit: limit,
})
if err != nil {
return err
}
@ -482,6 +497,22 @@ func parseOptionalPositiveInt(value string) (int, error) {
return parsed, nil
}
func parseOptionalPositiveIntList(value string) ([]int, error) {
if strings.TrimSpace(value) == "" {
return nil, nil
}
parts := strings.Split(value, ",")
out := make([]int, 0, len(parts))
for _, part := range parts {
parsed, err := parseOptionalPositiveInt(strings.TrimSpace(part))
if err != nil {
return nil, err
}
out = append(out, parsed)
}
return out, nil
}
func (a *App) writeOutput(title string, payload any, allowLog bool) error {
switch a.format {
case FormatJSON:

View File

@ -53,4 +53,11 @@ func TestUpsertRepositoryAndThread(t *testing.T) {
if len(rows) != 1 || rows[0].Title != "download stalls" {
t.Fatalf("unexpected rows: %#v", rows)
}
filtered, err := st.ListThreadsFiltered(ctx, ThreadListOptions{RepoID: repoID, Numbers: []int{1}, Limit: 1})
if err != nil {
t.Fatalf("filtered threads: %v", err)
}
if len(filtered) != 1 || filtered[0].Number != 1 {
t.Fatalf("unexpected filtered rows: %#v", filtered)
}
}

View File

@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"fmt"
"strings"
)
type Thread struct {
@ -76,10 +77,35 @@ func (s *Store) UpsertThread(ctx context.Context, thread Thread) (int64, error)
}
func (s *Store) ListThreads(ctx context.Context, repoID int64, includeClosed bool) ([]Thread, error) {
return s.ListThreadsFiltered(ctx, ThreadListOptions{RepoID: repoID, IncludeClosed: includeClosed})
}
type ThreadListOptions struct {
RepoID int64
IncludeClosed bool
Numbers []int
Limit int
}
func (s *Store) ListThreadsFiltered(ctx context.Context, options ThreadListOptions) ([]Thread, error) {
where := `repo_id = ?`
if !includeClosed {
args := []any{options.RepoID}
if !options.IncludeClosed {
where += ` and closed_at_local is null`
}
if len(options.Numbers) > 0 {
placeholders := make([]string, 0, len(options.Numbers))
for _, number := range options.Numbers {
placeholders = append(placeholders, "?")
args = append(args, number)
}
where += ` and number in (` + strings.Join(placeholders, ",") + `)`
}
limitSQL := ``
if options.Limit > 0 {
limitSQL = ` limit ?`
args = append(args, options.Limit)
}
rows, err := s.db.QueryContext(ctx, `
select id, repo_id, github_id, number, kind, state, title, body, author_login, author_type,
html_url, labels_json, assignees_json, raw_json, content_hash, is_draft,
@ -87,8 +113,7 @@ func (s *Store) ListThreads(ctx context.Context, repoID int64, includeClosed boo
first_pulled_at, last_pulled_at, updated_at, closed_at_local, close_reason_local
from threads
where `+where+`
order by number
`, repoID)
order by number`+limitSQL, args...)
if err != nil {
return nil, fmt.Errorf("list threads: %w", err)
}