Skip to content
This repository was archived by the owner on Nov 6, 2021. It is now read-only.

Pagination

B1nj0y edited this page Sep 27, 2017 · 38 revisions

A keyset style pagination

100% offset-free

What's a keyset pagination: http://use-the-index-luke.com/no-offset.

Basic Usage

Take a model named Post as an example. A data type PostPage will be generated for paginating:

type PostPage struct {
    WhereString string
    WhereParams []interface{}
    Order       map[string]string
    FirstId     int64
    LastId      int64
    PageNum     int
    PerPage     int
    TotalPages  int
    TotalItems  int64
}

And meanwhile generated three methods Current, Next and Previous:

// Current get the current page of PostPage object for pagination
func (_p *PostPage) Current() ([]Post, error)

// Current get the next page of PostPage object for pagination
func (_p *PostPage) Next() ([]Post, error)

// Current get the previous page of PostPage object for pagination 
func (_p *PostPage) Previous() ([]Post, error)

You can init a PostPage at first:

pp := &PostPage{Order: map[string]string{"id": "desc"}, PerPage: 5}

Then get the first page:

ps, err := pp.Current()

Then next page:

ps, err = pp.Next()

Or back to previous page:

ps, err = pp.Previous()

Show the current page number:

fmt.Println(pp.PageNum)

Show total pages and total count:

fmt.Println(pp.TotalPages)
fmt.Println(pp.TotalItems)

Add a where clause

You can add a where clause with parameters as a filter when init a PostPage object:

pp := &PostPage{
WhereString: "title LIKE ? AND hits > ?", 
WhereParams: []interface{}{"%go-on-rails%", 200}, 
Order: map[string]string{"id": "desc"}, 
PerPage: 5}

Here the WhereString is a ? binding with WhereParams correspondingly.

A sample code in a Controller

All above is making a pagination object in the Model level, now we show how to make it work from the View to the Controller(a handler), and then call the methods of the object.

For example we GET an index page and pass three parameters:

  • pagination: previous / current / next, optional, it will be current if omited
  • first_id: the first ID in the page, optional, it will be 0 if omited
  • last_id: the last ID in the page, optional, it will be 0 if omited

In our Controller, we will do some check and then get the right page:

// for example, we use the Gin framework, and this's in a function named IndexHander
function IndexHandler(c *gin.Context) {
    pagination := c.Param("pagination")
    firstId := strconv.Atoi(c.Param("first_id"))
    lastId := strconv.Atoi(c.Param("last_id"))
    
    pp := &PostPage{
        WhereString: "title LIKE ? AND hits > ?", 
        WhereParams: []interface{}{"%go-on-rails%", 200}, 
        Order: map[string]string{"id": "desc"}, 
        PerPage: 5,
        FirstId: firstId,
        LastId: lastId}

    ps := []Post
    switch pagination {
        case "previous":
            ps, _ = pp.Previous()
        case "next":
            ps, _ = pp.Next()
        default:
            ps, _ = pp.Current()
    }

    c.JSON(200, gin.H{
			"status":  "success"
			"data": ps
		})
}

How to composite a url from the View?

In the View, take the GET action for example, the url will be:

/posts?pagination=(previous|current|next)&first_id=A_NUM&last_id=A_NUM
Clone this wiki locally