@@ -11,7 +11,7 @@ import (
1111 "github.com/neuronlabs/neuron-core/log"
1212)
1313
14- // Pagination constants
14+ // Pagination defined constants used for formatting the query.
1515const (
1616 // ParamPage is a JSON API query parameter used as for pagination.
1717 ParamPage = "page"
@@ -39,6 +39,24 @@ const (
3939 PageNumberPagination
4040)
4141
42+ // NewPaginationLimitOffset creates new Limit Offset pagination for given 'limit' and 'offset'.
43+ func NewPaginationLimitOffset (limit , offset int64 ) (* Pagination , error ) {
44+ pagination := & Pagination {Type : LimitOffsetPagination , Size : limit , Offset : offset }
45+ if err := pagination .IsValid (); err != nil {
46+ return nil , err
47+ }
48+ return pagination , nil
49+ }
50+
51+ // NewPaginationNumberSize sets the pagination of the type PageNumberSize with the page 'number' and page 'size'.
52+ func NewPaginationNumberSize (number , size int64 ) (* Pagination , error ) {
53+ pagination := & Pagination {Size : size , Offset : number , Type : PageNumberPagination }
54+ if err := pagination .IsValid (); err != nil {
55+ return nil , err
56+ }
57+ return pagination , nil
58+ }
59+
4260// Pagination defines the query limits and offsets.
4361// It defines the maximum size (Limit) as well as an offset at which
4462// the query should start.
@@ -79,7 +97,7 @@ func (p *Pagination) First() (*Pagination, error) {
7997 return first , nil
8098}
8199
82- // FormatQuery formats the pagination for the url query.
100+ // FormatQuery formats the pagination for the url query with respect to JSONAPI specification .
83101func (p * Pagination ) FormatQuery (q ... url.Values ) url.Values {
84102 var query url.Values
85103 if len (q ) != 0 {
@@ -178,7 +196,7 @@ func (p *Pagination) IsValid() error {
178196 return p .checkValues ()
179197}
180198
181- // IsZero checks if the pagination is already set .
199+ // IsZero checks if the pagination is zero valued .
182200func (p * Pagination ) IsZero () bool {
183201 return p .Size == 0 && p .Offset == 0
184202}
@@ -199,14 +217,25 @@ func (p *Pagination) Last(total int64) (*Pagination, error) {
199217 var last * Pagination
200218 switch p .Type {
201219 case LimitOffsetPagination :
202- offset := total - p .Size
203- // in case when total size is lower then the pagination size set the offset to 0
204- if offset < 0 {
205- offset = 0
220+ var offset int64
221+
222+ // check if the last page is not partial
223+ if partialSize := p .Offset % p .Size ; partialSize != 0 {
224+ lastFull := (total - partialSize ) / p .Size
225+ offset = lastFull * p .Size + partialSize
226+ } else {
227+ // the last should be total/p.Size - (10-3)/2 = 3
228+ // 3 * size = 3 * 2 = 6
229+ offset = total - p .Size
230+ // in case when total size is lower then the pagination size set the offset to 0
231+ if offset < 0 {
232+ offset = 0
233+ }
206234 }
207235 if offset == p .Offset {
208236 return p , nil
209237 }
238+ // the offset should be total / p.Size
210239 last = & Pagination {Size : p .Size , Offset : offset , Type : LimitOffsetPagination }
211240 case PageNumberPagination :
212241 // divide total number of instances by the page size.
@@ -215,9 +244,9 @@ func (p *Pagination) Last(total int64) (*Pagination, error) {
215244 // pageSize - 10
216245 // computedPageNumber = 52/10 = 5
217246 pageNumber := total / p .Size
218- if pageNumber == 0 {
219- // in case when 'total' < pageSize the pageNumber = 1
220- pageNumber = 1
247+ if total % p . Size != 0 || pageNumber == 0 {
248+ // total % p.Size = 52 % 10 = 2
249+ pageNumber ++
221250 }
222251 last = & Pagination {Size : p .Size , Offset : pageNumber , Type : PageNumberPagination }
223252 default :
@@ -246,7 +275,7 @@ func (p *Pagination) Next(total int64) (*Pagination, error) {
246275 // in example:
247276 // total 52; p.Offset = 50; p.Size = 10
248277 // the next offset would be 60 which overflows possible total values.
249- if offset > total {
278+ if offset >= total {
250279 return p , nil
251280 }
252281 next = & Pagination {Offset : offset , Size : p .Size , Type : LimitOffsetPagination }
@@ -256,10 +285,13 @@ func (p *Pagination) Next(total int64) (*Pagination, error) {
256285 // in example:
257286 // total: 52; pageNumber: 6; pageSize: 10;
258287 // nextTotal = pageNumber * pageSize = 60
259- if p .Size * (p .Offset ) > total {
288+ // 50 - (10 * 4+1) <= 0 ?
289+ //
290+ nextPageNumber := p .Offset + 1
291+ if total - (p .Size * (nextPageNumber )) <= 0 {
260292 return p , nil
261293 }
262- next = & Pagination {Offset : p . Offset + 1 , Size : p .Size , Type : PageNumberPagination }
294+ next = & Pagination {Offset : nextPageNumber , Size : p .Size , Type : PageNumberPagination }
263295 default :
264296 return nil , errors .NewDet (class .QueryPaginationType , "invalid pagination type" )
265297 }
@@ -280,12 +312,12 @@ func (p *Pagination) Previous() (*Pagination, error) {
280312 if p .Offset == 0 {
281313 return p , nil
282314 }
283- offset := p .Offset - p .Size
284- if offset < 0 {
285- return p , nil
315+ if p .Offset < p .Size {
316+ prev = & Pagination { Offset : 0 , Size : p . Offset , Type : LimitOffsetPagination }
317+ return prev , nil
286318 }
287319 // keep the same size but change the offset
288- prev = & Pagination {Offset : offset , Size : p .Size , Type : LimitOffsetPagination }
320+ prev = & Pagination {Offset : p . Offset - p . Size , Size : p .Size , Type : LimitOffsetPagination }
289321 case PageNumberPagination :
290322 if p .Offset <= 1 {
291323 return p , nil
0 commit comments