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

Commitea261a1

Browse files
authored
chore: add offset-based pagination support to aibridge list endpoint (#20393)
Necessary for the frontend to be able to paginate easily. Cursorpagination is good for fetching all events, but doesn't play very wellwhen a pagination component gets involved.Adds support for `?offset=x` to the existing endpoint. The cursor-basedpagination (`?after_id=x`) is still supported. The two pagination modesare mutually exclusive, and are documented as such. If both aresupplied, the request will be rejected.Also adds a `total` property to the response that contains the fullcount of items matching the filter. We already have indices in place soI don't think this will impact performance (or we can revisit it beforeGA).
1 parent01ff28d commitea261a1

File tree

17 files changed

+328
-48
lines changed

17 files changed

+328
-48
lines changed

‎coderd/apidoc/docs.go‎

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

‎coderd/apidoc/swagger.json‎

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

‎coderd/database/dbauthz/dbauthz.go‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,6 +1436,14 @@ func (q *querier) CleanTailnetTunnels(ctx context.Context) error {
14361436
returnq.db.CleanTailnetTunnels(ctx)
14371437
}
14381438

1439+
func (q*querier)CountAIBridgeInterceptions(ctx context.Context,arg database.CountAIBridgeInterceptionsParams) (int64,error) {
1440+
prep,err:=prepareSQLFilter(ctx,q.auth,policy.ActionRead,rbac.ResourceAibridgeInterception.Type)
1441+
iferr!=nil {
1442+
return0,xerrors.Errorf("(dev error) prepare sql filter: %w",err)
1443+
}
1444+
returnq.db.CountAuthorizedAIBridgeInterceptions(ctx,arg,prep)
1445+
}
1446+
14391447
func (q*querier)CountAuditLogs(ctx context.Context,arg database.CountAuditLogsParams) (int64,error) {
14401448
// Shortcut if the user is an owner. The SQL filter is noticeable,
14411449
// and this is an easy win for owners. Which is the common case.
@@ -5868,3 +5876,10 @@ func (q *querier) ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg d
58685876
// database.Store interface, so dbauthz needs to implement it.
58695877
returnq.ListAIBridgeInterceptions(ctx,arg)
58705878
}
5879+
5880+
func (q*querier)CountAuthorizedAIBridgeInterceptions(ctx context.Context,arg database.CountAIBridgeInterceptionsParams,_ rbac.PreparedAuthorized) (int64,error) {
5881+
// TODO: Delete this function, all CountAIBridgeInterceptions should be authorized. For now just call CountAIBridgeInterceptions on the authz querier.
5882+
// This cannot be deleted for now because it's included in the
5883+
// database.Store interface, so dbauthz needs to implement it.
5884+
returnq.CountAIBridgeInterceptions(ctx,arg)
5885+
}

‎coderd/database/dbauthz/dbauthz_test.go‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4549,6 +4549,20 @@ func (s *MethodTestSuite) TestAIBridge() {
45494549
check.Args(params,emptyPreparedAuthorized{}).Asserts()
45504550
}))
45514551

