Skip to content

Commit 8ce1b53

Browse files
authored
Use conditions but not repo ids as query condition (#16839)
* Use conditions but not repo ids as query condition * Improve the performance of pulls/issue * Remove duplicated code * fix lint * Fix bug * Fix stats * More fixes * Fix build * Fix lint * Fix test * Fix build * Adjust the logic * Merge * Fix conflicts * improve the performance * Add comments for the query conditions functions * Some improvements
1 parent 8fa97a2 commit 8ce1b53

File tree

11 files changed

+397
-423
lines changed

11 files changed

+397
-423
lines changed

models/issue.go

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,9 @@ type IssuesOptions struct {
11861186
// prioritize issues from this repo
11871187
PriorityRepoID int64
11881188
IsArchived util.OptionalBool
1189+
Org *Organization // issues permission scope
1190+
Team *Team // issues permission scope
1191+
User *user_model.User // issues permission scope
11891192
}
11901193

11911194
// sortIssuesSession sort an issues-related session based on the provided
@@ -1337,6 +1340,44 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
13371340
From("milestone").
13381341
Where(builder.In("name", opts.IncludeMilestones)))
13391342
}
1343+
1344+
if opts.User != nil {
1345+
sess.And(
1346+
issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue()),
1347+
)
1348+
}
1349+
}
1350+
1351+
// issuePullAccessibleRepoCond userID must not be zero, this condition require join repository table
1352+
func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *Organization, team *Team, isPull bool) builder.Cond {
1353+
var cond = builder.NewCond()
1354+
var unitType = unit.TypeIssues
1355+
if isPull {
1356+
unitType = unit.TypePullRequests
1357+
}
1358+
if org != nil {
1359+
if team != nil {
1360+
cond = cond.And(teamUnitsRepoCond(repoIDstr, userID, org.ID, team.ID, unitType)) // special team member repos
1361+
} else {
1362+
cond = cond.And(
1363+
builder.Or(
1364+
userOrgUnitRepoCond(repoIDstr, userID, org.ID, unitType), // team member repos
1365+
userOrgPublicUnitRepoCond(userID, org.ID), // user org public non-member repos, TODO: check repo has issues
1366+
),
1367+
)
1368+
}
1369+
} else {
1370+
cond = cond.And(
1371+
builder.Or(
1372+
userOwnedRepoCond(userID), // owned repos
1373+
userCollaborationRepoCond(repoIDstr, userID), // collaboration repos
1374+
userAssignedRepoCond(repoIDstr, userID), // user has been assigned accessible public repos
1375+
userMentionedRepoCond(repoIDstr, userID), // user has been mentioned accessible public repos
1376+
userCreateIssueRepoCond(repoIDstr, userID, isPull), // user has created issue/pr accessible public repos
1377+
),
1378+
)
1379+
}
1380+
return cond
13401381
}
13411382

13421383
func applyReposCondition(sess *xorm.Session, repoIDs []int64) *xorm.Session {
@@ -1646,15 +1687,16 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats,
16461687

16471688
// UserIssueStatsOptions contains parameters accepted by GetUserIssueStats.
16481689
type UserIssueStatsOptions struct {
1649-
UserID int64
1650-
RepoIDs []int64
1651-
UserRepoIDs []int64
1652-
FilterMode int
1653-
IsPull bool
1654-
IsClosed bool
1655-
IssueIDs []int64
1656-
IsArchived util.OptionalBool
1657-
LabelIDs []int64
1690+
UserID int64
1691+
RepoIDs []int64
1692+
FilterMode int
1693+
IsPull bool
1694+
IsClosed bool
1695+
IssueIDs []int64
1696+
IsArchived util.OptionalBool
1697+
LabelIDs []int64
1698+
Org *Organization
1699+
Team *Team
16581700
}
16591701

16601702
// GetUserIssueStats returns issue statistic information for dashboard by given conditions.
@@ -1671,28 +1713,34 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
16711713
cond = cond.And(builder.In("issue.id", opts.IssueIDs))
16721714
}
16731715

