Skip to content

Second part of refactor db.Find #28194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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