Skip to content

Commit 87505a9

Browse files
authored
Add AbsoluteListOptions (#17028)
This PR adds a `ListOptions` type which is not paged but uses absolute values. It is implemented as discussed in Discord. Extracted from #16510 to clean that PR.
1 parent 0a542dd commit 87505a9

29 files changed

+159
-56
lines changed

models/commit_status.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func GetCommitStatuses(repo *Repository, sha string, opts *CommitStatusOptions)
9797
}
9898

9999
countSession := listCommitStatusesStatement(repo, sha, opts)
100-
countSession = opts.setSessionPagination(countSession)
100+
countSession = setSessionPagination(countSession, opts)
101101
maxResults, err := countSession.Count(new(CommitStatus))
102102
if err != nil {
103103
log.Error("Count PRs: %v", err)
@@ -106,7 +106,7 @@ func GetCommitStatuses(repo *Repository, sha string, opts *CommitStatusOptions)
106106

107107
statuses := make([]*CommitStatus, 0, opts.PageSize)
108108
findSession := listCommitStatusesStatement(repo, sha, opts)
109-
findSession = opts.setSessionPagination(findSession)
109+
findSession = setSessionPagination(findSession, opts)
110110
sortCommitStatusesSession(findSession, opts.SortType)
111111
return statuses, maxResults, findSession.Find(&statuses)
112112
}
@@ -149,7 +149,7 @@ func getLatestCommitStatus(e Engine, repoID int64, sha string, listOptions ListO
149149
Select("max( id ) as id").
150150
GroupBy("context_hash").OrderBy("max( id ) desc")
151151

152-
sess = listOptions.setSessionPagination(sess)
152+
sess = setSessionPagination(sess, &listOptions)
153153

154154
err := sess.Find(&ids)
155155
if err != nil {

models/gpg_key.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func ListGPGKeys(uid int64, listOptions ListOptions) ([]*GPGKey, error) {
6464
func listGPGKeys(e Engine, uid int64, listOptions ListOptions) ([]*GPGKey, error) {
6565
sess := e.Table(&GPGKey{}).Where("owner_id=? AND primary_key_id=''", uid)
6666
if listOptions.Page != 0 {
67-
sess = listOptions.setSessionPagination(sess)
67+
sess = setSessionPagination(sess, &listOptions)
6868
}
6969

7070
keys := make([]*GPGKey, 0, 2)

models/issue_comment.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ func findComments(e Engine, opts *FindCommentsOptions) ([]*Comment, error) {
10071007
}
10081008

10091009
if opts.Page != 0 {
1010-
sess = opts.setSessionPagination(sess)
1010+
sess = setSessionPagination(sess, opts)
10111011
}
10121012

10131013
// WARNING: If you change this order you will need to fix createCodeComment

models/issue_label.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ func getLabelsByRepoID(e Engine, repoID int64, sortType string, listOptions List
459459
}
460460

461461
if listOptions.Page != 0 {
462-
sess = listOptions.setSessionPagination(sess)
462+
sess = setSessionPagination(sess, &listOptions)
463463
}
464464

465465
return labels, sess.Find(&labels)
@@ -576,7 +576,7 @@ func getLabelsByOrgID(e Engine, orgID int64, sortType string, listOptions ListOp
576576
}
577577

578578
if listOptions.Page != 0 {
579-
sess = listOptions.setSessionPagination(sess)
579+
sess = setSessionPagination(sess, &listOptions)
580580
}
581581

582582
return labels, sess.Find(&labels)

models/issue_milestone.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ func GetMilestones(opts GetMilestonesOption) (MilestoneList, int64, error) {
408408
sess := x.Where(opts.toCond())
409409

410410
if opts.Page != 0 {
411-
sess = opts.setSessionPagination(sess)
411+
sess = setSessionPagination(sess, &opts)
412412
}
413413

414414
switch opts.SortType {

models/issue_reaction.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func findReactions(e Engine, opts FindReactionsOptions) ([]*Reaction, error) {
8787
In("reaction.`type`", setting.UI.Reactions).
8888
Asc("reaction.issue_id", "reaction.comment_id", "reaction.created_unix", "reaction.id")
8989
if opts.Page != 0 {
90-
e = opts.setEnginePagination(e)
90+
e = setEnginePagination(e, &opts)
9191

9292
reactions := make([]*Reaction, 0, opts.PageSize)
9393
return reactions, e.Find(&reactions)

models/issue_stopwatch.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func GetUserStopwatches(userID int64, listOptions ListOptions) ([]*Stopwatch, er
4545
sws := make([]*Stopwatch, 0, 8)
4646
sess := x.Where("stopwatch.user_id = ?", userID)
4747
if listOptions.Page != 0 {
48-
sess = listOptions.setSessionPagination(sess)
48+
sess = setSessionPagination(sess, &listOptions)
4949
}
5050

5151
err := sess.Find(&sws)

models/issue_tracked_time.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func (opts *FindTrackedTimesOptions) toSession(e Engine) Engine {
113113
sess = sess.Where(opts.toCond())
114114

115115
if opts.Page != 0 {
116-
sess = opts.setEnginePagination(sess)
116+
sess = setEnginePagination(sess, opts)
117117
}
118118

119119
return sess

models/issue_watch.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func getIssueWatchers(e Engine, issueID int64, listOptions ListOptions) (IssueWa
111111
Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id")
112112

113113
if listOptions.Page != 0 {
114-
sess = listOptions.setSessionPagination(sess)
114+
sess = setSessionPagination(sess, &listOptions)
115115
watches := make([]*IssueWatch, 0, listOptions.PageSize)
116116
return watches, sess.Find(&watches)
117117
}

models/list_options.go

+60-19
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,49 @@ import (
1010
"xorm.io/xorm"
1111
)
1212

13-
// ListOptions options to paginate results
14-
type ListOptions struct {
15-
PageSize int
16-
Page int // start from 1
13+
// Paginator is the base for different ListOptions types
14+
type Paginator interface {
15+
GetSkipTake() (skip, take int)
16+
GetStartEnd() (start, end int)
1717
}
1818

19-
func (opts *ListOptions) getPaginatedSession() *xorm.Session {
20-
opts.setDefaultValues()
19+
// getPaginatedSession creates a paginated database session
20+
func getPaginatedSession(p Paginator) *xorm.Session {
21+
skip, take := p.GetSkipTake()
2122

22-
return x.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
23+
return x.Limit(take, skip)
2324
}
2425

25-
func (opts *ListOptions) setSessionPagination(sess *xorm.Session) *xorm.Session {
26-
opts.setDefaultValues()
26+
// setSessionPagination sets pagination for a database session
27+
func setSessionPagination(sess *xorm.Session, p Paginator) *xorm.Session {
28+
skip, take := p.GetSkipTake()
2729

28-
if opts.PageSize <= 0 {
29-
return sess
30-
}
31-
return sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
30+
return sess.Limit(take, skip)
3231
}
3332

34-
func (opts *ListOptions) setEnginePagination(e Engine) Engine {
35-
opts.setDefaultValues()
33+
// setSessionPagination sets pagination for a database engine
34+
func setEnginePagination(e Engine, p Paginator) Engine {
35+
skip, take := p.GetSkipTake()
36+
37+
return e.Limit(take, skip)
38+
}
39+
40+
// ListOptions options to paginate results
41+
type ListOptions struct {
42+
PageSize int
43+
Page int // start from 1
44+
}
3645

37-
return e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
46+
// GetSkipTake returns the skip and take values
47+
func (opts *ListOptions) GetSkipTake() (skip, take int) {
48+
opts.setDefaultValues()
49+
return (opts.Page - 1) * opts.PageSize, opts.PageSize
3850
}
3951

4052
// GetStartEnd returns the start and end of the ListOptions
4153
func (opts *ListOptions) GetStartEnd() (start, end int) {
42-
opts.setDefaultValues()
43-
start = (opts.Page - 1) * opts.PageSize
44-
end = start + opts.PageSize
54+
start, take := opts.GetSkipTake()
55+
end = start + take
4556
return
4657
}
4758

@@ -56,3 +67,33 @@ func (opts *ListOptions) setDefaultValues() {
5667
opts.Page = 1
5768
}
5869
}
70+
71+
// AbsoluteListOptions absolute options to paginate results
72+
type AbsoluteListOptions struct {
73+
skip int
74+
take int
75+
}
76+
77+
// NewAbsoluteListOptions creates a list option with applied limits
78+
func NewAbsoluteListOptions(skip, take int) *AbsoluteListOptions {
79+
if skip < 0 {
80+
skip = 0
81+
}
82+
if take <= 0 {
83+
take = setting.API.DefaultPagingNum
84+
}
85+
if take > setting.API.MaxResponseItems {
86+
take = setting.API.MaxResponseItems
87+
}
88+
return &AbsoluteListOptions{skip, take}
89+
}
90+
91+
// GetSkipTake returns the skip and take values
92+
func (opts *AbsoluteListOptions) GetSkipTake() (skip, take int) {
93+
return opts.skip, opts.take
94+
}
95+
96+
// GetStartEnd returns the start and end values
97+
func (opts *AbsoluteListOptions) GetStartEnd() (start, end int) {
98+
return opts.skip, opts.skip + opts.take
99+
}

models/list_options_test.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2021 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package models
6+
7+
import (
8+
"testing"
9+
10+
"code.gitea.io/gitea/modules/setting"
11+
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
func TestPaginator(t *testing.T) {
16+
cases := []struct {
17+
Paginator
18+
Skip int
19+
Take int
20+
Start int
21+
End int
22+
}{
23+
{
24+
Paginator: &ListOptions{Page: -1, PageSize: -1},
25+
Skip: 0,
26+
Take: setting.API.DefaultPagingNum,
27+
Start: 0,
28+
End: setting.API.DefaultPagingNum,
29+
},
30+
{
31+
Paginator: &ListOptions{Page: 2, PageSize: 10},
32+
Skip: 10,
33+
Take: 10,
34+
Start: 10,
35+
End: 20,
36+
},
37+
{
38+
Paginator: NewAbsoluteListOptions(-1, -1),
39+
Skip: 0,
40+
Take: setting.API.DefaultPagingNum,
41+
Start: 0,
42+
End: setting.API.DefaultPagingNum,
43+
},
44+
{
45+
Paginator: NewAbsoluteListOptions(2, 10),
46+
Skip: 2,
47+
Take: 10,
48+
Start: 2,
49+
End: 12,
50+
},
51+
}
52+
53+
for _, c := range cases {
54+
skip, take := c.Paginator.GetSkipTake()
55+
start, end := c.Paginator.GetStartEnd()
56+
57+
assert.Equal(t, c.Skip, skip)
58+
assert.Equal(t, c.Take, take)
59+
assert.Equal(t, c.Start, start)
60+
assert.Equal(t, c.End, end)
61+
}
62+
}

models/notification.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond {
110110
func (opts *FindNotificationOptions) ToSession(e Engine) *xorm.Session {
111111
sess := e.Where(opts.ToCond())
112112
if opts.Page != 0 {
113-
sess = opts.setSessionPagination(sess)
113+
sess = setSessionPagination(sess, opts)
114114
}
115115
return sess
116116
}

models/oauth2_application.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ func ListOAuth2Applications(uid int64, listOptions ListOptions) ([]*OAuth2Applic
275275
Desc("id")
276276

277277
if listOptions.Page != 0 {
278-
sess = listOptions.setSessionPagination(sess)
278+
sess = setSessionPagination(sess, &listOptions)
279279

280280
apps := make([]*OAuth2Application, 0, listOptions.PageSize)
281281
total, err := sess.FindAndCount(&apps)

models/org.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ func GetOrgUsersByUserID(uid int64, opts *SearchOrganizationsOptions) ([]*OrgUse
569569
}
570570

571571
if opts.PageSize != 0 {
572-
sess = opts.setSessionPagination(sess)
572+
sess = setSessionPagination(sess, opts)
573573
}
574574

575575
err := sess.
@@ -589,7 +589,7 @@ func getOrgUsersByOrgID(e Engine, opts *FindOrgMembersOpts) ([]*OrgUser, error)
589589
sess.And("is_public = ?", true)
590590
}
591591
if opts.ListOptions.PageSize > 0 {
592-
sess = opts.setSessionPagination(sess)
592+
sess = setSessionPagination(sess, opts)
593593

594594
ous := make([]*OrgUser, 0, opts.PageSize)
595595
return ous, sess.Find(&ous)

models/org_team.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func (t *Team) GetRepositories(opts *SearchTeamOptions) error {
168168
return t.getRepositories(x)
169169
}
170170

171-
return t.getRepositories(opts.getPaginatedSession())
171+
return t.getRepositories(getPaginatedSession(opts))
172172
}
173173

174174
func (t *Team) getMembers(e Engine) (err error) {
@@ -182,7 +182,7 @@ func (t *Team) GetMembers(opts *SearchMembersOptions) (err error) {
182182
return t.getMembers(x)
183183
}
184184

185-
return t.getMembers(opts.getPaginatedSession())
185+
return t.getMembers(getPaginatedSession(opts))
186186
}
187187

188188
// AddMember adds new membership of the team to the organization,

models/pull_list.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func PullRequests(baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest,
100100
log.Error("listPullRequestStatement: %v", err)
101101
return nil, maxResults, err
102102
}
103-
findSession = opts.setSessionPagination(findSession)
103+
findSession = setSessionPagination(findSession, opts)
104104
prs := make([]*PullRequest, 0, opts.PageSize)
105105
return prs, maxResults, findSession.Find(&prs)
106106
}

models/release.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions) ([]*Release, er
208208
Where(opts.toConds(repoID))
209209

210210
if opts.PageSize != 0 {
211-
sess = opts.setSessionPagination(sess)
211+
sess = setSessionPagination(sess, &opts.ListOptions)
212212
}
213213

214214
rels := make([]*Release, 0, opts.PageSize)

models/repo.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -1770,7 +1770,7 @@ func GetUserRepositories(opts *SearchRepoOptions) ([]*Repository, int64, error)
17701770

17711771
sess.Where(cond).OrderBy(opts.OrderBy.String())
17721772
repos := make([]*Repository, 0, opts.PageSize)
1773-
return repos, count, opts.setSessionPagination(sess).Find(&repos)
1773+
return repos, count, setSessionPagination(sess, opts).Find(&repos)
17741774
}
17751775

17761776
// GetUserMirrorRepositories returns a list of mirror repositories of given user.
@@ -2061,7 +2061,7 @@ func (repo *Repository) GetForks(listOptions ListOptions) ([]*Repository, error)
20612061
return forks, x.Find(&forks, &Repository{ForkID: repo.ID})
20622062
}
20632063

2064-
sess := listOptions.getPaginatedSession()
2064+
sess := getPaginatedSession(&listOptions)
20652065
forks := make([]*Repository, 0, listOptions.PageSize)
20662066
return forks, sess.Find(&forks, &Repository{ForkID: repo.ID})
20672067
}

models/repo_collaboration.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func (repo *Repository) getCollaborations(e Engine, listOptions ListOptions) ([]
6565
return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repo.ID})
6666
}
6767

68-
e = listOptions.setEnginePagination(e)
68+
e = setEnginePagination(e, &listOptions)
6969

7070
collaborations := make([]*Collaboration, 0, listOptions.PageSize)
7171
return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repo.ID})

models/repo_watch.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ func (repo *Repository) GetWatchers(opts ListOptions) ([]*User, error) {
165165
Join("LEFT", "watch", "`user`.id=`watch`.user_id").
166166
And("`watch`.mode<>?", RepoWatchModeDont)
167167
if opts.Page > 0 {
168-
sess = opts.setSessionPagination(sess)
168+
sess = setSessionPagination(sess, &opts)
169169
users := make([]*User, 0, opts.PageSize)
170170

171171
return users, sess.Find(&users)

models/review.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ func findReviews(e Engine, opts FindReviewOptions) ([]*Review, error) {
195195
reviews := make([]*Review, 0, 10)
196196
sess := e.Where(opts.toCond())
197197
if opts.Page > 0 {
198-
sess = opts.ListOptions.setSessionPagination(sess)
198+
sess = setSessionPagination(sess, &opts)
199199
}
200200
return reviews, sess.
201201
Asc("created_unix").

models/ssh_key.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ func SearchPublicKey(uid int64, fingerprint string) ([]*PublicKey, error) {
195195
func ListPublicKeys(uid int64, listOptions ListOptions) ([]*PublicKey, error) {
196196
sess := x.Where("owner_id = ? AND type != ?", uid, KeyTypePrincipal)
197197
if listOptions.Page != 0 {
198-
sess = listOptions.setSessionPagination(sess)
198+
sess = setSessionPagination(sess, &listOptions)
199199

200200
keys := make([]*PublicKey, 0, listOptions.PageSize)
201201
return keys, sess.Find(&keys)

0 commit comments

Comments
 (0)