Skip to content

Commit

Permalink
Second part of refactor db.Find (#28194)
Browse files Browse the repository at this point in the history
Continue of #27798 and move more functions to `db.Find` and `db.Count`.
  • Loading branch information
lunny authored Dec 11, 2023
1 parent 0abb563 commit 537fa69
Show file tree
Hide file tree
Showing 14 changed files with 149 additions and 222 deletions.
34 changes: 11 additions & 23 deletions models/git/branch_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"code.gitea.io/gitea/modules/util"

"xorm.io/builder"
"xorm.io/xorm"
)

type BranchList []*Branch
Expand Down Expand Up @@ -91,41 +90,30 @@ func (opts FindBranchOptions) ToConds() builder.Cond {
return cond
}

func CountBranches(ctx context.Context, opts FindBranchOptions) (int64, error) {
return db.GetEngine(ctx).Where(opts.ToConds()).Count(&Branch{})
}

func orderByBranches(sess *xorm.Session, opts FindBranchOptions) *xorm.Session {
func (opts FindBranchOptions) ToOrders() string {
orderBy := opts.OrderBy
if !opts.IsDeletedBranch.IsFalse() { // if deleted branch included, put them at the end
sess = sess.OrderBy("is_deleted ASC")
if orderBy != "" {
orderBy += ", "
}
orderBy += "is_deleted ASC"
}

if opts.OrderBy == "" {
if orderBy == "" {
// the commit_time might be the same, so add the "name" to make sure the order is stable
opts.OrderBy = "commit_time DESC, name ASC"
return "commit_time DESC, name ASC"
}
return sess.OrderBy(opts.OrderBy)
}

func FindBranches(ctx context.Context, opts FindBranchOptions) (BranchList, error) {
sess := db.GetEngine(ctx).Where(opts.ToConds())
if opts.PageSize > 0 && !opts.IsListAll() {
sess = db.SetSessionPagination(sess, &opts.ListOptions)
}
sess = orderByBranches(sess, opts)

var branches []*Branch
return branches, sess.Find(&branches)
return orderBy
}

func FindBranchNames(ctx context.Context, opts FindBranchOptions) ([]string, error) {
sess := db.GetEngine(ctx).Select("name").Where(opts.ToConds())
if opts.PageSize > 0 && !opts.IsListAll() {
sess = db.SetSessionPagination(sess, &opts.ListOptions)
}
sess = orderByBranches(sess, opts)

var branches []string
if err := sess.Table("branch").Find(&branches); err != nil {
if err := sess.Table("branch").OrderBy(opts.ToOrders()).Find(&branches); err != nil {
return nil, err
}
return branches, nil
Expand Down
6 changes: 2 additions & 4 deletions models/git/branch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,8 @@ func TestGetDeletedBranches(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})

branches, err := git_model.FindBranches(db.DefaultContext, git_model.FindBranchOptions{
ListOptions: db.ListOptions{
ListAll: true,
},
branches, err := db.Find[git_model.Branch](db.DefaultContext, git_model.FindBranchOptions{
ListOptions: db.ListOptionsAll,
RepoID: repo.ID,
IsDeletedBranch: util.OptionalBoolTrue,
})
Expand Down
9 changes: 4 additions & 5 deletions models/issues/milestone.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,16 +295,15 @@ func DeleteMilestoneByRepoID(ctx context.Context, repoID, id int64) error {
return err
}

numMilestones, err := CountMilestones(ctx, GetMilestonesOption{
numMilestones, err := db.Count[Milestone](ctx, FindMilestoneOptions{
RepoID: repo.ID,
State: api.StateAll,
})
if err != nil {
return err
}
numClosedMilestones, err := CountMilestones(ctx, GetMilestonesOption{
RepoID: repo.ID,
State: api.StateClosed,
numClosedMilestones, err := db.Count[Milestone](ctx, FindMilestoneOptions{
RepoID: repo.ID,
IsClosed: util.OptionalBoolTrue,
})
if err != nil {
return err
Expand Down
143 changes: 25 additions & 118 deletions models/issues/milestone_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import (
"strings"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"

"xorm.io/builder"
)
Expand All @@ -25,66 +24,55 @@ func (milestones MilestoneList) getMilestoneIDs() []int64 {
return ids
}

// GetMilestonesOption contain options to get milestones
type GetMilestonesOption struct {
// FindMilestoneOptions contain options to get milestones
type FindMilestoneOptions struct {
db.ListOptions
RepoID int64
State api.StateType
IsClosed util.OptionalBool
Name string
SortType string
RepoCond builder.Cond
RepoIDs []int64
}

func (opts GetMilestonesOption) toCond() builder.Cond {
func (opts FindMilestoneOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RepoID != 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}

switch opts.State {
case api.StateClosed:
cond = cond.And(builder.Eq{"is_closed": true})
case api.StateAll:
break
// api.StateOpen:
default:
cond = cond.And(builder.Eq{"is_closed": false})
if opts.IsClosed != util.OptionalBoolNone {
cond = cond.And(builder.Eq{"is_closed": opts.IsClosed.IsTrue()})
}
if opts.RepoCond != nil && opts.RepoCond.IsValid() {
cond = cond.And(builder.In("repo_id", builder.Select("id").From("repository").Where(opts.RepoCond)))
}
if len(opts.RepoIDs) > 0 {
cond = cond.And(builder.In("repo_id", opts.RepoIDs))
}

if len(opts.Name) != 0 {
cond = cond.And(db.BuildCaseInsensitiveLike("name", opts.Name))
}

return cond
}

// GetMilestones returns milestones filtered by GetMilestonesOption's
func GetMilestones(ctx context.Context, opts GetMilestonesOption) (MilestoneList, int64, error) {
sess := db.GetEngine(ctx).Where(opts.toCond())

if opts.Page != 0 {
sess = db.SetSessionPagination(sess, &opts)
}

func (opts FindMilestoneOptions) ToOrders() string {
switch opts.SortType {
case "furthestduedate":
sess.Desc("deadline_unix")
return "deadline_unix DESC"
case "leastcomplete":
sess.Asc("completeness")
return "completeness ASC"
case "mostcomplete":
sess.Desc("completeness")
return "completeness DESC"
case "leastissues":
sess.Asc("num_issues")
return "num_issues ASC"
case "mostissues":
sess.Desc("num_issues")
return "num_issues DESC"
case "id":
sess.Asc("id")
return "id ASC"
default:
sess.Asc("deadline_unix").Asc("id")
return "deadline_unix ASC, id ASC"
}

miles := make([]*Milestone, 0, opts.PageSize)
total, err := sess.FindAndCount(&miles)
return miles, total, err
}

// GetMilestoneIDsByNames returns a list of milestone ids by given names.
Expand All @@ -99,49 +87,6 @@ func GetMilestoneIDsByNames(ctx context.Context, names []string) ([]int64, error
Find(&ids)
}

// SearchMilestones search milestones
func SearchMilestones(ctx context.Context, repoCond builder.Cond, page int, isClosed bool, sortType, keyword string) (MilestoneList, error) {
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
sess := db.GetEngine(ctx).Where("is_closed = ?", isClosed)
if len(keyword) > 0 {
sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)})
}
if repoCond.IsValid() {
sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
}
if page > 0 {
sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
}

switch sortType {
case "furthestduedate":
sess.Desc("deadline_unix")
case "leastcomplete":
sess.Asc("completeness")
case "mostcomplete":
sess.Desc("completeness")
case "leastissues":
sess.Asc("num_issues")
case "mostissues":
sess.Desc("num_issues")
default:
sess.Asc("deadline_unix")
}
return miles, sess.Find(&miles)
}

// GetMilestonesByRepoIDs returns a list of milestones of given repositories and status.
func GetMilestonesByRepoIDs(ctx context.Context, repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) {
return SearchMilestones(
ctx,
builder.In("repo_id", repoIDs),
page,
isClosed,
sortType,
"",
)
}

// LoadTotalTrackedTimes loads for every milestone in the list the TotalTrackedTime by a batch request
func (milestones MilestoneList) LoadTotalTrackedTimes(ctx context.Context) error {
type totalTimesByMilestone struct {
Expand Down Expand Up @@ -183,47 +128,9 @@ func (milestones MilestoneList) LoadTotalTrackedTimes(ctx context.Context) error
return nil
}

// CountMilestones returns number of milestones in given repository with other options
func CountMilestones(ctx context.Context, opts GetMilestonesOption) (int64, error) {
return db.GetEngine(ctx).
Where(opts.toCond()).
Count(new(Milestone))
}

// CountMilestonesByRepoCond map from repo conditions to number of milestones matching the options`
func CountMilestonesByRepoCond(ctx context.Context, repoCond builder.Cond, isClosed bool) (map[int64]int64, error) {
sess := db.GetEngine(ctx).Where("is_closed = ?", isClosed)
if repoCond.IsValid() {
sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
}

countsSlice := make([]*struct {
RepoID int64
Count int64
}, 0, 10)
if err := sess.GroupBy("repo_id").
Select("repo_id AS repo_id, COUNT(*) AS count").
Table("milestone").
Find(&countsSlice); err != nil {
return nil, err
}

countMap := make(map[int64]int64, len(countsSlice))
for _, c := range countsSlice {
countMap[c.RepoID] = c.Count
}
return countMap, nil
}

// CountMilestonesByRepoCondAndKw map from repo conditions and the keyword of milestones' name to number of milestones matching the options`
func CountMilestonesByRepoCondAndKw(ctx context.Context, repoCond builder.Cond, keyword string, isClosed bool) (map[int64]int64, error) {
sess := db.GetEngine(ctx).Where("is_closed = ?", isClosed)
if len(keyword) > 0 {
sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)})
}
if repoCond.IsValid() {
sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
}
func CountMilestonesMap(ctx context.Context, opts FindMilestoneOptions) (map[int64]int64, error) {
sess := db.GetEngine(ctx).Where(opts.ToConds())

countsSlice := make([]*struct {
RepoID int64
Expand Down
Loading

0 comments on commit 537fa69

Please sign in to comment.