feat: filter thread listings
This commit is contained in:
parent
6967963729
commit
931aa91214
@ -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:
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user