1716+
if opts.UserID > 0 {
1717+
cond = cond.And(issuePullAccessibleRepoCond("issue.repo_id", opts.UserID, opts.Org, opts.Team, opts.IsPull))
1718+
}
1719+
16741720
sess := func(cond builder.Cond) *xorm.Session {
16751721
s := db.GetEngine(db.DefaultContext).Where(cond)
16761722
if len(opts.LabelIDs) > 0 {
16771723
s.Join("INNER", "issue_label", "issue_label.issue_id = issue.id").
16781724
In("issue_label.label_id", opts.LabelIDs)
16791725
}
1680-
if opts.IsArchived != util.OptionalBoolNone {
1681-
s.Join("INNER", "repository", "issue.repo_id = repository.id").
1682-
And(builder.Eq{"repository.is_archived": opts.IsArchived.IsTrue()})
1726+
if opts.UserID > 0 || opts.IsArchived != util.OptionalBoolNone {
1727+
s.Join("INNER", "repository", "issue.repo_id = repository.id")
1728+
if opts.IsArchived != util.OptionalBoolNone {
1729+
s.And(builder.Eq{"repository.is_archived": opts.IsArchived.IsTrue()})
1730+
}
16831731
}
16841732
return s
16851733
}
16861734

16871735
switch opts.FilterMode {
16881736
case FilterModeAll:
1689-
stats.OpenCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).
1737+
stats.OpenCount, err = sess(cond).
16901738
And("issue.is_closed = ?", false).
16911739
Count(new(Issue))
16921740
if err != nil {
16931741
return nil, err
16941742
}
1695-
stats.ClosedCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).
1743+
stats.ClosedCount, err = sess(cond).
16961744
And("issue.is_closed = ?", true).
16971745
Count(new(Issue))
16981746
if err != nil {
@@ -1768,7 +1816,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
17681816
return nil, err
17691817
}
17701818

1771-
stats.YourRepositoriesCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).Count(new(Issue))
1819+
stats.YourRepositoriesCount, err = sess(cond).Count(new(Issue))
17721820
if err != nil {
17731821
return nil, err
17741822
}

models/issue_list.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ const (
2525
func (issues IssueList) getRepoIDs() []int64 {
2626
repoIDs := make(map[int64]struct{}, len(issues))
2727
for _, issue := range issues {
28+
if issue.Repo != nil {
29+
continue
30+
}
2831
if _, ok := repoIDs[issue.RepoID]; !ok {
2932
repoIDs[issue.RepoID] = struct{}{}
3033
}
@@ -56,8 +59,12 @@ func (issues IssueList) loadRepositories(e db.Engine) ([]*repo_model.Repository,
5659
}
5760

5861
for _, issue := range issues {
59-
issue.Repo = repoMaps[issue.RepoID]
60-
if issue.PullRequest != nil {
62+
if issue.Repo == nil {
63+
issue.Repo = repoMaps[issue.RepoID]
64+
} else {
65+
repoMaps[issue.RepoID] = issue.Repo
66+
}
67+
if issue.PullRequest != nil && issue.PullRequest.BaseRepo == nil {
6168
issue.PullRequest.BaseRepo = issue.Repo
6269
}
6370
}

models/issue_test.go

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -206,52 +206,52 @@ func TestGetUserIssueStats(t *testing.T) {
206206
FilterMode: FilterModeAll,
207207
},
208208
IssueStats{
209-
YourRepositoriesCount: 0,
210-
AssignCount: 1,
211-
CreateCount: 1,
212-
OpenCount: 0,
213-
ClosedCount: 0,
209+
YourRepositoriesCount: 1, // 6
210+
AssignCount: 1, // 6
211+
CreateCount: 1, // 6
212+
OpenCount: 1, // 6
213+
ClosedCount: 1, // 1
214214
},
215215
},
216216
{
217217
UserIssueStatsOptions{
218218
UserID: 1,
219-
FilterMode: FilterModeAssign,
219+
RepoIDs: []int64{1},
220+
FilterMode: FilterModeAll,
221+
IsClosed: true,
220222
},
221223
IssueStats{
222-
YourRepositoriesCount: 0,
223-
AssignCount: 2,
224-
CreateCount: 2,
225-
OpenCount: 2,
226-
ClosedCount: 0,
224+
YourRepositoriesCount: 1, // 6
225+
AssignCount: 0,
226+
CreateCount: 0,
227+
OpenCount: 1, // 6
228+
ClosedCount: 1, // 1
227229
},
228230
},
229231
{
230232
UserIssueStatsOptions{
231233
UserID: 1,
232-
FilterMode: FilterModeCreate,
234+
FilterMode: FilterModeAssign,
233235
},
234236
IssueStats{
235-
YourRepositoriesCount: 0,
236-
AssignCount: 2,
237-
CreateCount: 2,
238-
OpenCount: 2,
237+
YourRepositoriesCount: 1, // 6
238+
AssignCount: 1, // 6
239+
CreateCount: 1, // 6
240+
OpenCount: 1, // 6
239241
ClosedCount: 0,
240242
},
241243
},
242244
{
243245
UserIssueStatsOptions{
244-
UserID: 2,
245-
UserRepoIDs: []int64{1, 2},
246-
FilterMode: FilterModeAll,
247-
IsClosed: true,
246+
UserID: 1,
247+
FilterMode: FilterModeCreate,
248248
},
249249
IssueStats{
250-
YourRepositoriesCount: 2,
251-
AssignCount: 0,
252-
CreateCount: 2,
253-
OpenCount: 2,
254-
ClosedCount: 2,
250+
YourRepositoriesCount: 1, // 6
251+
AssignCount: 1, // 6
252+
CreateCount: 1, // 6
253+
OpenCount: 1, // 6
254+
ClosedCount: 0,
255255
},
256256
},
257257
{
@@ -260,9 +260,10 @@ func TestGetUserIssueStats(t *testing.T) {
260260
FilterMode: FilterModeMention,
261261
},
262262
IssueStats{
263-
YourRepositoriesCount: 0,
264-
AssignCount: 2,
265-
CreateCount: 2,
263+
YourRepositoriesCount: 1, // 6
264+
AssignCount: 1, // 6
265+
CreateCount: 1, // 6
266+
MentionCount: 0,
266267
OpenCount: 0,
267268
ClosedCount: 0,
268269
},
@@ -274,19 +275,21 @@ func TestGetUserIssueStats(t *testing.T) {
274275
IssueIDs: []int64{1},
275276
},
276277
IssueStats{
277-
YourRepositoriesCount: 0,
278-
AssignCount: 1,
279-
CreateCount: 1,
280-
OpenCount: 1,
278+
YourRepositoriesCount: 1, // 1
279+
AssignCount: 1, // 1
280+
CreateCount: 1, // 1
281+
OpenCount: 1, // 1
281282
ClosedCount: 0,
282283
},
283284
},
284285
} {
285-
stats, err := GetUserIssueStats(test.Opts)
286-
if !assert.NoError(t, err) {
287-
continue
288-
}
289-
assert.Equal(t, test.ExpectedIssueStats, *stats)
286+
t.Run(fmt.Sprintf("%#v", test.Opts), func(t *testing.T) {
287+
stats, err := GetUserIssueStats(test.Opts)
288+
if !assert.NoError(t, err) {
289+
return
290+
}
291+
assert.Equal(t, test.ExpectedIssueStats, *stats)
292+
})
290293
}
291294
}
292295

models/repo/repo.go

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -731,15 +731,6 @@ func CountUserRepositories(userID int64, private bool) int64 {
731731
return countRepositories(userID, private)
732732
}
733733

734-
// GetUserMirrorRepositories returns a list of mirror repositories of given user.
735-
func GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
736-
repos := make([]*Repository, 0, 10)
737-
return repos, db.GetEngine(db.DefaultContext).
738-
Where("owner_id = ?", userID).
739-
And("is_mirror = ?", true).
740-
Find(&repos)
741-
}
742-
743734
func getRepositoryCount(e db.Engine, ownerID int64) (int64, error) {
744735
return e.Count(&Repository{OwnerID: ownerID})
745736
}
@@ -766,25 +757,3 @@ func GetPublicRepositoryCount(u *user_model.User) (int64, error) {
766757
func GetPrivateRepositoryCount(u *user_model.User) (int64, error) {
767758
return getPrivateRepositoryCount(db.GetEngine(db.DefaultContext), u)
768759
}
769-
770-
// IterateRepository iterate repositories
771-
func IterateRepository(f func(repo *Repository) error) error {
772-
var start int
773-
batchSize := setting.Database.IterateBufferSize
774-
for {
775-
repos := make([]*Repository, 0, batchSize)
776-
if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&repos); err != nil {
777-
return err
778-
}
779-
if len(repos) == 0 {
780-
return nil
781-
}
782-
start += len(repos)
783-
784-
for _, repo := range repos {
785-
if err := f(repo); err != nil {
786-
return err
787-
}
788-
}
789-
}
790-
}

