Parcourir la source

Add Pagination on stack events (#3062)

* pagination on app events

* updating comments

* adding metadata back
Stefan McShane il y a 3 ans
Parent
commit
f8fa7afce0

+ 15 - 3
api/server/handlers/stacks/list_porter_app_events.go

@@ -4,6 +4,7 @@ import (
 	"errors"
 	"net/http"
 
+	"github.com/gorilla/schema"
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/apierrors"
@@ -11,6 +12,7 @@ import (
 	"github.com/porter-dev/porter/api/server/shared/requestutils"
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository/gorm/helpers"
 	"gorm.io/gorm"
 )
 
@@ -37,13 +39,21 @@ func (p *PorterAppEventListHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
 		return
 	}
 
+	pr := types.PaginationRequest{}
+	d := schema.NewDecoder()
+	err := d.Decode(&pr, r.URL.Query())
+	if err != nil {
+		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
 	app, err := p.Repo().PorterApp().ReadPorterAppByName(cluster.ID, stackName)
 	if err != nil {
 		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
 	}
 
-	porterApps, err := p.Repo().PorterAppEvent().ListEventsByPorterAppID(app.ID)
+	porterApps, paginatedResult, err := p.Repo().PorterAppEvent().ListEventsByPorterAppID(app.ID, helpers.WithPageSize(2), helpers.WithPage(int(pr.Page)))
 	if err != nil {
 		if !errors.Is(err, gorm.ErrRecordNotFound) {
 			p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(reqErr, http.StatusBadRequest))
@@ -53,7 +63,10 @@ func (p *PorterAppEventListHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
 
 	res := struct {
 		Events []types.PorterAppEvent `json:"events"`
-	}{}
+		types.PaginationResponse
+	}{
+		PaginationResponse: types.PaginationResponse(paginatedResult),
+	}
 	res.Events = make([]types.PorterAppEvent, 0)
 
 	for _, porterApp := range porterApps {
@@ -61,7 +74,6 @@ func (p *PorterAppEventListHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
 			continue
 		}
 		pa := porterApp.ToPorterAppEvent()
-		pa.Metadata = nil
 		res.Events = append(res.Events, pa)
 	}
 	p.WriteResult(w, r, res)

+ 1 - 0
api/types/incident.go

@@ -46,6 +46,7 @@ type IncidentMeta struct {
 	PorterDocLink           string             `json:"porter_doc_link"`
 }
 
+// PaginationRequest allows for conveniently specifying pagination parameters. These can be parsed from a url using gorilla/schema.
 type PaginationRequest struct {
 	Page int64 `schema:"page"`
 }

+ 42 - 0
internal/repository/gorm/helpers/helpers.go

@@ -0,0 +1,42 @@
+package helpers
+
+import (
+	"math"
+
+	"gorm.io/gorm"
+)
+
+type PaginatedResult struct {
+	NumPages    int64
+	CurrentPage int64
+	NextPage    int64 `json:"next_page,omitempty"`
+}
+
+func Paginate(db *gorm.DB, pagination *PaginatedResult, opts ...QueryOption) func(db *gorm.DB) *gorm.DB {
+	q := Query{
+		PageSize: 50,
+		Page:     0,
+	}
+
+	for _, opt := range opts {
+		opt(&q)
+	}
+
+	var totalRows int64
+	db.Count(&totalRows)
+
+	offset := (q.Page - 1) * q.PageSize
+
+	pagination.NumPages = int64(math.Ceil(float64(totalRows) / float64(q.PageSize)))
+	pagination.CurrentPage = int64(q.Page)
+	pagination.NextPage = int64(q.Page + 1)
+	if pagination.CurrentPage >= pagination.NumPages {
+		pagination.NextPage = pagination.NumPages
+	}
+
+	return func(db *gorm.DB) *gorm.DB {
+		return db.
+			Offset(offset).
+			Limit(q.PageSize)
+	}
+}

+ 23 - 0
internal/repository/gorm/helpers/query.go

@@ -0,0 +1,23 @@
+package helpers
+
+type Query struct {
+	PageSize int
+	Page     int
+}
+
+type QueryOption func(*Query)
+
+func WithPage(page int) func(q *Query) {
+	if page == 0 {
+		page = 1
+	}
+	return func(q *Query) {
+		q.Page = page
+	}
+}
+
+func WithPageSize(pageSize int) func(q *Query) {
+	return func(q *Query) {
+		q.PageSize = pageSize
+	}
+}

+ 10 - 6
internal/repository/gorm/porter_app_event.go

@@ -8,6 +8,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/porter-dev/porter/internal/models"
 	"github.com/porter-dev/porter/internal/repository"
+	"github.com/porter-dev/porter/internal/repository/gorm/helpers"
 	"gorm.io/gorm"
 )
 
@@ -22,22 +23,25 @@ func NewPorterAppEventRepository(db *gorm.DB) repository.PorterAppEventRepositor
 	return &PorterAppEventRepository{db}
 }
 
-func (repo *PorterAppEventRepository) ListEventsByPorterAppID(porterAppID uint) ([]*models.PorterAppEvent, error) {
+func (repo *PorterAppEventRepository) ListEventsByPorterAppID(porterAppID uint, opts ...helpers.QueryOption) ([]*models.PorterAppEvent, helpers.PaginatedResult, error) {
 	apps := []*models.PorterAppEvent{}
+	paginatedResult := helpers.PaginatedResult{}
 
 	id := strconv.Itoa(int(porterAppID))
 	if id == "" {
-		return nil, errors.New("invalid porter app id supplied")
+		return nil, paginatedResult, errors.New("invalid porter app id supplied")
 	}
 
-	if err := repo.db.Where("porter_app_id = ?", id).Find(&apps).Error; err != nil {
-		fmt.Println("STEFAN", err)
+	db := repo.db.Model(&models.PorterAppEvent{})
+	db = db.Scopes(helpers.Paginate(db, &paginatedResult, opts...))
+
+	if err := db.Where("porter_app_id = ?", id).Find(&apps).Error; err != nil {
 		if !errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, err
+			return nil, paginatedResult, err
 		}
 	}
 
-	return apps, nil
+	return apps, paginatedResult, nil
 }
 
 func (repo *PorterAppEventRepository) EventByID(eventID uuid.UUID) (*models.PorterAppEvent, error) {

+ 2 - 1
internal/repository/porter_app_event.go

@@ -3,10 +3,11 @@ package repository
 import (
 	"github.com/google/uuid"
 	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository/gorm/helpers"
 )
 
 // PorterAppEventRepository represents the set of queries on the PorterAppEvent model
 type PorterAppEventRepository interface {
-	ListEventsByPorterAppID(porterAppID uint) ([]*models.PorterAppEvent, error)
+	ListEventsByPorterAppID(porterAppID uint, opts ...helpers.QueryOption) ([]*models.PorterAppEvent, helpers.PaginatedResult, error)
 	EventByID(eventID uuid.UUID) (*models.PorterAppEvent, error)
 }

+ 3 - 2
internal/repository/test/porter_app_event.go

@@ -6,6 +6,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/porter-dev/porter/internal/models"
 	"github.com/porter-dev/porter/internal/repository"
+	"github.com/porter-dev/porter/internal/repository/gorm/helpers"
 )
 
 type PorterAppEventRepository struct {
@@ -16,8 +17,8 @@ func NewPorterAppEventRepository(canQuery bool, failingMethods ...string) reposi
 	return &PorterAppEventRepository{canQuery: false}
 }
 
-func (repo *PorterAppEventRepository) ListEventsByPorterAppID(porterAppID uint) ([]*models.PorterAppEvent, error) {
-	return nil, errors.New("cannot write database")
+func (repo *PorterAppEventRepository) ListEventsByPorterAppID(porterAppID uint, opts ...helpers.QueryOption) ([]*models.PorterAppEvent, helpers.PaginatedResult, error) {
+	return nil, helpers.PaginatedResult{}, errors.New("cannot write database")
 }
 
 func (repo *PorterAppEventRepository) EventByID(eventID uuid.UUID) (*models.PorterAppEvent, error) {