Improve loadprojects for issue list (#25468)

This commit is contained in:
Lunny Xiao 2023-06-24 23:31:28 +08:00 committed by GitHub
parent 5eeddfde10
commit 083818cb85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 41 additions and 30 deletions

View File

@ -229,39 +229,41 @@ func (issues IssueList) loadMilestones(ctx context.Context) error {
return nil return nil
} }
func (issues IssueList) getProjectIDs() []int64 { func (issues IssueList) LoadProjects(ctx context.Context) error {
ids := make(container.Set[int64], len(issues)) issueIDs := issues.getIssueIDs()
for _, issue := range issues { projectMaps := make(map[int64]*project_model.Project, len(issues))
ids.Add(issue.ProjectID()) left := len(issueIDs)
}
return ids.Values() type projectWithIssueID struct {
*project_model.Project `xorm:"extends"`
IssueID int64
} }
func (issues IssueList) loadProjects(ctx context.Context) error {
projectIDs := issues.getProjectIDs()
if len(projectIDs) == 0 {
return nil
}
projectMaps := make(map[int64]*project_model.Project, len(projectIDs))
left := len(projectIDs)
for left > 0 { for left > 0 {
limit := db.DefaultMaxInSize limit := db.DefaultMaxInSize
if left < limit { if left < limit {
limit = left limit = left
} }
projects := make([]*projectWithIssueID, 0, limit)
err := db.GetEngine(ctx). err := db.GetEngine(ctx).
In("id", projectIDs[:limit]). Table("project").
Find(&projectMaps) Select("project.*, project_issue.issue_id").
Join("INNER", "project_issue", "project.id = project_issue.project_id").
In("project_issue.issue_id", issueIDs[:limit]).
Find(&projects)
if err != nil { if err != nil {
return err return err
} }
for _, project := range projects {
projectMaps[project.IssueID] = project.Project
}
left -= limit left -= limit
projectIDs = projectIDs[limit:] issueIDs = issueIDs[limit:]
} }
for _, issue := range issues { for _, issue := range issues {
issue.Project = projectMaps[issue.ProjectID()] issue.Project = projectMaps[issue.ID]
} }
return nil return nil
} }
@ -541,7 +543,7 @@ func (issues IssueList) loadAttributes(ctx context.Context) error {
return fmt.Errorf("issue.loadAttributes: loadMilestones: %w", err) return fmt.Errorf("issue.loadAttributes: loadMilestones: %w", err)
} }
if err := issues.loadProjects(ctx); err != nil { if err := issues.LoadProjects(ctx); err != nil {
return fmt.Errorf("issue.loadAttributes: loadProjects: %w", err) return fmt.Errorf("issue.loadAttributes: loadProjects: %w", err)
} }

View File

@ -66,8 +66,12 @@ func TestIssueList_LoadAttributes(t *testing.T) {
} }
if issue.ID == int64(1) { if issue.ID == int64(1) {
assert.Equal(t, int64(400), issue.TotalTrackedTime) assert.Equal(t, int64(400), issue.TotalTrackedTime)
assert.NotNil(t, issue.Project)
} else if issue.ID == int64(2) { } else if issue.ID == int64(2) {
assert.Equal(t, int64(3682), issue.TotalTrackedTime) assert.Equal(t, int64(3682), issue.TotalTrackedTime)
assert.Nil(t, issue.Project)
} else {
assert.Nil(t, issue.Project)
} }
} }
} }

View File

