Documentation
¶
Overview ¶
Package pagination provides comprehensive pagination support for the AuthSome framework.
This package implements both offset-based and cursor-based pagination patterns with full support for sorting, filtering, and search. All structs follow the Forge DTO tags specification for seamless integration with request binding and validation.
Features ¶
- Offset-based pagination (page/limit/offset)
- Cursor-based pagination for large datasets
- Sorting and ordering (ASC/DESC)
- Search and filtering support
- Complete metadata in responses (total count, pages, has_next/prev)
- Validation with sensible defaults
- Type-safe generic responses
- Base64 cursor encoding/decoding
- Zero-allocation validation
- Production-tested performance
Quick Start ¶
Offset-based pagination:
func (h *Handler) ListUsers(c *forge.Context) error {
var params pagination.PaginationParams
if err := c.BindQuery(¶ms); err != nil {
return c.JSON(400, ErrorResponse{Message: "invalid parameters"})
}
if err := params.Validate(); err != nil {
return c.JSON(400, ErrorResponse{Message: err.Error()})
}
users, total, err := h.userRepo.List(
c.Context(),
params.GetLimit(),
params.GetOffset(),
params.GetSortBy(),
params.GetOrder(),
)
if err != nil {
return c.JSON(500, ErrorResponse{Message: "failed to fetch users"})
}
response := pagination.NewPageResponse(users, total, ¶ms)
return c.JSON(200, response)
}
Cursor-based pagination:
func (h *Handler) ListPosts(c *forge.Context) error {
var params pagination.CursorParams
if err := c.BindQuery(¶ms); err != nil {
return c.JSON(400, ErrorResponse{Message: "invalid parameters"})
}
if err := params.Validate(); err != nil {
return c.JSON(400, ErrorResponse{Message: err.Error()})
}
cursorData, err := pagination.DecodeCursor(params.Cursor)
if err != nil {
return c.JSON(400, ErrorResponse{Message: "invalid cursor"})
}
posts, nextCursor, prevCursor, err := h.postRepo.ListCursor(
c.Context(), params.GetLimit()+1, cursorData, params.GetSortBy(), params.GetOrder(),
)
if err != nil {
return c.JSON(500, ErrorResponse{Message: "failed to fetch posts"})
}
response := pagination.NewCursorResponse(posts, nextCursor, prevCursor, ¶ms)
return c.JSON(200, response)
}
Configuration ¶
Constants can be adjusted for your use case:
const ( DefaultLimit = 10 // Default items per page MaxLimit = 10000 // Maximum items per page MinLimit = 1 // Minimum items per page )
Request Parameters ¶
Both PaginationParams and CursorParams support Forge DTO tags:
- json: JSON field name
- query: Query parameter name
- default: Default value
- validate: Validation rules
- example: OpenAPI example
Response Structure ¶
Responses include comprehensive metadata:
type PageResponse[T any] struct {
Data []T `json:"data"`
Pagination *PageMeta `json:"pagination,omitempty"` // For offset-based
Cursor *CursorMeta `json:"cursor,omitempty"` // For cursor-based
}
Performance ¶
Benchmarks on Apple M3 Max:
BenchmarkPaginationParams_Validate-16 430332202 2.771 ns/op 0 B/op 0 allocs/op BenchmarkEncodeCursor-16 3105051 391.6 ns/op 416 B/op 5 allocs/op BenchmarkDecodeCursor-16 1732579 691.3 ns/op 384 B/op 8 allocs/op
Best Practices ¶
1. Always validate parameters after binding:
if err := params.Validate(); err != nil {
return c.JSON(400, map[string]string{"error": err.Error()})
}
2. Use getter methods for safe defaults:
limit := params.GetLimit() // Returns default if not set
3. Choose the right pagination type:
- Offset: Good for small/medium datasets, supports jumping to pages
- Cursor: Better for large datasets, real-time data, infinite scroll
4. Index your database sort fields:
CREATE INDEX idx_users_created_at ON users(created_at); CREATE INDEX idx_posts_cursor ON posts(created_at DESC, id DESC);
5. Handle empty results gracefully:
if len(users) == 0 {
return c.JSON(200, pagination.NewEmptyPageResponse[User]())
}
Database Integration ¶
Example with Bun ORM:
func (r *userRepository) List(
ctx context.Context,
limit, offset int,
sortBy string,
order pagination.SortOrder,
) ([]*User, int64, error) {
var users []*User
query := r.db.NewSelect().
Model(&users).
Limit(limit).
Offset(offset).
Order(fmt.Sprintf("%s %s", sortBy, strings.ToUpper(string(order))))
total, err := query.ScanAndCount(ctx)
return users, int64(total), err
}
Thread Safety ¶
All methods are safe for concurrent use. The validation methods modify the receiver to set defaults but are designed to be called once per request.
Error Handling ¶
Validation errors are returned as standard Go errors with descriptive messages:
- "limit must be at least 1"
- "limit cannot exceed 10000"
- "offset cannot be negative"
- "page must be at least 1"
- "order must be 'asc' or 'desc'"
API Compatibility ¶
This package follows semantic versioning. The public API is stable and will not break between minor versions.
For detailed documentation and examples, see the README.md file.
Example (CursorEncoding) ¶
Example demonstrates cursor encoding and decoding
package main
import (
"fmt"
"time"
"github.com/xraph/authsome/core/pagination"
)
func main() {
// Encode cursor
id := "user_123"
timestamp := time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC)
value := "alice"
encoded, err := pagination.EncodeCursor(id, timestamp, value)
if err != nil {
fmt.Printf("Encoding error: %v\n", err)
return
}
// Decode cursor
decoded, err := pagination.DecodeCursor(encoded)
if err != nil {
fmt.Printf("Decoding error: %v\n", err)
return
}
fmt.Printf("ID: %s\n", decoded.ID)
fmt.Printf("Value: %s\n", decoded.Value)
}
Output: ID: user_123 Value: alice
Example (CursorPagination) ¶
Example demonstrates cursor-based pagination
package main
import (
"fmt"
"time"
"github.com/xraph/authsome/core/pagination"
)
// User represents a sample user model
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
func main() {
params := &pagination.CursorParams{
BaseRequestParams: pagination.BaseRequestParams{
Order: pagination.SortOrderDesc,
},
Limit: 10,
}
if err := params.Validate(); err != nil {
fmt.Printf("Validation error: %v\n", err)
return
}
// Simulate fetching posts
posts := []User{
{ID: "1", Name: "Post 1", CreatedAt: time.Now()},
{ID: "2", Name: "Post 2", CreatedAt: time.Now()},
}
// Generate next cursor
nextCursor, _ := pagination.EncodeCursor("2", time.Now(), "")
// Create response
response := pagination.NewCursorResponse(posts, nextCursor, "", params)
fmt.Printf("Item count: %d\n", response.Cursor.Count)
fmt.Printf("Has next: %v\n", response.Cursor.HasNext)
fmt.Printf("Has cursor: %v\n", response.Cursor.NextCursor != "")
}
Output: Item count: 2 Has next: true Has cursor: true
Example (EmptyResponse) ¶
Example demonstrates empty response handling
package main
import (
"fmt"
"time"
"github.com/xraph/authsome/core/pagination"
)
// User represents a sample user model
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
func main() {
response := pagination.NewEmptyPageResponse[User]()
fmt.Printf("Data count: %d\n", len(response.Data))
fmt.Printf("Total: %d\n", response.Pagination.Total)
fmt.Printf("Has next: %v\n", response.Pagination.HasNext)
}
Output: Data count: 0 Total: 0 Has next: false
Example (FieldSelection) ¶
Example demonstrates field selection
package main
import (
"fmt"
"github.com/xraph/authsome/core/pagination"
)
func main() {
params := &pagination.PaginationParams{
BaseRequestParams: pagination.BaseRequestParams{
Fields: "id, name, email",
},
Limit: 10,
}
fields := params.GetFields()
fmt.Printf("Selected fields: %v\n", fields)
fmt.Printf("Has fields: %v\n", params.HasFields())
}
Output: Selected fields: [id name email] Has fields: true
Example (HandlerIntegration) ¶
Example_handlerIntegration demonstrates integration with a handler
package main
import (
"context"
"fmt"
"time"
"github.com/xraph/authsome/core/pagination"
)
// User represents a sample user model
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
func main() {
// This example shows typical handler usage
// 1. Bind query parameters
params := &pagination.PaginationParams{
BaseRequestParams: pagination.BaseRequestParams{
SortBy: "name",
Order: pagination.SortOrderAsc,
},
Limit: 20,
Page: 2,
}
// 2. Validate
if err := params.Validate(); err != nil {
fmt.Printf("Validation failed: %v\n", err)
return
}
// 3. Query database (simulated)
users, total := queryUsers(context.Background(), params)
// 4. Create response
response := pagination.NewPageResponse(users, total, params)
// 5. Return response
fmt.Printf("Showing page %d of %d\n", response.Pagination.CurrentPage, response.Pagination.TotalPages)
fmt.Printf("Items: %d-%d of %d\n",
response.Pagination.Offset+1,
response.Pagination.Offset+len(response.Data),
response.Pagination.Total,
)
}
// queryUsers simulates a database query
func queryUsers(ctx context.Context, params *pagination.PaginationParams) ([]User, int64) {
users := make([]User, 20)
for i := range users {
users[i] = User{
ID: fmt.Sprintf("user_%d", params.GetOffset()+i+1),
Name: fmt.Sprintf("User %d", params.GetOffset()+i+1),
Email: fmt.Sprintf("user%d@example.com", params.GetOffset()+i+1),
CreatedAt: time.Now(),
}
}
return users, 50
}
Output: Showing page 2 of 3 Items: 21-40 of 50
Example (OffsetPagination) ¶
Example demonstrates basic offset-based pagination
package main
import (
"fmt"
"time"
"github.com/xraph/authsome/core/pagination"
)
// User represents a sample user model
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
func main() {
// Simulate request parameters
params := &pagination.PaginationParams{
BaseRequestParams: pagination.BaseRequestParams{
SortBy: "created_at",
Order: pagination.SortOrderDesc,
},
Limit: 10,
Page: 1,
}
// Validate parameters
if err := params.Validate(); err != nil {
fmt.Printf("Validation error: %v\n", err)
return
}
// Simulate fetching users from database
users := []User{
{ID: "1", Name: "Alice", Email: "alice@example.com", CreatedAt: time.Now()},
{ID: "2", Name: "Bob", Email: "bob@example.com", CreatedAt: time.Now()},
}
total := int64(25)
// Create paginated response
response := pagination.NewPageResponse(users, total, params)
fmt.Printf("Current page: %d\n", response.Pagination.CurrentPage)
fmt.Printf("Total pages: %d\n", response.Pagination.TotalPages)
fmt.Printf("Has next: %v\n", response.Pagination.HasNext)
fmt.Printf("Total items: %d\n", response.Pagination.Total)
}
Output: Current page: 1 Total pages: 3 Has next: true Total items: 25
Example (ParameterValidation) ¶
Example demonstrates parameter validation with defaults
package main
import (
"fmt"
"github.com/xraph/authsome/core/pagination"
)
func main() {
// Parameters with defaults
params := &pagination.PaginationParams{}
if err := params.Validate(); err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Limit: %d\n", params.GetLimit())
fmt.Printf("Page: %d\n", params.GetPage())
fmt.Printf("Order: %s\n", params.GetOrder())
}
Output: Limit: 10 Page: 1 Order: desc
Example (SqlOrderClause) ¶
Example demonstrates SQL ORDER BY clause generation
package main
import (
"fmt"
"github.com/xraph/authsome/core/pagination"
)
func main() {
params := &pagination.PaginationParams{
BaseRequestParams: pagination.BaseRequestParams{
SortBy: "name",
Order: pagination.SortOrderAsc,
},
}
orderClause := params.GetOrderClause()
fmt.Printf("ORDER BY %s\n", orderClause)
}
Output: ORDER BY name ASC
Index ¶
- Constants
- func Apply(query *bun.SelectQuery, params *PaginationParams) *bun.SelectQuery
- func ApplyAll(query *bun.SelectQuery, params *PaginationParams, searchFields ...string) *bun.SelectQuery
- func ApplyBase(query *bun.SelectQuery, params *BaseRequestParams, searchFields ...string) *bun.SelectQuery
- func ApplyCursorPagination(query *bun.SelectQuery, params *CursorParams, ...) (*bun.SelectQuery, error)
- func ApplyWithFilters(query *bun.SelectQuery, params *PaginationParams) *bun.SelectQuery
- func ApplyWithSearch(query *bun.SelectQuery, params *PaginationParams, searchFields ...string) *bun.SelectQuery
- func EncodeCursor(id string, timestamp time.Time, value string) (string, error)
- func ParseFilters(filterStr string) map[string]string
- func ScanAndCount[T any](ctx context.Context, query *bun.SelectQuery, dest *[]T) (int64, error)
- func SimpleCursorDecode(cursor string) (string, error)
- func SimpleCursorEncode(value string) string
- type BaseRequestParams
- type CursorData
- type CursorMeta
- type CursorParams
- type PageMeta
- type PageResponse
- func NewCursorResponse[T any](data []T, nextCursor, prevCursor string, params *CursorParams) *PageResponse[T]
- func NewEmptyCursorResponse[T any]() *PageResponse[T]
- func NewEmptyPageResponse[T any]() *PageResponse[T]
- func NewPageResponse[T any](data []T, total int64, params *PaginationParams) *PageResponse[T]
- type Pagination
- type PaginationParams
- func (p *PaginationParams) GetLimit() int
- func (p *PaginationParams) GetOffset() int
- func (p *PaginationParams) GetOrder() SortOrder
- func (p *PaginationParams) GetOrderClause() string
- func (p *PaginationParams) GetPage() int
- func (p *PaginationParams) GetSortBy() string
- func (p *PaginationParams) Validate() error
- type QueryBuilder
- func (qb *QueryBuilder) ApplyCursor(query *bun.SelectQuery, cursorData *CursorData, ...) *bun.SelectQuery
- func (qb *QueryBuilder) ApplyFields(query *bun.SelectQuery) *bun.SelectQuery
- func (qb *QueryBuilder) ApplyFilters(query *bun.SelectQuery, filters map[string]string) *bun.SelectQuery
- func (qb *QueryBuilder) ApplyLimit(query *bun.SelectQuery) *bun.SelectQuery
- func (qb *QueryBuilder) ApplyOffset(query *bun.SelectQuery) *bun.SelectQuery
- func (qb *QueryBuilder) ApplyOrder(query *bun.SelectQuery) *bun.SelectQuery
- func (qb *QueryBuilder) ApplySearch(query *bun.SelectQuery, searchFields ...string) *bun.SelectQuery
- func (qb *QueryBuilder) ApplyToQuery(query *bun.SelectQuery) *bun.SelectQuery
- type SortOrder
Examples ¶
Constants ¶
const ( DefaultLimit = 10 MaxLimit = 10000 MinLimit = 1 )
Constants for pagination limits
Variables ¶
This section is empty.
Functions ¶
func Apply ¶
func Apply(query *bun.SelectQuery, params *PaginationParams) *bun.SelectQuery
Apply applies all standard parameters (limit, offset, order) to a query
func ApplyAll ¶
func ApplyAll(query *bun.SelectQuery, params *PaginationParams, searchFields ...string) *bun.SelectQuery
ApplyAll applies all parameters including search and filters
func ApplyBase ¶
func ApplyBase(query *bun.SelectQuery, params *BaseRequestParams, searchFields ...string) *bun.SelectQuery
ApplyBase applies sorting, searching, filtering, and field selection from BaseRequestParams This is useful for non-paginated requests that still need sorting/filtering
func ApplyCursorPagination ¶
func ApplyCursorPagination(query *bun.SelectQuery, params *CursorParams, cursorField, timestampField string) (*bun.SelectQuery, error)
ApplyCursorPagination applies cursor-based pagination to a query
func ApplyWithFilters ¶
func ApplyWithFilters(query *bun.SelectQuery, params *PaginationParams) *bun.SelectQuery
ApplyWithFilters applies standard parameters plus filters to a query
func ApplyWithSearch ¶
func ApplyWithSearch(query *bun.SelectQuery, params *PaginationParams, searchFields ...string) *bun.SelectQuery
ApplyWithSearch applies standard parameters plus search to a query
func EncodeCursor ¶
EncodeCursor encodes cursor data into a base64 string
func ParseFilters ¶
ParseFilters parses a filter string into a map Format: "key1:value1,key2:value2" Example: "status:active,role:admin"
func ScanAndCount ¶
ScanAndCount is a helper that executes a query and returns results with total count This is useful for offset-based pagination
func SimpleCursorDecode ¶
SimpleCursorDecode decodes a simple string cursor
func SimpleCursorEncode ¶
SimpleCursorEncode encodes a simple string cursor
Types ¶
type BaseRequestParams ¶
type BaseRequestParams struct {
SortBy string `json:"sortBy" query:"sortBy" default:"created_at" example:"created_at" optional:"true"`
Order SortOrder `json:"order" query:"order" default:"desc" validate:"oneof=asc desc" example:"desc" optional:"true"`
Search string `json:"search" query:"search" default:"" example:"john" optional:"true"`
Filter string `json:"filter" query:"filter" default:"" example:"status:active" optional:"true"`
Fields string `json:"fields" query:"fields" default:"" example:"id,name,email" optional:"true"`
}
BaseRequestParams contains common request parameters for sorting, searching, and filtering Can be used in both paginated and non-paginated requests
func (*BaseRequestParams) GetFields ¶
func (b *BaseRequestParams) GetFields() []string
GetFields returns the parsed list of fields to select Returns nil if no fields specified (select all)
func (*BaseRequestParams) GetOrder ¶
func (b *BaseRequestParams) GetOrder() SortOrder
GetOrder returns the sort order with fallback
func (*BaseRequestParams) GetOrderClause ¶
func (b *BaseRequestParams) GetOrderClause() string
GetOrderClause returns SQL ORDER BY clause
func (*BaseRequestParams) GetSortBy ¶
func (b *BaseRequestParams) GetSortBy() string
GetSortBy returns the sort field with fallback
func (*BaseRequestParams) HasFields ¶
func (b *BaseRequestParams) HasFields() bool
HasFields returns true if field selection is specified
func (*BaseRequestParams) Validate ¶
func (b *BaseRequestParams) Validate() error
Validate validates and normalizes base request parameters
type CursorData ¶
type CursorData struct {
ID string `json:"id"`
Timestamp time.Time `json:"ts"`
Value string `json:"val,omitempty"` // For sorting by fields other than timestamp
}
CursorData represents the data encoded in a cursor
func DecodeCursor ¶
func DecodeCursor(cursor string) (*CursorData, error)
DecodeCursor decodes a base64 cursor string back to CursorData
type CursorMeta ¶
type CursorMeta struct {
NextCursor string `json:"nextCursor,omitempty" example:"eyJpZCI6IjEyMyIsInRzIjoxNjQwMDAwMDAwfQ=="`
PrevCursor string `json:"prevCursor,omitempty" example:"eyJpZCI6IjEwMCIsInRzIjoxNjM5OTAwMDAwfQ=="`
HasNext bool `json:"hasNext" example:"true"`
HasPrev bool `json:"hasPrev" example:"false"`
Count int `json:"count" example:"10"`
}
CursorMeta contains cursor-based pagination metadata
type CursorParams ¶
type CursorParams struct {
BaseRequestParams
Limit int `json:"limit" query:"limit" default:"10" validate:"min=1,max=10000" example:"10" optional:"true"`
Cursor string `json:"cursor" query:"cursor" default:"" example:"eyJpZCI6IjEyMyIsInRzIjoxNjQwMDAwMDAwfQ==" optional:"true"`
}
CursorParams represents cursor-based pagination parameters
func (*CursorParams) GetLimit ¶
func (c *CursorParams) GetLimit() int
GetLimit returns the limit for cursor pagination
func (*CursorParams) GetOrder ¶
func (c *CursorParams) GetOrder() SortOrder
GetOrder returns the sort order with fallback
func (*CursorParams) GetOrderClause ¶
func (c *CursorParams) GetOrderClause() string
GetOrderClause returns SQL ORDER BY clause
func (*CursorParams) GetSortBy ¶
func (c *CursorParams) GetSortBy() string
GetSortBy returns the sort field with fallback
func (*CursorParams) Validate ¶
func (c *CursorParams) Validate() error
Validate validates cursor pagination parameters
type PageMeta ¶
type PageMeta struct {
Total int64 `json:"total" example:"1000"`
Limit int `json:"limit" example:"10"`
Offset int `json:"offset" example:"0"`
CurrentPage int `json:"currentPage" example:"1"`
TotalPages int `json:"totalPages" example:"100"`
HasNext bool `json:"hasNext" example:"true"`
HasPrev bool `json:"hasPrev" example:"false"`
}
PageMeta contains offset-based pagination metadata
type PageResponse ¶
type PageResponse[T any] struct { Data []T `json:"data"` Pagination *PageMeta `json:"pagination,omitempty"` Cursor *CursorMeta `json:"cursor,omitempty"` }
PageResponse represents a paginated response with metadata
func NewCursorResponse ¶
func NewCursorResponse[T any](data []T, nextCursor, prevCursor string, params *CursorParams) *PageResponse[T]
NewCursorResponse creates a new cursor-based paginated response
func NewEmptyCursorResponse ¶
func NewEmptyCursorResponse[T any]() *PageResponse[T]
NewEmptyCursorResponse creates an empty cursor-based response
func NewEmptyPageResponse ¶
func NewEmptyPageResponse[T any]() *PageResponse[T]
NewEmptyPageResponse creates an empty paginated response
func NewPageResponse ¶
func NewPageResponse[T any](data []T, total int64, params *PaginationParams) *PageResponse[T]
NewPageResponse creates a new paginated response
type Pagination ¶ added in v0.0.3
type Pagination struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
TotalItems int `json:"totalItems"`
TotalPages int `json:"totalPages"`
}
Pagination is a simple pagination response struct for use in services
func (*Pagination) HasNext ¶ added in v0.0.3
func (p *Pagination) HasNext() bool
HasNext returns true if there are more pages
func (*Pagination) HasPrev ¶ added in v0.0.3
func (p *Pagination) HasPrev() bool
HasPrev returns true if there are previous pages
func (*Pagination) ToPageMeta ¶ added in v0.0.3
func (p *Pagination) ToPageMeta() *PageMeta
ToPageMeta converts Pagination to PageMeta for compatibility
type PaginationParams ¶
type PaginationParams struct {
BaseRequestParams
Limit int `json:"limit" query:"limit" default:"10" validate:"min=1,max=10000" example:"10" optional:"true"`
Offset int `json:"offset" query:"offset" default:"0" validate:"min=0" example:"0" optional:"true"`
Page int `json:"page" query:"page" default:"1" validate:"min=1" example:"1" optional:"true"`
}
PaginationParams represents offset-based pagination request parameters
func (*PaginationParams) GetLimit ¶
func (p *PaginationParams) GetLimit() int
GetLimit returns the limit with fallback to default
func (*PaginationParams) GetOffset ¶
func (p *PaginationParams) GetOffset() int
GetOffset returns the calculated offset
Example ¶
ExamplePaginationParams_GetOffset demonstrates offset calculation
package main
import (
"fmt"
"github.com/xraph/authsome/core/pagination"
)
func main() {
// Using page number
params := &pagination.PaginationParams{
Limit: 10,
Page: 3,
}
offset := params.GetOffset()
fmt.Printf("Page 3 offset: %d\n", offset)
}
Output: Page 3 offset: 20
func (*PaginationParams) GetOrder ¶
func (p *PaginationParams) GetOrder() SortOrder
GetOrder returns the sort order with fallback
func (*PaginationParams) GetOrderClause ¶
func (p *PaginationParams) GetOrderClause() string
GetOrderClause returns SQL ORDER BY clause
func (*PaginationParams) GetPage ¶
func (p *PaginationParams) GetPage() int
GetPage returns the current page number
Example ¶
ExamplePaginationParams_GetPage demonstrates page calculation
package main
import (
"fmt"
"github.com/xraph/authsome/core/pagination"
)
func main() {
// Using offset
params := &pagination.PaginationParams{
Limit: 10,
Offset: 50,
}
page := params.GetPage()
fmt.Printf("Offset 50 page: %d\n", page)
}
Output: Offset 50 page: 6
func (*PaginationParams) GetSortBy ¶
func (p *PaginationParams) GetSortBy() string
GetSortBy returns the sort field with fallback
func (*PaginationParams) Validate ¶
func (p *PaginationParams) Validate() error
Validate validates and normalizes pagination parameters
type QueryBuilder ¶
type QueryBuilder struct {
// contains filtered or unexported fields
}
QueryBuilder provides methods to apply pagination parameters to Bun queries
func NewQueryBuilder ¶
func NewQueryBuilder(params interface{}) *QueryBuilder
NewQueryBuilder creates a new QueryBuilder from pagination parameters
func (*QueryBuilder) ApplyCursor ¶
func (qb *QueryBuilder) ApplyCursor(query *bun.SelectQuery, cursorData *CursorData, cursorField, timestampField string) *bun.SelectQuery
ApplyCursor applies cursor-based pagination to a Bun query cursorData should be obtained from DecodeCursor() cursorField is the field to use for cursor comparison (default: "id") timestampField is the timestamp field (default: "created_at")
func (*QueryBuilder) ApplyFields ¶
func (qb *QueryBuilder) ApplyFields(query *bun.SelectQuery) *bun.SelectQuery
ApplyFields applies field selection to a Bun query Only selects specified fields if Fields parameter is set
func (*QueryBuilder) ApplyFilters ¶
func (qb *QueryBuilder) ApplyFilters(query *bun.SelectQuery, filters map[string]string) *bun.SelectQuery
ApplyFilters applies parsed filters to a Bun query filters should be from ParseFilters() It applies exact match filters as WHERE conditions
func (*QueryBuilder) ApplyLimit ¶
func (qb *QueryBuilder) ApplyLimit(query *bun.SelectQuery) *bun.SelectQuery
ApplyLimit applies the limit parameter to a Bun query Note: BaseRequestParams does not have a Limit field (not all requests need pagination)
func (*QueryBuilder) ApplyOffset ¶
func (qb *QueryBuilder) ApplyOffset(query *bun.SelectQuery) *bun.SelectQuery
ApplyOffset applies the offset parameter to a Bun query Only works with PaginationParams (not cursor-based)
func (*QueryBuilder) ApplyOrder ¶
func (qb *QueryBuilder) ApplyOrder(query *bun.SelectQuery) *bun.SelectQuery
ApplyOrder applies the order parameter to a Bun query
func (*QueryBuilder) ApplySearch ¶
func (qb *QueryBuilder) ApplySearch(query *bun.SelectQuery, searchFields ...string) *bun.SelectQuery
ApplySearch applies a search filter to a Bun query searchFields should be the column names to search in Example: ApplySearch(query, "name", "email", "username") Note: Uses LOWER() for case-insensitive search (works with all databases)
func (*QueryBuilder) ApplyToQuery ¶
func (qb *QueryBuilder) ApplyToQuery(query *bun.SelectQuery) *bun.SelectQuery
ApplyToQuery applies all pagination parameters to a Bun query This is a convenience method that calls ApplyLimit, ApplyOffset, ApplyOrder, and ApplyFields