pagination

package module
v1.3.1 Latest Latest
Warning

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

Go to latest
Published: Feb 21, 2022 License: MIT Imports: 6 Imported by: 0

README

Pagination library

Package go-pagination was designed to paginate simple RESTful APIs with GORM and Gin. It uses cursor-based strategy, that avoids many of the pitfalls of "offset–limit" pagination.

Usage

Model
package models

import "github.com/rosberry/go-pagination"


type User struct {
	ID   uint
	Name string
	Role uint `json:"roleID" cursor:"roleID"`
}

func GetUsersList(role uint, paginator *pagination.Paginator) []User {
	var users []User
	q := db.DB.Model(&User{}).Where("role = ?", role)

	err := paginator.Find(q, &users)
	if err != nil {
		log.Println(err)
		return nil
	}

	return users
}
Controllers
package controllers

import "github.com/rosberry/go-pagination"

type (
	usersListResponse struct {
		Result     bool
		Users      []userData
		Pagination *pagination.PageInfo
	}
)


func UsersList(c *gin.Context) {
	paginator, err := pagination.New(pagination.Options{
		GinContext: c,
		DB: models.GetDB(),
		Model: &models.User{},
		Limit: 5,
		DefaultCursor: nil,
	})
	if err != nil {
		log.Println(err)
	}

	users := models.GetUsersList(0, paginator)

	c.JSON(200, usersListResponse{
		Result:     true,
		Users:      usersListToData(users),
		Pagination: paginator.PageInfo,
	})
}
Customize request

If you want to get values in a special way, you can customize the functions to find the values you need. You must implement functions RequestGetter type

type RequestGetter  func(c *gin.Context) (query string)

for example

func cursorGetter(c *gin.Context) (query string) {
	cursorQuery := c.Request.Header.Get("customCursorFromHeader")
	return cursorQuery
}

func sortingGetter(c *gin.Context) (query string) {
	sortingQuery := c.Query("sort")
	return sortingQuery
}

and pass the functions as Options.CustomRequest (type RequestOptions) in pagination.New() function.

paginator, err := New(Options{
		GinContext: c,
		Limit:      uint(limit),
		DB:         db,
		Model:      &Material{},
		CustomRequest: &RequestOptions{
			Cursor: func(c *gin.Context) (query string) {
				cursorQuery := c.Request.Header.Get("customCursorFromHeader")
				return cursorQuery
			},
			Sorting: func(c *gin.Context) (query string) {
				sortingQuery := c.Query("sort")
				return sortingQuery
			},
		},
	})
  • query for cursor/after/before - base64 string
  • query for sorting - json string

Client-Server interaction

Request:

GET /items
GET /items?sorting=%5B%7B%22field%22:%22id%22,%22direction%22:%22desc%22%7D%5D

Sorting query parameters is JSON:

[
    {
        "field": "Name",
        "direction": "asc"
    },
    {
        "field": "UpdatedAt",
        "direction": "desc"
    }
]

field name in query parameters should have name from response. If name in response is different from name in model - you need add tag cursor:"fieldName" in model

Response:

{
    "result": true,
    "data": {
    },
    "pagination": {
		"hasPrev": false,
		"hasNext": true,
		"prev": "ew2YWxU0Cn01ZSI6ogICJID=",
		"next": "ewogICJ2YWx1ZSI6IDU0Cn0=",
		"totalRows": 10,
		"rangeTruncated": true
    }
}

Request next page:

GET /items?cursor=ew2YWxU0Cn01ZSI6ogICJID

Response (end):

{
    "result": true,
    "data": null,
    "pagination:" null
}
Before / After

You can use after/before params instead of cursor in request

GET /items?after=e2sdw2wO0WDwwW&before=sdqqwDsdDq2Pd1

The after parameter is typically sent by the client to get the next page, while before is used to get the prior page.

Clients MAY use the after and before parameters together on the same request. These are called “range pagination requests”, as the client is asking for all the results starting from immediately after the after cursor and continuing up until the before cursor.

For range pagination requests, the server uses a limit to determine the maximum page size. In other words, the page size used will depend on the value of the limit parameter or the maximum page size.

If the number of results that satisfy both the after and before constraints exceeds the used page size, the server responds with the same paginated data that it would have if the before parameter had not been provided. However, in this case the server MUST also add "rangeTruncated": true to the pagination metadata to indicate to the client that the paginated data does not contain all the results it requested.

Field naming

About

This project is owned and maintained by Rosberry. We build mobile apps for users worldwide 🌏.

Check out our open source projects, read our blog or give us a high-five on 🐦 @rosberryapps.

License

This project is available under the MIT license. See the LICENSE file for more info.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Options

type Options struct {
	GinContext    *gin.Context
	DefaultCursor *cursor.Cursor
	Model         interface{}
	Limit         uint
	DB            *gorm.DB
	CustomRequest *RequestOptions
}

type PageInfo

type PageInfo struct {
	Next           string `json:"next"`
	Prev           string `json:"prev"`
	HasNext        bool   `json:"hasNext"`
	HasPrev        bool   `json:"hasPrev"`
	TotalRows      int    `json:"totalRows"`
	RangeTruncated bool   `json:"rangeTruncated"`
}

type Paginator

type Paginator struct {
	PageInfo *PageInfo
	// contains filtered or unexported fields
}

func New

func New(o Options) (*Paginator, error)

func (*Paginator) Find

func (p *Paginator) Find(tx *gorm.DB, dst interface{}) error

func (*Paginator) SetDB added in v1.3.0

func (p *Paginator) SetDB(db *gorm.DB)

func (*Paginator) SetModel added in v1.3.0

func (p *Paginator) SetModel(model interface{})

type RequestGetter added in v1.2.0

type RequestGetter func(c *gin.Context) (query string)

type RequestOptions added in v1.2.0

type RequestOptions struct {
	Cursor  RequestGetter
	After   RequestGetter
	Before  RequestGetter
	Sorting RequestGetter
}

Directories

Path Synopsis
_examples

Jump to

Keyboard shortcuts

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