paging

package module
v0.0.0-...-a21a33c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 14, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package paging provides cursor-based pagination utilities for efficient large dataset traversal in web APIs.

Cursor-based pagination is superior to offset-based pagination for:

  • Large datasets (no performance degradation with deep pages)
  • Real-time data (handles insertions/deletions gracefully)
  • Consistent results (no duplicates or missing items)
  • Scalability (constant-time lookups)

Basic Usage

Create pagination parameters from request:

params := &paging.Params{
    Cursor: r.URL.Query().Get("cursor"),
    Limit:  20,
}

Execute paginated query and build response:

items, nextCursor := queryItems(params.Cursor, params.Limit)

result := paging.NewResult(items, nextCursor, params.Limit)
// Returns: {items: [...], next_cursor: "...", has_more: true}

Cursor Encoding

The package handles cursor encoding/decoding automatically:

// Encode a cursor value (e.g., last item ID)
cursor := paging.EncodeCursor("last-item-id")

// Decode cursor for querying
value, err := paging.DecodeCursor(cursor)
if err != nil {
    return paging.ErrInvalidCursor
}

Custom Cursor Providers

Implement CursorProvider interface for custom cursor logic:

type Item struct {
    ID        string
    Timestamp int64
}

func (i *Item) GetCursorValue() string {
    return fmt.Sprintf("%d:%s", i.Timestamp, i.ID)
}

Response Structure

Standard pagination response:

{
  "items": [...],           // Array of results
  "next_cursor": "...",     // Cursor for next page
  "has_more": true,         // Whether more results exist
  "limit": 20               // Page size
}

Best Practices

  • Use composite cursors (timestamp + ID) for ordering stability
  • Set reasonable limit defaults (10-100 items)
  • Always validate and sanitize cursor values
  • Return empty next_cursor when no more results
  • Use indexes on cursor fields for optimal performance

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidCursor = errors.New("invalid cursor")
)

Functions

func DecodeCursor

func DecodeCursor(cursor string) (string, int64, error)

func EncodeCursor

func EncodeCursor(value string) string

Types

type CursorProvider

type CursorProvider interface {
	GetCursorValue() string
}

type PagingFunc

type PagingFunc[T CursorProvider] func(cursor string, limit int, direction string) (items []T, total int, err error)

type Params

type Params struct {
	Cursor    string `json:"cursor"`
	Limit     int    `json:"limit"`
	Direction string `json:"direction"` // "forward" or "backward"
}

func NormalizeParams

func NormalizeParams(params Params) Params

type Result

type Result[T CursorProvider] struct {
	Items      []T    `json:"items"`
	Total      int    `json:"total"`
	Cursor     string `json:"cursor,omitempty"`
	NextCursor string `json:"next_cursor,omitempty"`
	PrevCursor string `json:"prev_cursor,omitempty"`
	HasNext    bool   `json:"has_next"`
	HasPrev    bool   `json:"has_prev"`
}

func Paginate

func Paginate[T CursorProvider](params Params, paginateFunc PagingFunc[T]) (Result[T], error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL