README
¶
Paginator
A simple way to implement pagination in Golang.
Usage
package main
import (
"fmt"
"github.com/hinfinite/helm/pkg/paginator"
"github.com/hinfinite/helm/pkg/paginator/adapter"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"time"
)
type Post struct {
ID uint `gorm:"primary_key"`
Title string
Body string
PublishedAt time.Time
}
func main() {
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
if err != nil {
panic(fmt.Errorf("db connection error: %s", err))
}
if err := db.AutoMigrate(&Post{}); err != nil {
panic(err)
}
var posts []Post
q := db.Model(Post{}).Where("published_at > ?", time.Now())
p := paginator.New(adapter.NewGORMAdapter(q), 10)
p.SetPage(2)
if err = p.Results(&posts); err != nil {
panic(err)
}
for _, post := range posts {
fmt.Println(post.Title)
}
}
Some of other methods available:
p.HasNext()
p.HasPrev()
p.HasPages()
p.PageNums()
Adapters
An adapter must implement the Adapter
interface which has 2 methods:
- Nums - must return the number of results;
- Slice - must retrieve a slice for an offset and length.
This way you can create your own adapter for any kind of data source you want to paginate.
type Adapter interface {
Nums() (int64, error)
Slice(offset, length int, data interface{}) error
}
GORM Adapter
To paginate a GORM query builder.
q := db.Model(Post{}).Where("published_at > ?", time.Now())
p := paginator.New(adapter.NewGORMAdapter(q), 10)
Slice adapter
To paginate a slice.
var pages []int
p := paginator.New(adapter.NewSliceAdapter(pages), 10)
Result
// Paginate
var dataSlice []int
int size = 10
int page = 1
p := paginator.New(adapter.NewSliceAdapter(dataSlice), size)
dataSliceInCurrentPage := make([]int, 0)
// Note the data arguments must be the pointer to slice
pageResult, err := p.PageResults(page, &dataSliceInCurrentPage)
if err != nil {
// error handler
}
equivalent to
// Paginate
var dataSlice []int
int size = 10
int page = 1
p := paginator.New(adapter.NewSliceAdapter(dataSlice), size)
p.setPage(page)
dataSliceInCurrentPage := make([]int, 0)
// Note the data arguments must be the pointer to slice
err := p.Results(&dataSliceInCurrentPage)
if err != nil {
// error handler
}
pageResult, err := p.ToPageResults(page, dataSliceInCurrentPage)
if err != nil {
// error handler
}
Views
View models contains all necessary logic to render the paginator inside a template.
DefaultView
Use it if you want to render a paginator similar to the one from Google search.
< Prev 2 3 4 5 6 7 8 9 10 11 Next >
func main() {
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
if err != nil {
panic(fmt.Errorf("db connection error: %s", err))
}
db.AutoMigrate(&Post{})
var posts []Post
q := db.Model(Post{}).Where("published_at > ?", time.Now())
p := paginator.New(adapter.NewGORMAdapter(q), 10)
p.SetPage(7)
view := view.New(&p)
pages, _ := view.Pages()
fmt.Println(pages) // [2 3 4 5 6 7 8 9 10 11]
next, _ := view.Next()
fmt.Println(next) // 8
prev, _ := view.Prev()
fmt.Println(prev) // 6
current, _ := view.Current()
fmt.Println(current) // 7
}
Changelog
TODO
- More adapters
License
Paginator is licensed under the MIT License.
Documentation
¶
Index ¶
Constants ¶
View Source
const DefaultMaxPerPage = 10
DefaultMaxPerPage default number of records per page
Variables ¶
View Source
var (
// ErrNoPrevPage current page is first page
ErrNoPrevPage = errors.New("no previous page")
// ErrNoNextPage current page is last page
ErrNoNextPage = errors.New("no next page")
)
Functions ¶
This section is empty.
Types ¶
type Adapter ¶
type Adapter interface {
Nums() (int64, error)
Slice(offset, length int, data interface{}) error
}
Adapter any adapter must implement this interface
type Page ¶
type Page struct {
// total pages
TotalPages int `json:"totalPages,omitempty"`
// total elements size
TotalElements int64 `json:"totalElements,omitempty"`
// elements size in current page
NumberOfElements int `json:"numberOfElements,omitempty"`
// elements size in single page
Size int `json:"size,omitempty"`
// current page number
Number int `json:"number,omitempty"`
// stores the current page results into data argument which must be a pointer to a slice.
Content interface{} `json:"content,omitempty"`
}
type Paginator ¶
type Paginator interface {
SetPage(page int)
Page() (int, error)
Results(data interface{}) error
PageResults(page int, data interface{}) (*Page, error)
ToPageResults(data interface{}) (*Page, error)
Nums() (int64, error)
HasPages() (bool, error)
HasNext() (bool, error)
PrevPage() (int, error)
NextPage() (int, error)
HasPrev() (bool, error)
PageNums() (int, error)
}
Paginator interface
Click to show internal directories.
Click to hide internal directories.