Documentation
¶
Overview ¶
Package pagination allows construct the simple and safe cursor-based pagination for services.
Pagination parameter should be the last in repository method parameters:
type ItemFilterer interface {
FilterItems(ctx context.Context, params FilterParams, span *pagination.Span) ([]Items, error)
}
Basic repository implementation:
func (s *Storage) FilterItems(ctx context.Context, params FilterParams, span *pagination.Span) ([]Items, error) {
var id int64
if err := span.Pos.Bind(&id); err != nil {
return nil, ErrInvalidCursor
}
const spanSizeLimit = 100
limit := span.LimitSize(spanSizeLimit)
// use id and limit in database query, fetch items
// ...
if len(items) > 0 {
// advance cursor
id = items[len(items)-1].Id
}
span.SetLast(len(items) < limit)
return items, nil
}
Repository method using:
func handleGetItems(resp http.ResponseWriter, req *http.Request) {
// GET /items?limit=10&cursor=dGltZXN0YW1wOjE2MjI1NDg4MDA=
q := req.URL.Query()
cursor := q.Get("cursor")
limitStr := q.Get("limit")
limit, _ := strconv.Atoi(limitStr)
span, _ := NewSpan(cursor, limit)
items, _ := stor.FilterItems(req.Context(), FilterParams{}, span)
resp.Header().Add("X-Pagination-Cursor", span.Pos.EncodeToString())
// marshal response data
// ...
}
Compound cursor allows to use any sorting fields and order:
type Cursor struct {
T int64 // time
R int64 // rowid
}
cursor := Cursor {
T: time.Now().UnixMilli(),
R: math.MaxInt64,
}
span.Pos.Bind(&cursor)
The package supports only comparable values as cursor state. For example, unable to use slice as cursor or it's part. But you can use arrays.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Cursor ¶
type Cursor struct {
// contains filtered or unexported fields
}
Cursor keeps position of a collection between calls of repository method and hides the repository implementation details. Cursor allow transfer state across process boundaries. Zero value means starting position.
func ParseCursor ¶
ParseCursor parses string representation of the Cursor. Empty string treats as starting position.
Returns en errors in case invalid cursor.
func (*Cursor) Bind ¶
Bind binds state of the cursor with variable pointed by v. The variable value defines internal structure of the cursor. Changes of the variable will be change cursor state. v should be pointer of comparable value: struct, scalar.
Bind panics in case cursor misuse - if cursor state was not changed on previous iteration.
Don't use with Get/Set methods.
func (*Cursor) EncodeToString ¶
EncodeToString encodes cursor state to string. The string url-encoded and safe to use in url address. Empty string means cursor reach end of collection.
EncodeToString panics in case cursor misuse - if cursor state was not changed between iterations.
func (*Cursor) Get ¶
Get puts state of the cursor into variable pointed by v. v should be pointer of comparable value: struct, scalar.
Get panics in case cursor misuse - if cursor state was not changed on previous iteration.
Don't use with Bind method.
func (*Cursor) IsOutOfScope ¶
IsOutOfScope returns true in case the cursor reach end of collection.
func (*Cursor) MarkOutOfScope ¶
func (cur *Cursor) MarkOutOfScope()
MarkOutOfScope sets flag the cursor reach end of collection.
type Span ¶
type Span struct {
Pos *Cursor
// contains filtered or unexported fields
}
Span presents position and size of collection items chunk in the collection.
func NewFirstSpan ¶
NewFirstSpan returns a new span of the defined size and in the starting position.
func NewSpan ¶
NewSpan returns a new span of the defined size and in position defined by the cursor value.
func (*Span) LimitSize ¶
LimitSize limits size of the span by the maxSize value and returns the size.
func (*Span) LimitSize64 ¶
LimitSize64 limits size of the span by the maxSize value and returns the size.