diff --git a/models/db/search.go b/models/db/search.go index 704a48ed1eb40..ade61b3409046 100644 --- a/models/db/search.go +++ b/models/db/search.go @@ -4,11 +4,29 @@ package db +import "xorm.io/xorm" + // SearchOrderBy is used to sort the result type SearchOrderBy string func (s SearchOrderBy) String() string { - return string(s) + switch s { + case SearchOrderByAlphabetically, SearchOrderByAlphabeticallyReverse, SearchOrderByLeastUpdated, + SearchOrderByRecentUpdated, SearchOrderByOldest, SearchOrderByNewest, + SearchOrderBySize, SearchOrderBySizeReverse, SearchOrderByID, + SearchOrderByIDReverse, SearchOrderByStars, SearchOrderByStarsReverse, + SearchOrderByForks, SearchOrderByForksReverse: + return string(s) + default: + return "" + + } +} + +func (s SearchOrderBy) Builder() func(sess *xorm.Session) *xorm.Session { + return func(sess *xorm.Session) *xorm.Session { + return sess.OrderBy(s.String()) + } } // Strings for sorting result diff --git a/models/repo_list.go b/models/repo_list.go index 906b7548d4a64..d7946eccaa66e 100644 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/util" "xorm.io/builder" + "xorm.io/xorm" ) // RepositoryListDefaultPageSize is the default number of repositories @@ -116,7 +117,7 @@ type SearchRepoOptions struct { OwnerID int64 PriorityOwnerID int64 TeamID int64 - OrderBy db.SearchOrderBy + OrderBy func(sess *xorm.Session) *xorm.Session Private bool // Include private repositories in results StarredByID int64 WatchedByID int64 @@ -552,16 +553,20 @@ func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, c opts.Page = 1 } - if len(opts.OrderBy) == 0 { - opts.OrderBy = db.SearchOrderByAlphabetically + if opts.OrderBy == nil { + opts.OrderBy = db.SearchOrderByAlphabetically.Builder() } if opts.PriorityOwnerID > 0 { - opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_id = %d THEN 0 ELSE owner_id END, %s", opts.PriorityOwnerID, opts.OrderBy)) + opts.OrderBy = func(sess *xorm.Session) *xorm.Session { + return sess.SQL("ORDER BY CASE WHEN owner_id = ? THEN 0 ELSE owner_id END, ?", opts.PriorityOwnerID, db.SearchOrderByAlphabetically.String()) + } } else if strings.Count(opts.Keyword, "/") == 1 { // With "owner/repo" search times, prioritise results which match the owner field orgName := strings.Split(opts.Keyword, "/")[0] - opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_name LIKE '%s' THEN 0 ELSE 1 END, %s", orgName, opts.OrderBy)) + opts.OrderBy = func(sess *xorm.Session) *xorm.Session { + return sess.SQL("ORDER BY CASE WHEN owner_name LIKE ? THEN 0 ELSE 1 END, ?", orgName, db.SearchOrderByAlphabetically.String()) + } } sess := db.GetEngine(ctx) @@ -577,7 +582,12 @@ func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, c } } - sess = sess.Where(cond).OrderBy(opts.OrderBy.String()) + if opts.OrderBy != nil { + sess = opts.OrderBy(sess.Where(cond)) + } else { + sess = sess.Where(cond) + } + if opts.PageSize > 0 { sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) } @@ -674,8 +684,8 @@ func FindUserAccessibleRepoIDs(user *user_model.User) ([]int64, error) { // GetUserRepositories returns a list of repositories of given user. func GetUserRepositories(opts *SearchRepoOptions) (RepositoryList, int64, error) { - if len(opts.OrderBy) == 0 { - opts.OrderBy = "updated_unix DESC" + if opts.OrderBy == nil { + opts.OrderBy = db.SearchOrderByRecentUpdated.Builder() } cond := builder.NewCond() @@ -695,7 +705,11 @@ func GetUserRepositories(opts *SearchRepoOptions) (RepositoryList, int64, error) return nil, 0, fmt.Errorf("Count: %v", err) } - sess = sess.Where(cond).OrderBy(opts.OrderBy.String()) + if opts.OrderBy != nil { + sess = opts.OrderBy(sess.Where(cond)) + } else { + sess = sess.Where(cond) + } repos := make(RepositoryList, 0, opts.PageSize) return repos, count, db.SetSessionPagination(sess, opts).Find(&repos) } diff --git a/modules/indexer/issues/indexer.go b/modules/indexer/issues/indexer.go index 7adc938dccbad..1edb9e03652e2 100644 --- a/modules/indexer/issues/indexer.go +++ b/modules/indexer/issues/indexer.go @@ -293,7 +293,7 @@ func populateIssueIndexer(ctx context.Context) { } repos, _, err := models.SearchRepositoryByName(&models.SearchRepoOptions{ ListOptions: db.ListOptions{Page: page, PageSize: models.RepositoryListDefaultPageSize}, - OrderBy: db.SearchOrderByID, + OrderBy: db.SearchOrderByID.Builder(), Private: true, Collaborate: util.OptionalBoolFalse, }) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 62959c3a76da5..c27301df7b28d 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -137,7 +137,7 @@ func SearchIssues(ctx *context.APIContext) { Collaborate: util.OptionalBoolNone, // This needs to be a column that is not nil in fixtures or // MySQL will return different results when sorting by null in some cases - OrderBy: db.SearchOrderByAlphabetically, + OrderBy: db.SearchOrderByAlphabetically.Builder(), Actor: ctx.Doer, } if ctx.IsSigned { diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 8485ffbac2145..3a7ade50d096f 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -180,7 +180,7 @@ func Search(ctx *context.APIContext) { } if searchModeMap, ok := context.SearchOrderByMap[sortOrder]; ok { if orderBy, ok := searchModeMap[sortMode]; ok { - opts.OrderBy = orderBy + opts.OrderBy = orderBy.Builder() } else { ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("Invalid sort mode: \"%s\"", sortMode)) return diff --git a/routers/api/v1/user/repo.go b/routers/api/v1/user/repo.go index 05cecf508b383..ddf78f011cf40 100644 --- a/routers/api/v1/user/repo.go +++ b/routers/api/v1/user/repo.go @@ -8,6 +8,7 @@ import ( "net/http" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" user_model "code.gitea.io/gitea/models/user" @@ -25,7 +26,7 @@ func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) { Actor: u, Private: private, ListOptions: opts, - OrderBy: "id ASC", + OrderBy: db.SearchOrderByID.Builder(), }) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserRepositories", err) diff --git a/routers/web/explore/repo.go b/routers/web/explore/repo.go index 3e8aa2bb0fda7..ef23cdaf146d3 100644 --- a/routers/web/explore/repo.go +++ b/routers/web/explore/repo.go @@ -87,7 +87,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { PageSize: opts.PageSize, }, Actor: ctx.Doer, - OrderBy: orderBy, + OrderBy: orderBy.Builder(), Private: opts.Private, Keyword: keyword, OwnerID: opts.OwnerID, diff --git a/routers/web/org/home.go b/routers/web/org/home.go index 24a0f13b542e1..36d9ea1ac92e6 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -112,7 +112,7 @@ func Home(ctx *context.Context) { }, Keyword: keyword, OwnerID: org.ID, - OrderBy: orderBy, + OrderBy: orderBy.Builder(), Private: ctx.IsSigned, Actor: ctx.Doer, Language: language, diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 079ccbf6cf968..c2f60d3e3a226 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -2152,7 +2152,7 @@ func SearchIssues(ctx *context.Context) { Collaborate: util.OptionalBoolNone, // This needs to be a column that is not nil in fixtures or // MySQL will return different results when sorting by null in some cases - OrderBy: db.SearchOrderByAlphabetically, + OrderBy: db.SearchOrderByAlphabetically.Builder(), Actor: ctx.Doer, } if ctx.IsSigned { diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 30cb888dce989..180e9fe5edde5 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -569,7 +569,7 @@ func SearchRepo(ctx *context.Context) { } if searchModeMap, ok := context.SearchOrderByMap[sortOrder]; ok { if orderBy, ok := searchModeMap[sortMode]; ok { - opts.OrderBy = orderBy + opts.OrderBy = orderBy.Builder() } else { ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid sort mode: \"%s\"", sortMode)) return diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 8bce5460ccec1..b81eae1425bbb 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -202,7 +202,7 @@ func Profile(ctx *context.Context) { }, Actor: ctx.Doer, Keyword: keyword, - OrderBy: orderBy, + OrderBy: orderBy.Builder(), Private: ctx.IsSigned, StarredByID: ctx.ContextUser.ID, Collaborate: util.OptionalBoolFalse, @@ -234,7 +234,7 @@ func Profile(ctx *context.Context) { }, Actor: ctx.Doer, Keyword: keyword, - OrderBy: orderBy, + OrderBy: orderBy.Builder(), Private: ctx.IsSigned, WatchedByID: ctx.ContextUser.ID, Collaborate: util.OptionalBoolFalse, @@ -257,7 +257,7 @@ func Profile(ctx *context.Context) { Actor: ctx.Doer, Keyword: keyword, OwnerID: ctx.ContextUser.ID, - OrderBy: orderBy, + OrderBy: orderBy.Builder(), Private: ctx.IsSigned, Collaborate: util.OptionalBoolFalse, TopicOnly: topicOnly,