Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2d3dc43

Browse files
authored
feat: Implement unified pagination and add template versions support (#1308)
* feat: Implement pagination for template versions* feat: Use unified pagination between users and template versions* Sync codepaths between users and template versions* Create requestOption type in codersdk and add test* Fix created_at edge case for pagination cursor in queries* feat: Add support for json omitempty and embedded structs in apitypings (#1318)* Add scripts/apitypings/main.go to Makefile
1 parentdc115b8 commit2d3dc43

File tree

18 files changed

+540
-167
lines changed

18 files changed

+540
-167
lines changed

‎Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ site/out/index.html: $(shell find ./site -not -path './site/node_modules/*' -typ
8383
# Restores GITKEEP files!
8484
git checkout HEAD site/out
8585

86-
site/src/api/typesGenerated.ts:$(shell find codersdk -type f -name '*.go')
86+
site/src/api/typesGenerated.ts:scripts/apitypings/main.go$(shell find codersdk -type f -name '*.go')
8787
go run scripts/apitypings/main.go> site/src/api/typesGenerated.ts
8888
cd site&& yarn run format:types
8989

‎coderd/database/databasefake/databasefake.go

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -172,25 +172,25 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
172172
q.mutex.RLock()
173173
deferq.mutex.RUnlock()
174174

175-
users:=q.users
175+
// Avoid side-effect of sorting.
176+
users:=make([]database.User,len(q.users))
177+
copy(users,q.users)
178+
176179
// Database orders by created_at
177-
sort.Slice(users,func(i,jint)bool {
178-
ifusers[i].CreatedAt.Equal(users[j].CreatedAt) {
180+
slices.SortFunc(users,func(a,b database.User)bool {
181+
ifa.CreatedAt.Equal(b.CreatedAt) {
179182
// Technically the postgres database also orders by uuid. So match
180183
// that behavior
181-
returnusers[i].ID.String()<users[j].ID.String()
184+
returna.ID.String()<b.ID.String()
182185
}
183-
returnusers[i].CreatedAt.Before(users[j].CreatedAt)
186+
returna.CreatedAt.Before(b.CreatedAt)
184187
})
185188

186-
ifparams.AfterUser!=uuid.Nil {
189+
ifparams.AfterID!=uuid.Nil {
187190
found:=false
188-
fori:=rangeusers {
189-
ifusers[i].ID==params.AfterUser {
191+
fori,v:=rangeusers {
192+
ifv.ID==params.AfterID {
190193
// We want to return all users after index i.
191-
ifi+1>=len(users) {
192-
return []database.User{},nil
193-
}
194194
users=users[i+1:]
195195
found=true
196196
break
@@ -199,7 +199,7 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
199199

200200
// If no users after the time, then we return an empty list.
201201
if!found {
202-
return[]database.User{},nil
202+
returnnil,sql.ErrNoRows
203203
}
204204
}
205205

@@ -227,7 +227,7 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
227227

228228
ifparams.OffsetOpt>0 {
229229
ifint(params.OffsetOpt)>len(users)-1 {
230-
return[]database.User{},nil
230+
returnnil,sql.ErrNoRows
231231
}
232232
users=users[params.OffsetOpt:]
233233
}
@@ -239,10 +239,7 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
239239
users=users[:params.LimitOpt]
240240
}
241241

242-
tmp:=make([]database.User,len(users))
243-
copy(tmp,users)
244-
245-
returntmp,nil
242+
returnusers,nil
246243
}
247244

248245
func (q*fakeQuerier)GetAllUserRoles(_ context.Context,userID uuid.UUID) (database.GetAllUserRolesRow,error) {
@@ -621,20 +618,62 @@ func (q *fakeQuerier) GetTemplateByOrganizationAndName(_ context.Context, arg da
621618
return database.Template{},sql.ErrNoRows
622619
}
623620

624-
func (q*fakeQuerier)GetTemplateVersionsByTemplateID(_ context.Context,templateID uuid.UUID) ([]database.TemplateVersion,error) {
621+
func (q*fakeQuerier)GetTemplateVersionsByTemplateID(_ context.Context,arg database.GetTemplateVersionsByTemplateIDParams) (version[]database.TemplateVersion,errerror) {
625622
q.mutex.RLock()
626623
deferq.mutex.RUnlock()
627624

628-
version:=make([]database.TemplateVersion,0)
629625
for_,templateVersion:=rangeq.templateVersions {
630-
iftemplateVersion.TemplateID.UUID.String()!=templateID.String() {
626+
iftemplateVersion.TemplateID.UUID.String()!=arg.TemplateID.String() {
631627
continue
632628
}
633629
version=append(version,templateVersion)
634630
}
631+
632+
// Database orders by created_at
633+
slices.SortFunc(version,func(a,b database.TemplateVersion)bool {
634+
ifa.CreatedAt.Equal(b.CreatedAt) {
635+
// Technically the postgres database also orders by uuid. So match
636+
// that behavior
637+
returna.ID.String()<b.ID.String()
638+
}
639+
returna.CreatedAt.Before(b.CreatedAt)
640+
})
641+
642+
ifarg.AfterID!=uuid.Nil {
643+
found:=false
644+
fori,v:=rangeversion {
645+
ifv.ID==arg.AfterID {
646+
// We want to return all users after index i.
647+
version=version[i+1:]
648+
found=true
649+
break
650+
}
651+
}
652+
653+
// If no users after the time, then we return an empty list.
654+
if!found {
655+
returnnil,sql.ErrNoRows
656+
}
657+
}
658+
659+
ifarg.OffsetOpt>0 {
660+
ifint(arg.OffsetOpt)>len(version)-1 {
661+
returnnil,sql.ErrNoRows
662+
}
663+
version=version[arg.OffsetOpt:]
664+
}
665+
666+
ifarg.LimitOpt>0 {
667+
ifint(arg.LimitOpt)>len(version) {
668+
arg.LimitOpt=int32(len(version))
669+
}
670+
version=version[:arg.LimitOpt]
671+
}
672+
635673
iflen(version)==0 {
636674
returnnil,sql.ErrNoRows
637675
}
676+
638677
returnversion,nil
639678
}
640679

‎coderd/database/querier.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries.sql.go

Lines changed: 54 additions & 19 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/templateversions.sql

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,33 @@ SELECT
44
FROM
55
template_versions
66
WHERE
7-
template_id= $1 :: uuid;
7+
template_id= @template_id :: uuid
8+
AND CASE
9+
-- This allows using the last element on a page as effectively a cursor.
10+
-- This is an important option for scripts that need to paginate without
11+
-- duplicating or missing data.
12+
WHEN @after_id :: uuid!='00000000-00000000-00000000-00000000' THEN (
13+
-- The pagination cursor is the last ID of the previous page.
14+
-- The query is ordered by the created_at field, so select all
15+
-- rows after the cursor.
16+
(created_at, id)> (
17+
SELECT
18+
created_at, id
19+
FROM
20+
template_versions
21+
WHERE
22+
id= @after_id
23+
)
24+
)
25+
ELSE true
26+
END
27+
ORDER BY
28+
-- Deterministic and consistent ordering of all rows, even if they share
29+
-- a timestamp. This is to ensure consistent pagination.
30+
(created_at, id)ASC OFFSET @offset_opt
31+
LIMIT
32+
-- A null limit means "no limit", so -1 means return all
33+
NULLIF(@limit_opt ::int,-1);
834

935
-- name: GetTemplateVersionByJobID :one
1036
SELECT

‎coderd/database/queries/users.sql

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,23 +77,20 @@ WHERE
7777
-- This allows using the last element on a page as effectively a cursor.
7878
-- This is an important option for scripts that need to paginate without
7979
-- duplicating or missing data.
80-
WHEN @after_user :: uuid!='00000000-00000000-00000000-00000000' THEN (
81-
-- The pagination cursor is the last user of the previous page.
82-
-- The query is ordered by the created_at field, so select all
83-
-- users after the cursor. We also want to include any users
84-
-- that share the created_at (super rare).
85-
created_at>= (
86-
SELECT
87-
created_at
88-
FROM
89-
users
90-
WHERE
91-
id= @after_user
92-
)
93-
-- Omit the cursor from the final.
94-
AND id!= @after_user
80+
WHEN @after_id :: uuid!='00000000-00000000-00000000-00000000' THEN (
81+
-- The pagination cursor is the last ID of the previous page.
82+
-- The query is ordered by the created_at field, so select all
83+
-- rows after the cursor.
84+
(created_at, id)> (
85+
SELECT
86+
created_at, id
87+
FROM
88+
users
89+
WHERE
90+
id= @after_id
9591
)
96-
ELSE true
92+
)
93+
ELSE true
9794
END
9895
-- Start filters
9996
-- Filter by name, email or username

‎coderd/pagination.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package coderd
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"strconv"
7+
8+
"github.com/google/uuid"
9+
10+
"github.com/coder/coder/coderd/httpapi"
11+
"github.com/coder/coder/codersdk"
12+
)
13+
14+
// parsePagination extracts pagination query params from the http request.
15+
// If an error is encountered, the error is written to w and ok is set to false.
16+
funcparsePagination(w http.ResponseWriter,r*http.Request) (p codersdk.Pagination,okbool) {
17+
var (
18+
afterID=uuid.Nil
19+
limit=-1// Default to no limit and return all results.
20+
offset=0
21+
)
22+
23+
varerrerror
24+
ifs:=r.URL.Query().Get("after_id");s!="" {
25+
afterID,err=uuid.Parse(r.URL.Query().Get("after_id"))
26+
iferr!=nil {
27+
httpapi.Write(w,http.StatusBadRequest, httpapi.Response{
28+
Message:fmt.Sprintf("after_id must be a valid uuid: %s",err.Error()),
29+
})
30+
returnp,false
31+
}
32+
}
33+
ifs:=r.URL.Query().Get("limit");s!="" {
34+
limit,err=strconv.Atoi(s)
35+
iferr!=nil {
36+
httpapi.Write(w,http.StatusBadRequest, httpapi.Response{
37+
Message:fmt.Sprintf("limit must be an integer: %s",err.Error()),
38+
})
39+
returnp,false
40+
}
41+
}
42+
ifs:=r.URL.Query().Get("offset");s!="" {
43+
offset,err=strconv.Atoi(s)
44+
iferr!=nil {
45+
httpapi.Write(w,http.StatusBadRequest, httpapi.Response{
46+
Message:fmt.Sprintf("offset must be an integer: %s",err.Error()),
47+
})
48+
returnp,false
49+
}
50+
}
51+
52+
return codersdk.Pagination{
53+
AfterID:afterID,
54+
Limit:limit,
55+
Offset:offset,
56+
},true
57+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp