Skip to content

Commit 67593b8

Browse files
authored
feat: add pagination for server entities (#1347)
1 parent 95f3ed1 commit 67593b8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+4863
-1536
lines changed

api/openapispec/docs.go

+1,486-464
Large diffs are not rendered by default.

api/openapispec/swagger.json

+1,486-464
Large diffs are not rendered by default.

api/openapispec/swagger.yaml

+856-321
Large diffs are not rendered by default.

pkg/domain/constant/global.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ const (
2222
ResourcePageDefault = 1
2323
ResourcePageSizeDefault = 100
2424
ResourcePageSizeLarge = 1000
25-
RunPageDefault = 1
26-
RunPageSizeDefault = 10
25+
CommonPageDefault = 1
26+
CommonPageSizeDefault = 10
2727
)

pkg/domain/entity/backend.go

+9
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ type Backend struct {
2525
UpdateTimestamp time.Time `yaml:"updateTimestamp,omitempty" json:"updateTimestamp,omitempty"`
2626
}
2727

28+
type BackendFilter struct {
29+
Pagination *Pagination
30+
}
31+
32+
type BackendListResult struct {
33+
Backends []*Backend
34+
Total int
35+
}
36+
2837
// Validate checks if the backend is valid.
2938
// It returns an error if the backend is not valid.
3039
func (w *Backend) Validate() error {

pkg/domain/entity/module.go

+7
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ type ModuleWithVersion struct {
4141
type ModuleFilter struct {
4242
// ModuleName is the name of the module to filter by.
4343
ModuleName string
44+
Pagination *Pagination
45+
}
46+
47+
type ModuleListResult struct {
48+
Modules []*Module
49+
ModulesWithVersion []*ModuleWithVersion
50+
Total int
4451
}
4552

4653
// Validate checks if the module is valid.

pkg/domain/entity/organization.go

+9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ type Organization struct {
2626
UpdateTimestamp time.Time `yaml:"updateTimestamp,omitempty" json:"updateTimestamp,omitempty"`
2727
}
2828

29+
type OrganizationFilter struct {
30+
Pagination *Pagination
31+
}
32+
33+
type OrganizationListResult struct {
34+
Organizations []*Organization
35+
Total int
36+
}
37+
2938
// Validate checks if the organization is valid.
3039
// It returns an error if the organization is not valid.
3140
func (p *Organization) Validate() error {

pkg/domain/entity/project.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,14 @@ type Project struct {
3434
}
3535

3636
type ProjectFilter struct {
37-
OrgID uint
38-
Name string
37+
OrgID uint
38+
Name string
39+
Pagination *Pagination
40+
}
41+
42+
type ProjectListResult struct {
43+
Projects []*Project
44+
Total int
3945
}
4046

4147
// Validate checks if the project is valid.

pkg/domain/entity/resource.go

+6
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ type ResourceFilter struct {
8686
ResourceType string
8787
KusionResourceID string
8888
Status string
89+
Pagination *Pagination
90+
}
91+
92+
type ResourceListResult struct {
93+
Resources []*Resource
94+
Total int
8995
}
9096

9197
// Validate checks if the resource is valid.

pkg/domain/entity/source.go

+6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ type Source struct {
3333

3434
type SourceFilter struct {
3535
SourceName string
36+
Pagination *Pagination
37+
}
38+
39+
type SourceListResult struct {
40+
Sources []*Source
41+
Total int
3642
}
3743

3844
// Validate checks if the source is valid.

pkg/domain/entity/stack.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,15 @@ type Stack struct {
4646
}
4747

4848
type StackFilter struct {
49-
OrgID uint
50-
ProjectID uint
51-
Path string
49+
OrgID uint
50+
ProjectID uint
51+
Path string
52+
Pagination *Pagination
53+
}
54+
55+
type StackListResult struct {
56+
Stacks []*Stack
57+
Total int
5258
}
5359

5460
// Validate checks if the stack is valid.

pkg/domain/entity/workspace.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,14 @@ func (s *SecretStore) ConvertToKusionSecretStore() (*v1.SecretStore, error) {
103103
}
104104

105105
type WorkspaceFilter struct {
106-
BackendID uint
107-
Name string
106+
BackendID uint
107+
Name string
108+
Pagination *Pagination
109+
}
110+
111+
type WorkspaceListResult struct {
112+
Workspaces []*Workspace
113+
Total int
108114
}
109115

110116
// Validate checks if the workspace is valid.

pkg/domain/repository/repository.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type OrganizationRepository interface {
2020
// GetByName retrieves a organization by its name.
2121
GetByName(ctx context.Context, name string) (*entity.Organization, error)
2222
// List retrieves all existing organizations.
23-
List(ctx context.Context) ([]*entity.Organization, error)
23+
List(ctx context.Context, filter *entity.OrganizationFilter) (*entity.OrganizationListResult, error)
2424
}
2525

2626
// ProjectRepository is an interface that defines the repository operations
@@ -37,7 +37,7 @@ type ProjectRepository interface {
3737
// GetByName retrieves a project by its name.
3838
GetByName(ctx context.Context, name string) (*entity.Project, error)
3939
// List retrieves all existing projects.
40-
List(ctx context.Context, filter *entity.ProjectFilter) ([]*entity.Project, error)
40+
List(ctx context.Context, filter *entity.ProjectFilter) (*entity.ProjectListResult, error)
4141
}
4242

4343
// StackRepository is an interface that defines the repository operations
@@ -52,7 +52,7 @@ type StackRepository interface {
5252
// Get retrieves a stack by its ID.
5353
Get(ctx context.Context, id uint) (*entity.Stack, error)
5454
// List retrieves all existing stacks.
55-
List(ctx context.Context, filter *entity.StackFilter) ([]*entity.Stack, error)
55+
List(ctx context.Context, filter *entity.StackFilter) (*entity.StackListResult, error)
5656
}
5757

5858
// SourceRepository is an interface that defines the repository operations
@@ -63,7 +63,7 @@ type SourceRepository interface {
6363
// GetByRemote retrieves a source by its remote.
6464
GetByRemote(ctx context.Context, remote string) (*entity.Source, error)
6565
// List retrieves all existing sources.
66-
List(ctx context.Context, filter *entity.SourceFilter) ([]*entity.Source, error)
66+
List(ctx context.Context, filter *entity.SourceFilter) (*entity.SourceListResult, error)
6767
// Create creates a new source.
6868
Create(ctx context.Context, source *entity.Source) error
6969
// Delete deletes a stack by its ID.
@@ -86,7 +86,7 @@ type WorkspaceRepository interface {
8686
// GetByName retrieves a workspace by its name.
8787
GetByName(ctx context.Context, name string) (*entity.Workspace, error)
8888
// List retrieves all existing workspace.
89-
List(ctx context.Context, filter *entity.WorkspaceFilter) ([]*entity.Workspace, error)
89+
List(ctx context.Context, filter *entity.WorkspaceFilter) (*entity.WorkspaceListResult, error)
9090
}
9191

9292
// BackendRepository is an interface that defines the repository operations
@@ -101,7 +101,7 @@ type BackendRepository interface {
101101
// Get retrieves a backend by its ID.
102102
Get(ctx context.Context, id uint) (*entity.Backend, error)
103103
// List retrieves all existing backend.
104-
List(ctx context.Context) ([]*entity.Backend, error)
104+
List(ctx context.Context, filter *entity.BackendFilter) (*entity.BackendListResult, error)
105105
}
106106

107107
// ResourceRepository is an interface that defines the repository operations
@@ -120,7 +120,7 @@ type ResourceRepository interface {
120120
// GetByKusionResourceURN retrieves a resource by its Kusion resource URN.
121121
GetByKusionResourceURN(ctx context.Context, urn string) (*entity.Resource, error)
122122
// List retrieves all existing resource.
123-
List(ctx context.Context, filter *entity.ResourceFilter) ([]*entity.Resource, error)
123+
List(ctx context.Context, filter *entity.ResourceFilter) (*entity.ResourceListResult, error)
124124
}
125125

126126
// ModuleRepository is an interface that defines the repository operations
@@ -135,7 +135,7 @@ type ModuleRepository interface {
135135
// Get retrieves a module by its name.
136136
Get(ctx context.Context, name string) (*entity.Module, error)
137137
// List retrives all the existing modules.
138-
List(ctx context.Context, filter *entity.ModuleFilter) ([]*entity.Module, error)
138+
List(ctx context.Context, filter *entity.ModuleFilter) (*entity.ModuleListResult, error)
139139
}
140140

141141
// RunRepository is an interface that defines the repository operations

pkg/domain/response/backend.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package response
2+
3+
import "kusionstack.io/kusion/pkg/domain/entity"
4+
5+
type PaginatedBackendResponse struct {
6+
Backends []*entity.Backend `json:"backends"`
7+
Total int `json:"total"`
8+
CurrentPage int `json:"currentPage"`
9+
PageSize int `json:"pageSize"`
10+
}

pkg/domain/response/module.go

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package response
2+
3+
import "kusionstack.io/kusion/pkg/domain/entity"
4+
5+
type PaginatedModuleResponse struct {
6+
Modules []*entity.Module `json:"modules"`
7+
ModulesWithVersion []*entity.ModuleWithVersion `json:"modulesWithVersion"`
8+
Total int `json:"total"`
9+
CurrentPage int `json:"currentPage"`
10+
PageSize int `json:"pageSize"`
11+
}

pkg/domain/response/organization.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package response
2+
3+
import "kusionstack.io/kusion/pkg/domain/entity"
4+
5+
type PaginatedOrganizationResponse struct {
6+
Organizations []*entity.Organization `json:"organizations"`
7+
Total int `json:"total"`
8+
CurrentPage int `json:"currentPage"`
9+
PageSize int `json:"pageSize"`
10+
}

pkg/domain/response/project.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package response
2+
3+
import "kusionstack.io/kusion/pkg/domain/entity"
4+
5+
type PaginatedProjectResponse struct {
6+
Projects []*entity.Project `json:"projects"`
7+
Total int `json:"total"`
8+
CurrentPage int `json:"currentPage"`
9+
PageSize int `json:"pageSize"`
10+
}

pkg/domain/response/source.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package response
2+
3+
import "kusionstack.io/kusion/pkg/domain/entity"
4+
5+
type PaginatedSourceResponse struct {
6+
Sources []*entity.Source `json:"sources"`
7+
Total int `json:"total"`
8+
CurrentPage int `json:"currentPage"`
9+
PageSize int `json:"pageSize"`
10+
}

pkg/domain/response/stack.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package response
2+
3+
import "kusionstack.io/kusion/pkg/domain/entity"
4+
5+
type PaginatedStackResponse struct {
6+
Stacks []*entity.Stack `json:"stacks"`
7+
Total int `json:"total"`
8+
CurrentPage int `json:"currentPage"`
9+
PageSize int `json:"pageSize"`
10+
}

pkg/domain/response/workspace.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package response
2+
3+
import "kusionstack.io/kusion/pkg/domain/entity"
4+
5+
type PaginatedWorkspaceResponse struct {
6+
Workspaces []*entity.Workspace `json:"workspaces"`
7+
Total int `json:"total"`
8+
CurrentPage int `json:"currentPage"`
9+
PageSize int `json:"pageSize"`
10+
}

pkg/infra/persistence/backend.go

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//nolint:dupl
12
package persistence
23

34
import (
@@ -95,10 +96,17 @@ func (r *backendRepository) Get(ctx context.Context, id uint) (*entity.Backend,
9596
}
9697

9798
// List retrieves all backends.
98-
func (r *backendRepository) List(ctx context.Context) ([]*entity.Backend, error) {
99+
func (r *backendRepository) List(ctx context.Context, filter *entity.BackendFilter) (*entity.BackendListResult, error) {
99100
var dataModel []BackendModel
100101
backendEntityList := make([]*entity.Backend, 0)
101-
result := r.db.WithContext(ctx).Find(&dataModel)
102+
103+
// Get total rows.
104+
var totalRows int64
105+
r.db.WithContext(ctx).Model(dataModel).Count(&totalRows)
106+
107+
// Fetch paginated data with offset and limit.
108+
offset := (filter.Pagination.Page - 1) * filter.Pagination.PageSize
109+
result := r.db.WithContext(ctx).Offset(offset).Limit(filter.Pagination.PageSize).Find(&dataModel)
102110
if result.Error != nil {
103111
return nil, result.Error
104112
}
@@ -109,5 +117,8 @@ func (r *backendRepository) List(ctx context.Context) ([]*entity.Backend, error)
109117
}
110118
backendEntityList = append(backendEntityList, backendEntity)
111119
}
112-
return backendEntityList, nil
120+
return &entity.BackendListResult{
121+
Backends: backendEntityList,
122+
Total: int(totalRows),
123+
}, nil
113124
}

pkg/infra/persistence/backend_test.go

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//nolint:dupl
12
package persistence
23

34
import (
@@ -9,6 +10,7 @@ import (
910
"gorm.io/gorm"
1011

1112
v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1"
13+
"kusionstack.io/kusion/pkg/domain/constant"
1214
"kusionstack.io/kusion/pkg/domain/entity"
1315
)
1416

@@ -139,14 +141,25 @@ func TestBackendRepository(t *testing.T) {
139141
expectedIDSecond uint = 2
140142
expectedNameSecond = "mockedBackend2"
141143
)
142-
sqlMock.ExpectQuery("SELECT .* FROM `backend`").
144+
145+
sqlMock.ExpectQuery("SELECT count(.*) FROM `backend`").
146+
WillReturnRows(
147+
sqlmock.NewRows([]string{"count"}).
148+
AddRow(2))
149+
150+
sqlMock.ExpectQuery("SELECT .* FROM `backend` .* IS NULL LIMIT").
143151
WillReturnRows(
144152
sqlmock.NewRows([]string{"id", "name"}).
145153
AddRow(expectedIDFirst, expectedNameFirst).
146154
AddRow(expectedIDSecond, expectedNameSecond))
147155

148-
actual, err := repo.List(context.Background())
156+
actual, err := repo.List(context.Background(), &entity.BackendFilter{
157+
Pagination: &entity.Pagination{
158+
Page: constant.CommonPageDefault,
159+
PageSize: constant.CommonPageSizeDefault,
160+
},
161+
})
149162
require.NoError(t, err)
150-
require.Len(t, actual, 2)
163+
require.Len(t, actual.Backends, 2)
151164
})
152165
}

pkg/infra/persistence/module.go

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//nolint:dupl
12
package persistence
23

34
import (
@@ -93,11 +94,19 @@ func (r *moduleRepository) Get(ctx context.Context, name string) (*entity.Module
9394
}
9495

9596
// List retrieves all the modules.
96-
func (r *moduleRepository) List(ctx context.Context, filter *entity.ModuleFilter) ([]*entity.Module, error) {
97+
func (r *moduleRepository) List(ctx context.Context, filter *entity.ModuleFilter) (*entity.ModuleListResult, error) {
9798
var dataModel []ModuleModel
9899
moduleEntityList := make([]*entity.Module, 0)
99100
pattern, args := GetModuleQuery(filter)
100-
result := r.db.WithContext(ctx).Where(pattern, args...).Find(&dataModel)
101+
searchResult := r.db.WithContext(ctx).Where(pattern, args...)
102+
103+
// Get total rows
104+
var totalRows int64
105+
searchResult.Model(dataModel).Count(&totalRows)
106+
107+
// Fetch paginated data from searchResult with offset and limit
108+
offset := (filter.Pagination.Page - 1) * filter.Pagination.PageSize
109+
result := searchResult.Offset(offset).Limit(filter.Pagination.PageSize).Find(&dataModel)
101110
if result.Error != nil {
102111
return nil, result.Error
103112
}
@@ -110,5 +119,8 @@ func (r *moduleRepository) List(ctx context.Context, filter *entity.ModuleFilter
110119
moduleEntityList = append(moduleEntityList, moduleEntity)
111120
}
112121

113-
return moduleEntityList, nil
122+
return &entity.ModuleListResult{
123+
Modules: moduleEntityList,
124+
Total: int(totalRows),
125+
}, nil
114126
}

0 commit comments

Comments
 (0)