@ -27,11 +27,6 @@ func (issue *Issue) LoadProject(ctx context.Context) (err error) {
return err return err
} }
// ProjectID return project id if issue was assigned to one
func (issue *Issue) ProjectID() int64 {
return issue.projectID(db.DefaultContext)
}
func (issue *Issue) projectID(ctx context.Context) int64 { func (issue *Issue) projectID(ctx context.Context) int64 {
var ip project_model.ProjectIssue var ip project_model.ProjectIssue
has, err := db.GetEngine(ctx).Where("issue_id=?", issue.ID).Get(&ip) has, err := db.GetEngine(ctx).Where("issue_id=?", issue.ID).Get(&ip)

View File

@ -383,7 +383,7 @@ func ViewProject(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplProjectsView) ctx.HTML(http.StatusOK, tplProjectsView)
} }
func getActionIssues(ctx *context.Context) []*issues_model.Issue { func getActionIssues(ctx *context.Context) issues_model.IssueList {
commaSeparatedIssueIDs := ctx.FormString("issue_ids") commaSeparatedIssueIDs := ctx.FormString("issue_ids")
if len(commaSeparatedIssueIDs) == 0 { if len(commaSeparatedIssueIDs) == 0 {
return nil return nil
@ -429,9 +429,14 @@ func UpdateIssueProject(ctx *context.Context) {
return return
} }
if err := issues.LoadProjects(ctx); err != nil {
ctx.ServerError("LoadProjects", err)
return
}
projectID := ctx.FormInt64("id") projectID := ctx.FormInt64("id")
for _, issue := range issues { for _, issue := range issues {
oldProjectID := issue.ProjectID() oldProjectID := issue.Project.ID
if oldProjectID == projectID { if oldProjectID == projectID {
continue continue
} }

View File

@ -1984,7 +1984,7 @@ func checkIssueRights(ctx *context.Context, issue *issues_model.Issue) {
} }
} }
func getActionIssues(ctx *context.Context) []*issues_model.Issue { func getActionIssues(ctx *context.Context) issues_model.IssueList {
commaSeparatedIssueIDs := ctx.FormString("issue_ids") commaSeparatedIssueIDs := ctx.FormString("issue_ids")
if len(commaSeparatedIssueIDs) == 0 { if len(commaSeparatedIssueIDs) == 0 {
return nil return nil
@ -2749,7 +2749,7 @@ func UpdateIssueStatus(ctx *context.Context) {
log.Warn("Unrecognized action: %s", action) log.Warn("Unrecognized action: %s", action)
} }
if _, err := issues_model.IssueList(issues).LoadRepositories(ctx); err != nil { if _, err := issues.LoadRepositories(ctx); err != nil {
ctx.ServerError("LoadRepositories", err) ctx.ServerError("LoadRepositories", err)
return return
} }

View File

@ -378,9 +378,14 @@ func UpdateIssueProject(ctx *context.Context) {
return return
} }
if err := issues.LoadProjects(ctx); err != nil {
ctx.ServerError("LoadProjects", err)
return
}
projectID := ctx.FormInt64("id") projectID := ctx.FormInt64("id")
for _, issue := range issues { for _, issue := range issues {
oldProjectID := issue.ProjectID() oldProjectID := issue.Project.ID
if oldProjectID == projectID { if oldProjectID == projectID {
continue continue
} }

View File

@ -192,9 +192,9 @@
</div> </div>
</div> </div>
<div class="ui select-project list"> <div class="ui select-project list">
<span class="no-select item {{if .Issue.ProjectID}}gt-hidden{{end}}">{{.locale.Tr "repo.issues.new.no_projects"}}</span> <span class="no-select item {{if .Issue.Project}}gt-hidden{{end}}">{{.locale.Tr "repo.issues.new.no_projects"}}</span>
<div class="selected"> <div class="selected">
{{if .Issue.ProjectID}} {{if .Issue.Project}}
<a class="item muted sidebar-item-link" href="{{.Issue.Project.Link}}"> <a class="item muted sidebar-item-link" href="{{.Issue.Project.Link}}">
{{svg .Issue.Project.IconName 18 "gt-mr-3"}}{{.Issue.Project.Title}} {{svg .Issue.Project.IconName 18 "gt-mr-3"}}{{.Issue.Project.Title}}
</a> </a>