models/repo/repo_list.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2021 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package repo
6+
7+
import (
8+
"code.gitea.io/gitea/models/db"
9+
"code.gitea.io/gitea/modules/setting"
10+
)
11+
12+
// GetUserMirrorRepositories returns a list of mirror repositories of given user.
13+
func GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
14+
repos := make([]*Repository, 0, 10)
15+
return repos, db.GetEngine(db.DefaultContext).
16+
Where("owner_id = ?", userID).
17+
And("is_mirror = ?", true).
18+
Find(&repos)
19+
}
20+
21+
// IterateRepository iterate repositories
22+
func IterateRepository(f func(repo *Repository) error) error {
23+
var start int
24+
batchSize := setting.Database.IterateBufferSize
25+
for {
26+
repos := make([]*Repository, 0, batchSize)
27+
if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&repos); err != nil {
28+
return err
29+
}
30+
if len(repos) == 0 {
31+
return nil
32+
}
33+
start += len(repos)
34+
35+
for _, repo := range repos {
36+
if err := f(repo); err != nil {
37+
return err
38+
}
39+
}
40+
}
41+
}
42+
43+
// FindReposMapByIDs find repos as map
44+
func FindReposMapByIDs(repoIDs []int64, res map[int64]*Repository) error {
45+
return db.GetEngine(db.DefaultContext).In("id", repoIDs).Find(&res)
46+
}

0 commit comments

Comments
 (0)