4552+
s.Run("CountAIBridgeInterceptions",s.Mocked(func(db*dbmock.MockStore,faker*gofakeit.Faker,check*expects) {
4553+
params:= database.CountAIBridgeInterceptionsParams{}
4554+
db.EXPECT().CountAuthorizedAIBridgeInterceptions(gomock.Any(),params,gomock.Any()).Return(int64(0),nil).AnyTimes()
4555+
// No asserts here because SQLFilter.
4556+
check.Args(params).Asserts()
4557+
}))
4558+
4559+
s.Run("CountAuthorizedAIBridgeInterceptions",s.Mocked(func(db*dbmock.MockStore,faker*gofakeit.Faker,check*expects) {
4560+
params:= database.CountAIBridgeInterceptionsParams{}
4561+
db.EXPECT().CountAuthorizedAIBridgeInterceptions(gomock.Any(),params,gomock.Any()).Return(int64(0),nil).AnyTimes()
4562+
// No asserts here because SQLFilter.
4563+
check.Args(params,emptyPreparedAuthorized{}).Asserts()
4564+
}))
4565+
45524566
s.Run("ListAIBridgeTokenUsagesByInterceptionIDs",s.Mocked(func(db*dbmock.MockStore,faker*gofakeit.Faker,check*expects) {
45534567
ids:= []uuid.UUID{{1}}
45544568
db.EXPECT().ListAIBridgeTokenUsagesByInterceptionIDs(gomock.Any(),ids).Return([]database.AIBridgeTokenUsage{},nil).AnyTimes()

‎coderd/database/dbmetrics/querymetrics.go‎

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

‎coderd/database/dbmock/dbmock.go‎

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

‎coderd/database/modelqueries.go‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ func (q *sqlQuerier) CountAuthorizedConnectionLogs(ctx context.Context, arg Coun
764764

765765
typeaibridgeQuerierinterface {
766766
ListAuthorizedAIBridgeInterceptions(ctx context.Context,argListAIBridgeInterceptionsParams,prepared rbac.PreparedAuthorized) ([]AIBridgeInterception,error)
767+
CountAuthorizedAIBridgeInterceptions(ctx context.Context,argCountAIBridgeInterceptionsParams,prepared rbac.PreparedAuthorized) (int64,error)
767768
}
768769

769770
func (q*sqlQuerier)ListAuthorizedAIBridgeInterceptions(ctx context.Context,argListAIBridgeInterceptionsParams,prepared rbac.PreparedAuthorized) ([]AIBridgeInterception,error) {
@@ -786,6 +787,7 @@ func (q *sqlQuerier) ListAuthorizedAIBridgeInterceptions(ctx context.Context, ar
786787
arg.Provider,
787788
arg.Model,
788789
arg.AfterID,
790+
arg.Offset,
789791
arg.Limit,
790792
)
791793
iferr!=nil {
@@ -816,6 +818,45 @@ func (q *sqlQuerier) ListAuthorizedAIBridgeInterceptions(ctx context.Context, ar
816818
returnitems,nil
817819
}
818820

821+
func (q*sqlQuerier)CountAuthorizedAIBridgeInterceptions(ctx context.Context,argCountAIBridgeInterceptionsParams,prepared rbac.PreparedAuthorized) (int64,error) {
822+
authorizedFilter,err:=prepared.CompileToSQL(ctx, regosql.ConvertConfig{
823+
VariableConverter:regosql.AIBridgeInterceptionConverter(),
824+
})
825+
iferr!=nil {
826+
return0,xerrors.Errorf("compile authorized filter: %w",err)
827+
}
828+
filtered,err:=insertAuthorizedFilter(countAIBridgeInterceptions,fmt.Sprintf(" AND %s",authorizedFilter))
829+
iferr!=nil {
830+
return0,xerrors.Errorf("insert authorized filter: %w",err)
831+
}
832+
833+
query:=fmt.Sprintf("-- name: CountAuthorizedAIBridgeInterceptions :one\n%s",filtered)
834+
rows,err:=q.db.QueryContext(ctx,query,
835+
arg.StartedAfter,
836+
arg.StartedBefore,
837+
arg.InitiatorID,
838+
arg.Provider,
839+
arg.Model,
840+
)
841+
iferr!=nil {
842+
return0,err
843+
}
844+
deferrows.Close()
845+
varcountint64
846+
forrows.Next() {
847+
iferr:=rows.Scan(&count);err!=nil {
848+
return0,err
849+
}
850+
}
851+
iferr:=rows.Close();err!=nil {
852+
return0,err
853+
}
854+
iferr:=rows.Err();err!=nil {
855+
return0,err
856+
}
857+
returncount,nil
858+
}
859+
819860
funcinsertAuthorizedFilter(querystring,replaceWithstring) (string,error) {
820861
if!strings.Contains(query,authorizedQueryPlaceholder) {
821862
return"",xerrors.Errorf("query does not contain authorized replace string, this is not an authorized query")

‎coderd/database/querier.go‎

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

‎coderd/database/queries.sql.go‎

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

‎coderd/database/queries/aibridge.sql‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,40 @@ ORDER BY
7575
created_atASC,
7676
idASC;
7777

78+
-- name: CountAIBridgeInterceptions :one
79+
SELECT
80+
COUNT(*)
81+
FROM
82+
aibridge_interceptions
83+
WHERE
84+
-- Filter by time frame
85+
CASE
86+
WHEN @started_after::timestamptz!='0001-01-01 00:00:00+00'::timestamptz THENaibridge_interceptions.started_at>= @started_after::timestamptz
87+
ELSE true
88+
END
89+
AND CASE
90+
WHEN @started_before::timestamptz!='0001-01-01 00:00:00+00'::timestamptz THENaibridge_interceptions.started_at<= @started_before::timestamptz
91+
ELSE true
92+
END
93+
-- Filter initiator_id
94+
AND CASE
95+
WHEN @initiator_id::uuid!='00000000-0000-0000-0000-000000000000'::uuid THENaibridge_interceptions.initiator_id= @initiator_id::uuid
96+
ELSE true
97+
END
98+
-- Filter provider
99+
AND CASE
100+
WHEN @provider::text!='' THENaibridge_interceptions.provider= @provider::text
101+
ELSE true
102+
END
103+
-- Filter model
104+
AND CASE
105+
WHEN @model::text!='' THENaibridge_interceptions.model= @model::text
106+
ELSE true
107+
END
108+
-- Authorize Filter clause will be injected below in ListAuthorizedAIBridgeInterceptions
109+
-- @authorize_filter
110+
;
111+
78112
-- name: ListAIBridgeInterceptions :many
79113
SELECT
80114
*
@@ -127,6 +161,7 @@ ORDER BY
127161
aibridge_interceptions.started_atDESC,
128162
aibridge_interceptions.idDESC
129163
LIMIT COALESCE(NULLIF(@limit_::integer,0),100)
164+
OFFSET @offset_
130165
;
131166

132167
-- name: ListAIBridgeTokenUsagesByInterceptionIDs :many

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp