Browse Source

Refactor for issues loadattributes of a repository (#971)

* refactor for issues loadattributes of a repository

* refactors
Lunny Xiao 3 years ago
parent
commit
1f7837d6d6
3 changed files with 343 additions and 64 deletions
  1. 21 0
      models/helper.go
  2. 2 64
      models/issue.go
  3. 320 0
      models/issue_list.go

+ 21 - 0
models/helper.go

@@ -0,0 +1,21 @@
1
+// Copyright 2017 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 models
6
+
7
+func keysInt64(m map[int64]struct{}) []int64 {
8
+	var keys = make([]int64, 0, len(m))
9
+	for k, _ := range m {
10
+		keys = append(keys, k)
11
+	}
12
+	return keys
13
+}
14
+
15
+func valuesRepository(m map[int64]*Repository) []*Repository {
16
+	var values = make([]*Repository, 0, len(m))
17
+	for _, v := range m {
18
+		values = append(values, v)
19
+	}
20
+	return values
21
+}

+ 2 - 64
models/issue.go

@@ -1128,11 +1128,8 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
1128 1128
 		return nil, fmt.Errorf("Find: %v", err)
1129 1129
 	}
1130 1130
 
1131
-	// FIXME: use IssueList to improve performance.
1132
-	for i := range issues {
1133
-		if err := issues[i].LoadAttributes(); err != nil {
1134
-			return nil, fmt.Errorf("LoadAttributes [%d]: %v", issues[i].ID, err)
1135
-		}
1131
+	if err := IssueList(issues).LoadAttributes(); err != nil {
1132
+		return nil, fmt.Errorf("LoadAttributes: %v", err)
1136 1133
 	}
1137 1134
 
1138 1135
 	return issues, nil
@@ -1399,62 +1396,3 @@ func updateIssue(e Engine, issue *Issue) error {
1399 1396
 func UpdateIssue(issue *Issue) error {
1400 1397
 	return updateIssue(x, issue)
1401 1398
 }
1402
-
1403
-// IssueList defines a list of issues
1404
-type IssueList []*Issue
1405
-
1406
-func (issues IssueList) getRepoIDs() []int64 {
1407
-	repoIDs := make([]int64, 0, len(issues))
1408
-	for _, issue := range issues {
1409
-		var has bool
1410
-		for _, repoID := range repoIDs {
1411
-			if repoID == issue.RepoID {
1412
-				has = true
1413
-				break
1414
-			}
1415
-		}
1416
-		if !has {
1417
-			repoIDs = append(repoIDs, issue.RepoID)
1418
-		}
1419
-	}
1420
-	return repoIDs
1421
-}
1422
-
1423
-func (issues IssueList) loadRepositories(e Engine) ([]*Repository, error) {
1424
-	if len(issues) == 0 {
1425
-		return nil, nil
1426
-	}
1427
-
1428
-	repoIDs := issues.getRepoIDs()
1429
-	rows, err := e.
1430
-		Where("id > 0").
1431
-		In("id", repoIDs).
1432
-		Rows(new(Repository))
1433
-	if err != nil {
1434
-		return nil, fmt.Errorf("find repository: %v", err)
1435
-	}
1436
-	defer rows.Close()
1437
-
1438
-	repositories := make([]*Repository, 0, len(repoIDs))
1439
-	repoMaps := make(map[int64]*Repository, len(repoIDs))
1440
-	for rows.Next() {
1441
-		var repo Repository
1442
-		err = rows.Scan(&repo)
1443
-		if err != nil {
1444
-			return nil, fmt.Errorf("find repository: %v", err)
1445
-		}
1446
-
1447
-		repositories = append(repositories, &repo)
1448
-		repoMaps[repo.ID] = &repo
1449
-	}
1450
-
1451
-	for _, issue := range issues {
1452
-		issue.Repo = repoMaps[issue.RepoID]
1453
-	}
1454
-	return repositories, nil
1455
-}
1456
-
1457
-// LoadRepositories loads issues' all repositories
1458
-func (issues IssueList) LoadRepositories() ([]*Repository, error) {
1459
-	return issues.loadRepositories(x)
1460
-}

+ 320 - 0
models/issue_list.go

@@ -0,0 +1,320 @@
1
+// Copyright 2017 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 models
6
+
7
+import "fmt"
8
+
9
+// IssueList defines a list of issues
10
+type IssueList []*Issue
11
+
12
+func (issues IssueList) getRepoIDs() []int64 {
13
+	repoIDs := make(map[int64]struct{}, len(issues))
14
+	for _, issue := range issues {
15
+		if _, ok := repoIDs[issue.RepoID]; !ok {
16
+			repoIDs[issue.RepoID] = struct{}{}
17
+		}
18
+	}
19
+	return keysInt64(repoIDs)
20
+}
21
+
22
+func (issues IssueList) loadRepositories(e Engine) ([]*Repository, error) {
23
+	if len(issues) == 0 {
24
+		return nil, nil
25
+	}
26
+
27
+	repoIDs := issues.getRepoIDs()
28
+	repoMaps := make(map[int64]*Repository, len(repoIDs))
29
+	err := e.
30
+		In("id", repoIDs).
31
+		Find(&repoMaps)
32
+	if err != nil {
33
+		return nil, fmt.Errorf("find repository: %v", err)
34
+	}
35
+
36
+	for _, issue := range issues {
37
+		issue.Repo = repoMaps[issue.RepoID]
38
+	}
39
+	return valuesRepository(repoMaps), nil
40
+}
41
+
42
+// LoadRepositories loads issues' all repositories
43
+func (issues IssueList) LoadRepositories() ([]*Repository, error) {
44
+	return issues.loadRepositories(x)
45
+}
46
+
47
+func (issues IssueList) getPosterIDs() []int64 {
48
+	posterIDs := make(map[int64]struct{}, len(issues))
49
+	for _, issue := range issues {
50
+		if _, ok := posterIDs[issue.PosterID]; !ok {
51
+			posterIDs[issue.PosterID] = struct{}{}
52
+		}
53
+	}
54
+	return keysInt64(posterIDs)
55
+}
56
+
57
+func (issues IssueList) loadPosters(e Engine) error {
58
+	if len(issues) == 0 {
59
+		return nil
60
+	}
61
+
62
+	postgerIDs := issues.getPosterIDs()
63
+	posterMaps := make(map[int64]*User, len(postgerIDs))
64
+	err := e.
65
+		In("id", postgerIDs).
66
+		Find(&posterMaps)
67
+	if err != nil {
68
+		return err
69
+	}
70
+
71
+	for _, issue := range issues {
72
+		issue.Poster = posterMaps[issue.PosterID]
73
+	}
74
+	return nil
75
+}
76
+
77
+func (issues IssueList) getIssueIDs() []int64 {
78
+	var ids = make([]int64, 0, len(issues))
79
+	for _, issue := range issues {
80
+		ids = append(ids, issue.ID)
81
+	}
82
+	return ids
83
+}
84
+
85
+func (issues IssueList) loadLabels(e Engine) error {
86
+	if len(issues) == 0 {
87
+		return nil
88
+	}
89
+
90
+	type LabelIssue struct {
91
+		Label      *Label      `xorm:"extends"`
92
+		IssueLabel *IssueLabel `xorm:"extends"`
93
+	}
94
+
95
+	var issueLabels = make(map[int64][]*Label, len(issues)*3)
96
+	rows, err := e.Table("label").
97
+		Join("LEFT", "issue_label", "issue_label.label_id = label.id").
98
+		In("issue_label.issue_id", issues.getIssueIDs()).
99
+		Asc("label.name").
100
+		Rows(new(LabelIssue))
101
+	if err != nil {
102
+		return err
103
+	}
104
+	defer rows.Close()
105
+
106
+	for rows.Next() {
107
+		var labelIssue LabelIssue
108
+		err = rows.Scan(&labelIssue)
109
+		if err != nil {
110
+			return err
111
+		}
112
+		issueLabels[labelIssue.IssueLabel.IssueID] = append(issueLabels[labelIssue.IssueLabel.IssueID], labelIssue.Label)
113
+	}
114
+
115
+	for _, issue := range issues {
116
+		issue.Labels = issueLabels[issue.ID]
117
+	}
118
+	return nil
119
+}
120
+
121
+func (issues IssueList) getMilestoneIDs() []int64 {
122
+	var ids = make(map[int64]struct{}, len(issues))
123
+	for _, issue := range issues {
124
+		if _, ok := ids[issue.MilestoneID]; !ok {
125
+			ids[issue.MilestoneID] = struct{}{}
126
+		}
127
+	}
128
+	return keysInt64(ids)
129
+}
130
+
131
+func (issues IssueList) loadMilestones(e Engine) error {
132
+	milestoneIDs := issues.getMilestoneIDs()
133
+	if len(milestoneIDs) == 0 {
134
+		return nil
135
+	}
136
+
137
+	milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs))
138
+	err := e.
139
+		In("id", milestoneIDs).
140
+		Find(&milestoneMaps)
141
+	if err != nil {
142
+		return err
143
+	}
144
+
145
+	for _, issue := range issues {
146
+		issue.Milestone = milestoneMaps[issue.MilestoneID]
147
+	}
148
+	return nil
149
+}
150
+
151
+func (issues IssueList) getAssigneeIDs() []int64 {
152
+	var ids = make(map[int64]struct{}, len(issues))
153
+	for _, issue := range issues {
154
+		if _, ok := ids[issue.AssigneeID]; !ok {
155
+			ids[issue.AssigneeID] = struct{}{}
156
+		}
157
+	}
158
+	return keysInt64(ids)
159
+}
160
+
161
+func (issues IssueList) loadAssignees(e Engine) error {
162
+	assigneeIDs := issues.getAssigneeIDs()
163
+	if len(assigneeIDs) == 0 {
164
+		return nil
165
+	}
166
+
167
+	assigneeMaps := make(map[int64]*User, len(assigneeIDs))
168
+	err := e.
169
+		In("id", assigneeIDs).
170
+		Find(&assigneeMaps)
171
+	if err != nil {
172
+		return err
173
+	}
174
+
175
+	for _, issue := range issues {
176
+		issue.Assignee = assigneeMaps[issue.AssigneeID]
177
+	}
178
+	return nil
179
+}
180
+
181
+func (issues IssueList) getPullIssueIDs() []int64 {
182
+	var ids = make([]int64, 0, len(issues))
183
+	for _, issue := range issues {
184
+		if issue.IsPull && issue.PullRequest == nil {
185
+			ids = append(ids, issue.ID)
186
+		}
187
+	}
188
+	return ids
189
+}
190
+
191
+func (issues IssueList) loadPullRequests(e Engine) error {
192
+	issuesIDs := issues.getPullIssueIDs()
193
+	if len(issuesIDs) == 0 {
194
+		return nil
195
+	}
196
+
197
+	pullRequestMaps := make(map[int64]*PullRequest, len(issuesIDs))
198
+	rows, err := e.
199
+		In("issue_id", issuesIDs).
200
+		Rows(new(PullRequest))
201
+	if err != nil {
202
+		return err
203
+	}
204
+	defer rows.Close()
205
+
206
+	for rows.Next() {
207
+		var pr PullRequest
208
+		err = rows.Scan(&pr)
209
+		if err != nil {
210
+			return err
211
+		}
212
+		pullRequestMaps[pr.IssueID] = &pr
213
+	}
214
+
215
+	for _, issue := range issues {
216
+		issue.PullRequest = pullRequestMaps[issue.ID]
217
+	}
218
+	return nil
219
+}
220
+
221
+func (issues IssueList) loadAttachments(e Engine) (err error) {
222
+	if len(issues) == 0 {
223
+		return nil
224
+	}
225
+
226
+	var attachments = make(map[int64][]*Attachment, len(issues))
227
+	rows, err := e.Table("attachment").
228
+		Join("INNER", "issue", "issue.id = attachment.issue_id").
229
+		In("issue.id", issues.getIssueIDs()).
230
+		Rows(new(Attachment))
231
+	if err != nil {
232
+		return err
233
+	}
234
+	defer rows.Close()
235
+
236
+	for rows.Next() {
237
+		var attachment Attachment
238
+		err = rows.Scan(&attachment)
239
+		if err != nil {
240
+			return err
241
+		}
242
+		attachments[attachment.IssueID] = append(attachments[attachment.IssueID], &attachment)
243
+	}
244
+
245
+	for _, issue := range issues {
246
+		issue.Attachments = attachments[issue.ID]
247
+	}
248
+	return nil
249
+}
250
+
251
+func (issues IssueList) loadComments(e Engine) (err error) {
252
+	if len(issues) == 0 {
253
+		return nil
254
+	}
255
+
256
+	var comments = make(map[int64][]*Comment, len(issues))
257
+	rows, err := e.Table("comment").
258
+		Join("INNER", "issue", "issue.id = comment.issue_id").
259
+		In("issue.id", issues.getIssueIDs()).
260
+		Rows(new(Comment))
261
+	if err != nil {
262
+		return err
263
+	}
264
+	defer rows.Close()
265
+
266
+	for rows.Next() {
267
+		var comment Comment
268
+		err = rows.Scan(&comment)
269
+		if err != nil {
270
+			return err
271
+		}
272
+		comments[comment.IssueID] = append(comments[comment.IssueID], &comment)
273
+	}
274
+
275
+	for _, issue := range issues {
276
+		issue.Comments = comments[issue.ID]
277
+	}
278
+	return nil
279
+}
280
+
281
+func (issues IssueList) loadAttributes(e Engine) (err error) {
282
+	if _, err = issues.loadRepositories(e); err != nil {
283
+		return
284
+	}
285
+
286
+	if err = issues.loadPosters(e); err != nil {
287
+		return
288
+	}
289
+
290
+	if err = issues.loadLabels(e); err != nil {
291
+		return
292
+	}
293
+
294
+	if err = issues.loadMilestones(e); err != nil {
295
+		return
296
+	}
297
+
298
+	if err = issues.loadAssignees(e); err != nil {
299
+		return
300
+	}
301
+
302
+	if err = issues.loadPullRequests(e); err != nil {
303
+		return
304
+	}
305
+
306
+	if err = issues.loadAttachments(e); err != nil {
307
+		return
308
+	}
309
+
310
+	if err = issues.loadComments(e); err != nil {
311
+		return
312
+	}
313
+
314
+	return nil
315
+}
316
+
317
+// LoadAttributes loads atrributes of the issues
318
+func (issues IssueList) LoadAttributes() error {
319
+	return issues.loadAttributes(x)
320
+}