@@ -13,6 +13,7 @@ import (
1313
1414 db_model "code.gitea.io/gitea/models/db"
1515 repo_model "code.gitea.io/gitea/models/repo"
16+ "code.gitea.io/gitea/modules/container"
1617 "code.gitea.io/gitea/modules/graceful"
1718 "code.gitea.io/gitea/modules/indexer/issues/bleve"
1819 "code.gitea.io/gitea/modules/indexer/issues/db"
@@ -277,7 +278,7 @@ func IsAvailable(ctx context.Context) bool {
277278}
278279
279280// SearchOptions indicates the options for searching issues
280- type SearchOptions internal.SearchOptions
281+ type SearchOptions = internal.SearchOptions
281282
282283const (
283284 SortByCreatedDesc = internal .SortByCreatedDesc
@@ -291,7 +292,6 @@ const (
291292)
292293
293294// SearchIssues search issues by options.
294- // It returns issue ids and a bool value indicates if the result is imprecise.
295295func SearchIssues (ctx context.Context , opts * SearchOptions ) ([]int64 , int64 , error ) {
296296 indexer := * globalIndexer .Load ()
297297
@@ -305,7 +305,7 @@ func SearchIssues(ctx context.Context, opts *SearchOptions) ([]int64, int64, err
305305 indexer = db .NewIndexer ()
306306 }
307307
308- result , err := indexer .Search (ctx , ( * internal . SearchOptions )( opts ) )
308+ result , err := indexer .Search (ctx , opts )
309309 if err != nil {
310310 return nil , 0 , err
311311 }
@@ -317,3 +317,38 @@ func SearchIssues(ctx context.Context, opts *SearchOptions) ([]int64, int64, err
317317
318318 return ret , result .Total , nil
319319}
320+
321+ // CountIssues counts issues by options. It is a shortcut of SearchIssues(ctx, opts) but only returns the total count.
322+ func CountIssues (ctx context.Context , opts * SearchOptions ) (int64 , error ) {
323+ opts = opts .Copy (func (options * SearchOptions ) { opts .Paginator = & db_model.ListOptions {PageSize : 0 } })
324+
325+ _ , total , err := SearchIssues (ctx , opts )
326+ return total , err
327+ }
328+
329+ // CountIssuesByRepo counts issues by options and group by repo id.
330+ // It's not a complete implementation, since it requires the caller should provide the repo ids.
331+ // That means opts.RepoIDs must be specified, and opts.AllPublic must be false.
332+ // It's good enough for the current usage, and it can be improved if needed.
333+ // TODO: use "group by" of the indexer engines to implement it.
334+ func CountIssuesByRepo (ctx context.Context , opts * SearchOptions ) (map [int64 ]int64 , error ) {
335+ if len (opts .RepoIDs ) == 0 {
336+ return nil , fmt .Errorf ("opts.RepoIDs must be specified" )
337+ }
338+ if opts .AllPublic {
339+ return nil , fmt .Errorf ("opts.AllPublic must be false" )
340+ }
341+
342+ repoIDs := container .SetOf (opts .RepoIDs ... ).Values ()
343+ ret := make (map [int64 ]int64 , len (repoIDs ))
344+ // TODO: it could be faster if do it in parallel for some indexer engines. Improve it if users report it's slow.
345+ for _ , repoID := range repoIDs {
346+ count , err := CountIssues (ctx , opts .Copy (func (o * internal.SearchOptions ) { o .RepoIDs = []int64 {repoID } }))
347+ if err != nil {
348+ return nil , err
349+ }
350+ ret [repoID ] = count
351+ }
352+
353+ return ret , nil
354+ }
0 commit comments