@@ -13,6 +13,7 @@ import (
13
13
14
14
db_model "code.gitea.io/gitea/models/db"
15
15
repo_model "code.gitea.io/gitea/models/repo"
16
+ "code.gitea.io/gitea/modules/container"
16
17
"code.gitea.io/gitea/modules/graceful"
17
18
"code.gitea.io/gitea/modules/indexer/issues/bleve"
18
19
"code.gitea.io/gitea/modules/indexer/issues/db"
@@ -277,7 +278,7 @@ func IsAvailable(ctx context.Context) bool {
277
278
}
278
279
279
280
// SearchOptions indicates the options for searching issues
280
- type SearchOptions internal.SearchOptions
281
+ type SearchOptions = internal.SearchOptions
281
282
282
283
const (
283
284
SortByCreatedDesc = internal .SortByCreatedDesc
@@ -291,7 +292,6 @@ const (
291
292
)
292
293
293
294
// SearchIssues search issues by options.
294
- // It returns issue ids and a bool value indicates if the result is imprecise.
295
295
func SearchIssues (ctx context.Context , opts * SearchOptions ) ([]int64 , int64 , error ) {
296
296
indexer := * globalIndexer .Load ()
297
297
@@ -305,7 +305,7 @@ func SearchIssues(ctx context.Context, opts *SearchOptions) ([]int64, int64, err
305
305
indexer = db .NewIndexer ()
306
306
}
307
307
308
- result , err := indexer .Search (ctx , ( * internal . SearchOptions )( opts ) )
308
+ result , err := indexer .Search (ctx , opts )
309
309
if err != nil {
310
310
return nil , 0 , err
311
311
}
@@ -317,3 +317,38 @@ func SearchIssues(ctx context.Context, opts *SearchOptions) ([]int64, int64, err
317
317
318
318
return ret , result .Total , nil
319
319
}
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