98 lines
2.9 KiB
Go
98 lines
2.9 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package project
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
|
|
"code.gitea.io/gitea/models/db"
|
|
|
|
"xorm.io/builder"
|
|
)
|
|
|
|
// CountProjectColumns returns the total number of columns for a project
|
|
func CountProjectColumns(ctx context.Context, projectID int64) (int64, error) {
|
|
return db.GetEngine(ctx).Where("project_id=?", projectID).Count(&Column{})
|
|
}
|
|
|
|
// GetProjectColumns returns a list of columns for a project with pagination
|
|
func GetProjectColumns(ctx context.Context, projectID int64, opts db.ListOptions) (ColumnList, error) {
|
|
columns := make([]*Column, 0, opts.PageSize)
|
|
s := db.GetEngine(ctx).Where("project_id=?", projectID).OrderBy("sorting, id")
|
|
if !opts.IsListAll() {
|
|
db.SetSessionPagination(s, &opts)
|
|
}
|
|
if err := s.Find(&columns); err != nil {
|
|
return nil, err
|
|
}
|
|
return columns, nil
|
|
}
|
|
|
|
// LoadIssueCounts populates NumIssues, NumOpenIssues, and NumClosedIssues on
|
|
// every column in the list using two grouped queries against project_issue
|
|
// joined with issue. Columns with no attached issues stay at zero counts —
|
|
// nothing else has to be wired up by the caller.
|
|
func (cl ColumnList) LoadIssueCounts(ctx context.Context) error {
|
|
if len(cl) == 0 {
|
|
return nil
|
|
}
|
|
|
|
columnIDs := make([]int64, 0, len(cl))
|
|
for _, c := range cl {
|
|
columnIDs = append(columnIDs, c.ID)
|
|
}
|
|
|
|
openCounts, err := countColumnIssuesByState(ctx, columnIDs, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
closedCounts, err := countColumnIssuesByState(ctx, columnIDs, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, c := range cl {
|
|
c.NumOpenIssues = openCounts[c.ID]
|
|
c.NumClosedIssues = closedCounts[c.ID]
|
|
c.NumIssues = c.NumOpenIssues + c.NumClosedIssues
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func countColumnIssuesByState(ctx context.Context, columnIDs []int64, isClosed bool) (map[int64]int64, error) {
|
|
out := make(map[int64]int64, len(columnIDs))
|
|
cond := builder.In("project_issue.project_board_id", columnIDs).
|
|
And(builder.Eq{"issue.is_closed": isClosed})
|
|
sub := builder.Select("project_issue.project_board_id AS project_board_id", "COUNT(*) AS cnt").
|
|
From("project_issue").
|
|
InnerJoin("issue", "issue.id = project_issue.issue_id").
|
|
Where(cond).
|
|
GroupBy("project_issue.project_board_id")
|
|
rows, err := db.GetEngine(ctx).Query(sub)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, r := range rows {
|
|
columnID, _ := strconv.ParseInt(string(r["project_board_id"]), 10, 64)
|
|
cnt, _ := strconv.ParseInt(string(r["cnt"]), 10, 64)
|
|
out[columnID] = cnt
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func GetColumnsByIDs(ctx context.Context, projectID int64, columnsIDs []int64) (ColumnList, error) {
|
|
columns := make([]*Column, 0, len(columnsIDs))
|
|
if len(columnsIDs) == 0 {
|
|
return columns, nil
|
|
}
|
|
if err := db.GetEngine(ctx).
|
|
Where("project_id =?", projectID).
|
|
In("id", columnsIDs).
|
|
OrderBy("sorting").Find(&columns); err != nil {
|
|
return nil, err
|
|
}
|
|
return columns, nil
|
|
}
|