diff --git a/controller/controller_test.go b/controller/controller_test.go index 7c68186..c904429 100644 --- a/controller/controller_test.go +++ b/controller/controller_test.go @@ -30,6 +30,6 @@ func TestMain(m *testing.M) { } func newContext(url string) echo.Context { - req := httptest.NewRequest(http.MethodPost, url, strings.NewReader("")) + req := httptest.NewRequest(http.MethodGet, url, strings.NewReader("")) return c.Web.NewContext(req, httptest.NewRecorder()) } diff --git a/controller/page.go b/controller/page.go index ed388dc..df324d0 100644 --- a/controller/page.go +++ b/controller/page.go @@ -104,26 +104,26 @@ type Page struct { } } -// NewPage creates and initiatizes a new page for a given request context -func NewPage(c echo.Context) Page { +// NewPage creates and initiatizes a new Page for a given request context +func NewPage(ctx echo.Context) Page { p := Page{ - Context: c, - ToURL: c.Echo().Reverse, - Path: c.Request().URL.Path, - URL: c.Request().URL.String(), + Context: ctx, + ToURL: ctx.Echo().Reverse, + Path: ctx.Request().URL.Path, + URL: ctx.Request().URL.String(), StatusCode: http.StatusOK, - Pager: NewPager(c), + Pager: NewPager(ctx, DefaultItemsPerPage), Headers: make(map[string]string), - RequestID: c.Response().Header().Get(echo.HeaderXRequestID), + RequestID: ctx.Response().Header().Get(echo.HeaderXRequestID), } p.IsHome = p.Path == "/" - if csrf := c.Get(echomw.DefaultCSRFConfig.ContextKey); csrf != nil { + if csrf := ctx.Get(echomw.DefaultCSRFConfig.ContextKey); csrf != nil { p.CSRF = csrf.(string) } - if u := c.Get(context.AuthenticatedUserKey); u != nil { + if u := ctx.Get(context.AuthenticatedUserKey); u != nil { p.IsAuth = true } diff --git a/controller/page_test.go b/controller/page_test.go index 1e5471e..8be5fa7 100644 --- a/controller/page_test.go +++ b/controller/page_test.go @@ -23,7 +23,7 @@ func TestNewPage(t *testing.T) { assert.Equal(t, "/", p.Path) assert.Equal(t, "/", p.URL) assert.Equal(t, http.StatusOK, p.StatusCode) - assert.Equal(t, NewPager(ctx), p.Pager) + assert.Equal(t, NewPager(ctx, DefaultItemsPerPage), p.Pager) assert.Empty(t, p.Headers) assert.True(t, p.IsHome) assert.False(t, p.IsAuth) diff --git a/controller/pager.go b/controller/pager.go index 7e0158c..90f5168 100644 --- a/controller/pager.go +++ b/controller/pager.go @@ -10,23 +10,35 @@ import ( const ( // DefaultItemsPerPage stores the default amount of items per page DefaultItemsPerPage = 20 + + // PageQueryKey stores the query key used to indicate the current page + PageQueryKey = "page" ) +// Pager provides a mechanism to allow a user to page results via a query parameter type Pager struct { - Items int - Page int + // Items stores the total amount of items in the result set + Items int + + // Page stores the current page number + Page int + + // ItemsPerPage stores the amount of items to display per page ItemsPerPage int - Pages int + + // Pages stores the total amount of pages in the result set + Pages int } -func NewPager(c echo.Context) Pager { +// NewPager creates a new Pager +func NewPager(ctx echo.Context, itemsPerPage int) Pager { p := Pager{ - ItemsPerPage: DefaultItemsPerPage, + ItemsPerPage: itemsPerPage, Page: 1, } - if page := c.QueryParam("page"); page != "" { - if pageInt, err := strconv.Atoi(page); err != nil { + if page := ctx.QueryParam(PageQueryKey); page != "" { + if pageInt, err := strconv.Atoi(page); err == nil { if pageInt > 0 { p.Page = pageInt } @@ -36,6 +48,9 @@ func NewPager(c echo.Context) Pager { return p } +// SetItems sets the amount of items in total for the pager and calculate the amount +// of total pages based off on the item per page. +// This should be used rather than setting either items or pages directly. func (p *Pager) SetItems(items int) { p.Items = items p.Pages = int(math.Ceil(float64(items) / float64(p.ItemsPerPage))) @@ -45,14 +60,18 @@ func (p *Pager) SetItems(items int) { } } +// IsBeginning determines if the pager is at the beginning of the pages func (p *Pager) IsBeginning() bool { return p.Page == 1 } +// IsEnd determines if the pager is at the end of the pages func (p *Pager) IsEnd() bool { return p.Page >= p.Pages } +// GetOffset determines the offset of the results in order to get the items for +// the current page func (p *Pager) GetOffset() int { if p.Page == 0 { p.Page = 1 diff --git a/controller/pager_test.go b/controller/pager_test.go new file mode 100644 index 0000000..47806e4 --- /dev/null +++ b/controller/pager_test.go @@ -0,0 +1,65 @@ +package controller + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewPager(t *testing.T) { + ctx := newContext("/") + pgr := NewPager(ctx, 10) + assert.Equal(t, 10, pgr.ItemsPerPage) + assert.Equal(t, 1, pgr.Page) + assert.Equal(t, 0, pgr.Items) + assert.Equal(t, 0, pgr.Pages) + + ctx = newContext(fmt.Sprintf("/abc?%s=%d", PageQueryKey, 2)) + pgr = NewPager(ctx, 10) + assert.Equal(t, 2, pgr.Page) + + ctx = newContext(fmt.Sprintf("/abc?%s=%d", PageQueryKey, -2)) + pgr = NewPager(ctx, 10) + assert.Equal(t, 1, pgr.Page) +} + +func TestPager_SetItems(t *testing.T) { + ctx := newContext("/") + pgr := NewPager(ctx, 20) + pgr.SetItems(100) + assert.Equal(t, 100, pgr.Items) + assert.Equal(t, 5, pgr.Pages) +} + +func TestPager_IsBeginning(t *testing.T) { + ctx := newContext("/") + pgr := NewPager(ctx, 20) + pgr.Pages = 10 + assert.True(t, pgr.IsBeginning()) + pgr.Page = 2 + assert.False(t, pgr.IsBeginning()) + pgr.Page = 1 + assert.True(t, pgr.IsBeginning()) +} + +func TestPager_IsEnd(t *testing.T) { + ctx := newContext("/") + pgr := NewPager(ctx, 20) + pgr.Pages = 10 + assert.False(t, pgr.IsEnd()) + pgr.Page = 10 + assert.True(t, pgr.IsEnd()) + pgr.Page = 1 + assert.False(t, pgr.IsEnd()) +} + +func TestPager_GetOffset(t *testing.T) { + ctx := newContext("/") + pgr := NewPager(ctx, 20) + assert.Equal(t, 0, pgr.GetOffset()) + pgr.Page = 2 + assert.Equal(t, 20, pgr.GetOffset()) + pgr.Page = 3 + assert.Equal(t, 40, pgr.GetOffset()) +}