Skip to content

Commit

Permalink
Merge pull request #13 from morkid/v1.1.7-dev
Browse files Browse the repository at this point in the history
V1.1.7 dev
  • Loading branch information
morkid authored Sep 27, 2023
2 parents c3fb08d + 61bc696 commit 6a80ba9
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 52 deletions.
57 changes: 55 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# paginate - Gorm Pagination

[![Go Reference](https://pkg.go.dev/badge/github.com/morkid/paginate.svg)](https://pkg.go.dev/github.com/morkid/paginate)
[![CircleCI](https://circleci.com/gh/morkid/paginate.svg?style=svg)](https://circleci.com/gh/morkid/paginate)
[![Github Actions](https://github.com/morkid/paginate/workflows/Go/badge.svg)](https://github.com/morkid/paginate/actions)
[![Build Status](https://travis-ci.com/morkid/paginate.svg?branch=master)](https://travis-ci.com/morkid/paginate)
[![Go Report Card](https://goreportcard.com/badge/github.com/morkid/paginate)](https://goreportcard.com/report/github.com/morkid/paginate)
[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/morkid/paginate)](https://github.com/morkid/paginate/releases)

Expand All @@ -12,6 +10,7 @@ Simple way to paginate [Gorm](https://github.com/go-gorm/gorm) result. **paginat
## Table Of Contents
- [Installation](#installation)
- [Configuration](#configuration)
- [Pagination Result](#pagination-result)
- [Paginate using http request](#paginate-using-http-request)
- [Example usage](#example-usage)
- [net/http](#nethttp-example)
Expand Down Expand Up @@ -77,6 +76,59 @@ see more about [customize default configuration](#customize-default-configuratio
> Old: `pg.Response(model, req, &[]Article{})`,
> New: `pg.With(model).Request(req).Response(&[]Article{})`
## Pagination Result

```js
{
// the result items
"items": *[]any,

// total results
// including next pages
"total": number,

// Current page
// (provided by request parameter, eg: ?page=1)
// note: page is always start from 0
"page": number,

// Current size
// (provided by request parameter, eg: ?size=10)
// note: negative value means unlimited
"size": number,

// Total Pages
"total_pages": number,

// Max Page
// start from 0 until last index
// example:
// if you have 3 pages (page0, page1, page2)
// max_page is 2 not 3
"max_page": number,

// Last Page is true if the page
// has reached the end of the page
"last": bool,

// Fist Page is true if the page is 0
"fist": bool,

// Visible
// total visible items
"visible": number,

// Error
// true if an error has occurred and
// paginage.Config.ErrorEnabled is true
"error": bool,

// Error Message
// current error if available and
// paginage.Config.ErrorEnabled is true
"error_message": string,
}
```
## Paginate using http request
example paging, sorting and filtering:
1. `http://localhost:3000/?size=10&page=0&sort=-name`
Expand Down Expand Up @@ -550,6 +602,7 @@ OrderParams | `[]string` | `[]string{"order"}` | if `CustomParamEnabl
FilterParams | `[]string` | `[]string{"filters"}` | if `CustomParamEnabled` is `true`,<br>you can set the `FilterParams` with custom parameter names.<br>For example:<br>`[]string{"search", "find", "other_alternative_param"}`.<br>The following requests will capture same result<br>`?search=["name","john"]`<br>or `?find=["name","john"]`<br>or `?other_alternative_param=["name","john"]`<br>or `?filters=["name","john"]`
FieldsParams | `[]string` | `[]string{"fields"}` | if `FieldSelectorEnabled` and `CustomParamEnabled` is `true`,<br>you can set the `FieldsParams` with custom parameter names.<br>For example:<br>`[]string{"fields", "columns", "other_alternative_param"}`.<br>The following requests will capture same result `?fields=title,user.name`<br>or `?columns=title,user.name`<br>or `?other_alternative_param=title,user.name`
CacheAdapter | `*gocache.AdapterInterface` | `nil` | the cache adapter, see more about [cache config](#speed-up-response-with-cache).
ErrorEnabled | `bool` | `false` | Show error message in pagination result.

## Override results

Expand Down
14 changes: 0 additions & 14 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/iancoleman/strcase v0.1.3 h1:dJBk1m2/qjL1twPLf68JND55vvivMupZ4wIzE8CTdBw=
github.com/iancoleman/strcase v0.1.3/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg=
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.12 h1:famVnQVu7QwryBN4jNseQdUKES71ZAOnB6UQQJPZvqk=
github.com/klauspost/compress v1.11.12/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
Expand All @@ -21,21 +15,15 @@ github.com/morkid/gocache v1.0.0 h1:hTnU78Dqp2vs9al5vJC2TmmMF+Hm3nDH1AgRBjSXE+0=
github.com/morkid/gocache v1.0.0/go.mod h1:xK+hmoEMjYffIBvjn7DE8WfSd/rF5Kz/G9f20OliMJY=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.18.0 h1:IV0DdMlatq9QO1Cr6wGJPVW1sV1Q8HvZXAIcjorylyM=
github.com/valyala/fasthttp v1.18.0/go.mod h1:jjraHZVbKOXftJfsOYoAjaeygpj5hr8ermTRJNroD7A=
github.com/valyala/fasthttp v1.22.0 h1:OpwH5KDOJ9cS2bq8fD+KfT4IrksK0llvkHf4MZx42jQ=
github.com/valyala/fasthttp v1.22.0/go.mod h1:0mw2RjXGOzxf4NL2jni3gUQ7LfjjUSiG5sskOUUSEpU=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226101413-39120d07d75e/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
Expand All @@ -47,7 +35,5 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM=
gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw=
gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.8 h1:iToaOdZgjNvlc44NFkxfLa3U9q63qwaxt0FdNCiwOMs=
gorm.io/gorm v1.20.8/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.3 h1:qDFi55ZOsjZTwk5eN+uhAmHi8GysJ/qCTichM/yO7ME=
gorm.io/gorm v1.21.3/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
53 changes: 30 additions & 23 deletions paginate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"crypto/md5"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"log"
"math"
"net/http"
Expand Down Expand Up @@ -41,6 +41,7 @@ type Pagination struct {
//
// Deprecated: Response must not be used. Use With instead
func (p *Pagination) Response(stmt *gorm.DB, req interface{}, res interface{}) Page {
fmt.Println("paginate.Response(stmt, req, res) is deprecated! please use paginate.With(stmt).Request(req).Response(res) instead")
return p.With(stmt).Request(req).Response(res)
}

Expand Down Expand Up @@ -198,9 +199,11 @@ func (r resContext) Response(res interface{}) Page {
Limit(causes.Limit).
Offset(causes.Offset)

if result.Error != nil {
page.Error = result.Error
return page
page.RawError = result.Error

if result.Error != nil && p.Config.ErrorEnabled {
page.Error = true
page.ErrorMessage = result.Error.Error()
}

if nil != query.Statement.Preloads {
Expand All @@ -215,9 +218,13 @@ func (r resContext) Response(res interface{}) Page {
}

rs := result.Find(res)
if rs.Error != nil {
page.Error = rs.Error
return page
if nil == page.RawError {
page.RawError = rs.Error
}

if rs.Error != nil && p.Config.ErrorEnabled && !page.Error {
page.Error = true
page.ErrorMessage = rs.Error.Error()
}

page.Items = res
Expand All @@ -236,9 +243,7 @@ func (r resContext) Response(res interface{}) Page {
if page.TotalPages < 1 {
page.TotalPages = 1
}
if page.MaxPage < 1 {
page.MaxPage = 1
}

if page.Total < 1 {
page.MaxPage = 0
page.TotalPages = 0
Expand Down Expand Up @@ -342,7 +347,7 @@ func parsingNetHTTPRequest(r *http.Request, p *pageRequest) {
r.Method = "GET"
}
if strings.ToUpper(r.Method) == "POST" {
body, err := ioutil.ReadAll(r.Body)
body, err := io.ReadAll(r.Body)
if nil != err {
body = []byte("{}")
}
Expand Down Expand Up @@ -509,7 +514,6 @@ func generateParams(param *parameter, config Config, getValue func(string) strin
param.Fields = findValue(config.FieldsParams, "fields")
}

//gocyclo:ignore
func arrayToFilter(arr []interface{}, config Config) pageFilters {
filters := pageFilters{
Single: false,
Expand Down Expand Up @@ -592,7 +596,7 @@ func arrayToFilter(arr []interface{}, config Config) pageFilters {
separatedSubFilters := []pageFilters{}
hasOperator := false
defaultOperator := config.Operator
if "" == defaultOperator {
if defaultOperator == "" {
defaultOperator = "OR"
}
for k, s := range subFilters {
Expand Down Expand Up @@ -790,6 +794,7 @@ type Config struct {
CacheAdapter *gocache.AdapterInterface `json:"-"`
JSONMarshal func(v interface{}) ([]byte, error) `json:"-"`
JSONUnmarshal func(data []byte, v interface{}) error `json:"-"`
ErrorEnabled bool
}

// pageFilters struct
Expand All @@ -806,16 +811,18 @@ type pageFilters struct {

// Page result wrapper
type Page struct {
Items interface{} `json:"items"`
Page int64 `json:"page"`
Size int64 `json:"size"`
MaxPage int64 `json:"max_page"`
TotalPages int64 `json:"total_pages"`
Total int64 `json:"total"`
Last bool `json:"last"`
First bool `json:"first"`
Visible int64 `json:"visible"`
Error error `json:"error"`
Items interface{} `json:"items"`
Page int64 `json:"page"`
Size int64 `json:"size"`
MaxPage int64 `json:"max_page"`
TotalPages int64 `json:"total_pages"`
Total int64 `json:"total"`
Last bool `json:"last"`
First bool `json:"first"`
Visible int64 `json:"visible"`
Error bool `json:"error,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
RawError error `json:"-"`
}

// parameter struct
Expand Down
38 changes: 25 additions & 13 deletions paginate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"testing"
Expand Down Expand Up @@ -151,7 +151,7 @@ func TestPostNetHttp(t *testing.T) {
queryFilter := fmt.Sprintf(`[["user.average_point","like","%s"]]`, avg)
query := fmt.Sprintf(data, page, size, sort, queryFilter)

body := ioutil.NopCloser(bytes.NewReader([]byte(query)))
body := io.NopCloser(bytes.NewReader([]byte(query)))

req := &http.Request{
Method: "POST",
Expand Down Expand Up @@ -284,7 +284,7 @@ func TestPaginate(t *testing.T) {
dsn := "file::memory:?cache=shared"

db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
Logger: logger.Discard,
})
db.AutoMigrate(&User{}, &Article{})

Expand All @@ -299,11 +299,6 @@ func TestPaginate(t *testing.T) {
}

tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()

if err := tx.Create(&users).Error; nil != err {
tx.Rollback()
Expand Down Expand Up @@ -337,11 +332,28 @@ func TestPaginate(t *testing.T) {
response := []Article{}

model := db.Joins("User").Model(&Article{})
result := New().Response(model, request, &response)
result := New().With(model).Request(request).Response(&response)

_, err = json.MarshalIndent(result, "", " ")
if nil != err {
t.Error(err)
}

queryFilter = fmt.Sprintf(`[["users.average_point","like","%s"],["AND"],["user.name","IS NOT",null],["id","like","1"]]`, avg)
query = fmt.Sprintf(data, page, size, sort, url.QueryEscape(queryFilter))

request = &http.Request{
Method: "GET",
URL: &url.URL{
RawQuery: query,
},
}
response = []Article{}

str, err := json.MarshalIndent(result, "", " ")
if nil == err {
t.Log(string(str))
model = db.Joins("User").Model(&Article{})
result = New(&Config{ErrorEnabled: true}).With(model).Request(request).Response(&response)
if !result.Error {
t.Error("Failed to get error message")
}
}

Expand Down Expand Up @@ -420,7 +432,7 @@ func TestCache(t *testing.T) {
}
dsn := "file::memory:"
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
Logger: logger.Discard,
})
if nil != err {
t.Error(err.Error())
Expand Down

0 comments on commit 6a80ba9

Please sign in to comment.