Allow searching issues by ID (#31479)
When you are entering a number in the issue search, you likely want the issue with the given ID (code internal concept: issue index). As such, when a number is detected, the issue with the corresponding ID will now be added to the results. Fixes #4479 Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
416c36f303
commit
3571b7e3dd
@ -71,6 +71,12 @@ func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
|
||||
)),
|
||||
),
|
||||
)
|
||||
|
||||
if options.IsKeywordNumeric() {
|
||||
cond = cond.Or(
|
||||
builder.Eq{"`index`": options.Keyword},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
opt, err := ToDBOptions(ctx, options)
|
||||
|
@ -283,9 +283,9 @@ const (
|
||||
func SearchIssues(ctx context.Context, opts *SearchOptions) ([]int64, int64, error) {
|
||||
indexer := *globalIndexer.Load()
|
||||
|
||||
if opts.Keyword == "" {
|
||||
if opts.Keyword == "" || opts.IsKeywordNumeric() {
|
||||
// This is a conservative shortcut.
|
||||
// If the keyword is empty, db has better (at least not worse) performance to filter issues.
|
||||
// If the keyword is empty or an integer, db has better (at least not worse) performance to filter issues.
|
||||
// When the keyword is empty, it tends to listing rather than searching issues.
|
||||
// So if the user creates an issue and list issues immediately, the issue may not be listed because the indexer needs time to index the issue.
|
||||
// Even worse, the external indexer like elastic search may not be available for a while,
|
||||
|
@ -31,6 +31,7 @@ func TestDBSearchIssues(t *testing.T) {
|
||||
InitIssueIndexer(true)
|
||||
|
||||
t.Run("search issues with keyword", searchIssueWithKeyword)
|
||||
t.Run("search issues by index", searchIssueByIndex)
|
||||
t.Run("search issues in repo", searchIssueInRepo)
|
||||
t.Run("search issues by ID", searchIssueByID)
|
||||
t.Run("search issues is pr", searchIssueIsPull)
|
||||
@ -87,6 +88,43 @@ func searchIssueWithKeyword(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func searchIssueByIndex(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts SearchOptions
|
||||
expectedIDs []int64
|
||||
}{
|
||||
{
|
||||
SearchOptions{
|
||||
Keyword: "1000",
|
||||
RepoIDs: []int64{1},
|
||||
},
|
||||
[]int64{},
|
||||
},
|
||||
{
|
||||
SearchOptions{
|
||||
Keyword: "2",
|
||||
RepoIDs: []int64{1, 2, 3, 32},
|
||||
},
|
||||
[]int64{17, 12, 7, 2},
|
||||
},
|
||||
{
|
||||
SearchOptions{
|
||||
Keyword: "1",
|
||||
RepoIDs: []int64{58},
|
||||
},
|
||||
[]int64{19},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||
}
|
||||
}
|
||||
|
||||
func searchIssueInRepo(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts SearchOptions
|
||||
|
@ -4,6 +4,8 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
@ -124,6 +126,12 @@ func (o *SearchOptions) Copy(edit ...func(options *SearchOptions)) *SearchOption
|
||||
return &v
|
||||
}
|
||||
|
||||
// used for optimized issue index based search
|
||||
func (o *SearchOptions) IsKeywordNumeric() bool {
|
||||
_, err := strconv.Atoi(o.Keyword)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
type SortBy string
|
||||
|
||||
const (
|
||||
|
Loading…
Reference in New Issue
Block a user