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

Commit e9ffde0

Browse files
authored
Merge pull request #30 from neuronlabs/develop
Minor pagination issues fixed.
2 parents 3abe30b + a1722f4 commit e9ffde0

File tree

8 files changed

+153
-13
lines changed

8 files changed

+153
-13
lines changed

config/processor.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,23 @@ func DefaultProcessorConfig() map[string]interface{} {
7171
internal.ProcessTxCommitOrRollback,
7272
},
7373
"get_processes": []string{
74+
internal.ProcessCheckPagination,
7475
internal.ProcessFillEmptyFieldset,
7576
internal.ProcessConvertRelationFiltersSafe,
7677
internal.ProcessHookBeforeGet,
78+
internal.ProcessCheckPagination,
7779
internal.ProcessConvertRelationFiltersSafe,
7880
internal.ProcessGet,
7981
internal.ProcessGetForeignRelations,
8082
internal.ProcessHookAfterGet,
8183
internal.ProcessGetIncludedSafe,
8284
},
8385
"list_processes": []string{
86+
internal.ProcessCheckPagination,
8487
internal.ProcessFillEmptyFieldset,
8588
internal.ProcessConvertRelationFiltersSafe,
8689
internal.ProcessHookBeforeList,
90+
internal.ProcessCheckPagination,
8791
internal.ProcessConvertRelationFiltersSafe,
8892
internal.ProcessList,
8993
internal.ProcessGetForeignRelationsSafe,
@@ -139,9 +143,11 @@ func ThreadSafeProcessor() *Processor {
139143
internal.ProcessGetIncludedSafe,
140144
},
141145
ListProcesses: ProcessList{
146+
internal.ProcessCheckPagination,
142147
internal.ProcessFillEmptyFieldset,
143148
internal.ProcessConvertRelationFiltersSafe,
144149
internal.ProcessHookBeforeList,
150+
internal.ProcessCheckPagination,
145151
internal.ProcessConvertRelationFiltersSafe,
146152
internal.ProcessList,
147153
internal.ProcessGetForeignRelationsSafe,
@@ -187,18 +193,22 @@ func ConcurrentProcessor() *Processor {
187193
internal.ProcessTxCommitOrRollback,
188194
},
189195
GetProcesses: ProcessList{
196+
internal.ProcessCheckPagination,
190197
internal.ProcessFillEmptyFieldset,
191198
internal.ProcessConvertRelationFilters,
192199
internal.ProcessHookBeforeGet,
200+
internal.ProcessCheckPagination,
193201
internal.ProcessConvertRelationFilters,
194202
internal.ProcessGet,
195203
internal.ProcessGetForeignRelations,
196204
internal.ProcessHookAfterGet,
197205
},
198206
ListProcesses: ProcessList{
207+
internal.ProcessCheckPagination,
199208
internal.ProcessFillEmptyFieldset,
200209
internal.ProcessConvertRelationFilters,
201210
internal.ProcessHookBeforeList,
211+
internal.ProcessCheckPagination,
202212
internal.ProcessConvertRelationFilters,
203213
internal.ProcessList,
204214
internal.ProcessGetForeignRelations,
@@ -244,17 +254,21 @@ func DefaultConcurrentProcessorConfig() map[string]interface{} {
244254
internal.ProcessTxCommitOrRollback,
245255
},
246256
"get_processes": []string{
257+
internal.ProcessCheckPagination,
247258
internal.ProcessFillEmptyFieldset,
248259
internal.ProcessConvertRelationFilters,
249260
internal.ProcessHookBeforeGet,
261+
internal.ProcessCheckPagination,
250262
internal.ProcessConvertRelationFilters,
251263
internal.ProcessGet,
252264
internal.ProcessGetForeignRelations,
253265
},
254266
"list_processes": []string{
267+
internal.ProcessCheckPagination,
255268
internal.ProcessFillEmptyFieldset,
256269
internal.ProcessConvertRelationFilters,
257270
internal.ProcessHookBeforeList,
271+
internal.ProcessCheckPagination,
258272
internal.ProcessConvertRelationFilters,
259273
internal.ProcessList,
260274
internal.ProcessGetForeignRelations,

internal/processes.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var Processes = make(map[string]struct{})
55

66
// Processes constant names.
77
const (
8+
// Create processes
89
ProcessHookBeforeCreate = "hook_before_create"
910
ProcessSetBelongsToRelations = "set_belongs_to_relations"
1011
ProcessCreate = "create"
@@ -13,6 +14,7 @@ const (
1314
ProcessPatchForeignRelationsSafe = "patch_foreign_relationships_safe"
1415
ProcessHookAfterCreate = "hook_after_create"
1516

17+
// Get processes
1618
ProcessFillEmptyFieldset = "fill_empty_fieldset"
1719
ProcessConvertRelationFilters = "convert_relation_filters"
1820
ProcessConvertRelationFiltersSafe = "convert_relation_filters_safe"
@@ -22,24 +24,29 @@ const (
2224
ProcessGetForeignRelationsSafe = "get_foreign_relations_safe"
2325
ProcessHookAfterGet = "hook_after_get"
2426

27+
// List processes
28+
ProcessCheckPagination = "check_pagination"
2529
ProcessHookBeforeList = "hook_before_list"
2630
ProcessList = "list"
2731
ProcessHookAfterList = "hook_after_list"
2832
ProcessGetIncluded = "get_included"
2933
ProcessGetIncludedSafe = "get_included_safe"
3034

35+
// Patch processes
3136
ProcessHookBeforePatch = "hook_before_patch"
3237
ProcessPatch = "patch"
3338
ProcessHookAfterPatch = "hook_after_patch"
3439
ProcessPatchBelongsToRelations = "patch_belongs_to_relations"
3540

41+
// Delete processes
3642
ProcessReducePrimaryFilters = "reduce_primary_filters"
3743
ProcessHookBeforeDelete = "hook_before_delete"
3844
ProcessDelete = "delete"
3945
ProcessHookAfterDelete = "hook_after_delete"
4046
ProcessDeleteForeignRelations = "delete_foreign_relations"
4147
ProcessDeleteForeignRelationsSafe = "delete_foreign_relations_safe"
4248

49+
// Transaction processes
4350
ProcessTxBegin = "tx_begin"
4451
ProcessTxCommitOrRollback = "tx_commit_or_rollback"
4552
)

query/const.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ const (
5656
ProcessGetForeignRelationsSafe = internal.ProcessGetForeignRelationsSafe
5757
ProcessHookAfterGet = internal.ProcessHookAfterGet
5858

59+
ProcessCheckPagination = internal.ProcessCheckPagination
5960
ProcessHookBeforeList = internal.ProcessHookBeforeList
6061
ProcessList = internal.ProcessList
6162
ProcessHookAfterList = internal.ProcessHookAfterList

query/pagination.go

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ const (
4949
// Pagination defines the query limits and offsets.
5050
// It defines the maximum size (Limit) as well as an offset at which
5151
// the query should start.
52+
// If the pagination type is 'LimitOffsetPagination' the value of 'Size' defines the 'limit'
53+
// where the value of 'Offset' defines it's 'offset'.
54+
// If the pagination type is 'PageNumberPagination' the value of 'Size' defines 'pageSize'
55+
// and the value of 'Offset' defines 'pageNumber'. The page number value starts from '1'.
5256
type Pagination struct {
5357
// Size is a pagination value that defines 'limit' or 'page size'
5458
Size int
@@ -57,11 +61,61 @@ type Pagination struct {
5761
Type PaginationType
5862
}
5963

60-
// Check checks if the pagination is well formed.
61-
func (p *Pagination) Check() error {
64+
// IsValid checks if the pagination is well formed.
65+
func (p *Pagination) IsValid() error {
6266
return p.checkValues()
6367
}
6468

69+
// GetLimitOffset gets the 'limit' and 'offset' values from the given pagination.
70+
// If the pagination type is 'LimitOffsetPagination' then the value of 'limit' = p.Size
71+
// and the value of 'offset' = p.Offset.
72+
// In case when pagination type is 'PageNumberPagination' the 'limit' = p.Size and the
73+
// offset is a result of multiplication of (pageNumber - 1) * pageSize = (p.Offset - 1) * p.Size.
74+
// If the p.Offset is zero value then the (pageNumber - 1) value would be set previously to '0'.
75+
func (p *Pagination) GetLimitOffset() (limit, offset int) {
76+
switch p.Type {
77+
case LimitOffsetPagination:
78+
limit = p.Size
79+
offset = p.Offset
80+
case PageNumberPagination:
81+
limit = p.Size
82+
// the p.Offset value is a page number that starts it's value from '1'.
83+
// If it's value is zero - the offset = 0.
84+
if p.Offset >= 1 {
85+
offset = (p.Offset - 1) * p.Size
86+
}
87+
default:
88+
log.Warningf("Unknown pagination type: '%v'", p.Type)
89+
}
90+
return limit, offset
91+
}
92+
93+
// GetNumberSize gets the 'page number' and 'page size' from the pagination.
94+
// If the pagination type is 'PageNumberPagination' the results are just the values of pagination.
95+
// In case the pagination type is of 'LimitOffsetPagination' then 'limit'(Size) would be the page size
96+
// and the page number would be 'offset' / limit + 1. PageNumberPagination starts it's page number counting from 1.
97+
// If the offset % size != 0 - the offset is not dividable by the size without the rest - then the division
98+
// rounds down it's value.
99+
func (p *Pagination) GetNumberSize() (pageNumber, pageSize int) {
100+
switch p.Type {
101+
case LimitOffsetPagination:
102+
pageSize = p.Size
103+
// the default pageNumber value is '1'.
104+
pageNumber = 1
105+
// if the 'limit' and 'offset' values are greater than zero - compute the value of pageNumber.
106+
if p.Size > 0 && p.Offset > 0 {
107+
// page numbering starts from '1' thus the result would be
108+
pageNumber = p.Offset/p.Size + 1
109+
}
110+
case PageNumberPagination:
111+
pageSize = p.Size
112+
pageNumber = p.Offset
113+
default:
114+
log.Warningf("Unknown pagination type: '%v'", p.Type)
115+
}
116+
return pageNumber, pageSize
117+
}
118+
65119
// IsZero checks if the pagination is already set.
66120
func (p *Pagination) IsZero() bool {
67121
return p.Size == 0 && p.Offset == 0
@@ -94,7 +148,7 @@ func (p *Pagination) FormatQuery(q ...url.Values) url.Values {
94148
}
95149
case PageNumberPagination:
96150
number, size := p.Offset, p.Size
97-
if number != 0 {
151+
if number >= 1 {
98152
k = ParamPageNumber
99153
v = strconv.Itoa(number)
100154
query.Set(k, v)
@@ -156,9 +210,9 @@ func (p *Pagination) checkPageBasedValues() error {
156210
return err
157211
}
158212

159-
if p.Offset < 0 {
213+
if p.Offset <= 0 {
160214
err := errors.NewDet(class.QueryPaginationValue, "invalid pagination value")
161-
err.SetDetails("Pagination page-number lower than 0")
215+
err.SetDetails("Pagination page-number lower equalt to 0")
162216
return err
163217
}
164218
return nil

query/pagination_test.go

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@ import (
1212
func TestPaginationFormatQuery(t *testing.T) {
1313
t.Run("Paged", func(t *testing.T) {
1414
p := &Pagination{Size: 10, Offset: 2, Type: PageNumberPagination}
15-
require.NoError(t, p.Check())
15+
require.NoError(t, p.IsValid())
1616

1717
q := url.Values{}
1818

1919
p.FormatQuery(q)
2020
require.Len(t, q, 2)
2121

22-
assert.Equal(t, "10", q.Get(ParamPageSize), "%+v", p)
22+
assert.Equal(t, "10", q.Get(ParamPageSize))
2323
assert.Equal(t, "2", q.Get(ParamPageNumber))
2424
})
2525

2626
t.Run("Limited", func(t *testing.T) {
2727
p := &Pagination{Size: 10}
2828

29-
require.NoError(t, p.Check())
29+
require.NoError(t, p.IsValid())
3030

3131
q := p.FormatQuery()
3232
require.Len(t, q, 1)
@@ -37,7 +37,7 @@ func TestPaginationFormatQuery(t *testing.T) {
3737
t.Run("Offseted", func(t *testing.T) {
3838
p := &Pagination{Offset: 10}
3939

40-
require.NoError(t, p.Check())
40+
require.NoError(t, p.IsValid())
4141

4242
q := p.FormatQuery()
4343
require.Len(t, q, 1)
@@ -48,7 +48,7 @@ func TestPaginationFormatQuery(t *testing.T) {
4848
t.Run("LimitOffset", func(t *testing.T) {
4949
p := &Pagination{10, 140, LimitOffsetPagination}
5050

51-
require.NoError(t, p.Check())
51+
require.NoError(t, p.IsValid())
5252

5353
q := p.FormatQuery()
5454
require.Len(t, q, 2)
@@ -57,3 +57,53 @@ func TestPaginationFormatQuery(t *testing.T) {
5757
assert.Equal(t, "140", q.Get(ParamPageOffset))
5858
})
5959
}
60+
61+
// TestGetLimitOffset tests the pagination GetLimitOffset method.
62+
func TestGetLimitOffset(t *testing.T) {
63+
// At first check the default 'LimitOffsetPagination'.
64+
p := &Pagination{Size: 1, Offset: 10}
65+
limit, offset := p.GetLimitOffset()
66+
assert.Equal(t, 1, limit)
67+
assert.Equal(t, 10, offset)
68+
69+
// Check the pagination with PageNumberPagination type.
70+
t.Run("PageNumber", func(t *testing.T) {
71+
p = &Pagination{Type: PageNumberPagination, Size: 3, Offset: 9}
72+
limit, offset = p.GetLimitOffset()
73+
74+
// the offset would be (pageNumber - 1) * pageSize = 8 * 3 = 24
75+
assert.Equal(t, 24, offset)
76+
assert.Equal(t, 3, limit)
77+
78+
// Check the pagination without page number defined.
79+
p = &Pagination{Type: PageNumberPagination, Size: 10}
80+
limit, offset = p.GetLimitOffset()
81+
82+
assert.Equal(t, 0, offset)
83+
assert.Equal(t, 10, limit)
84+
})
85+
}
86+
87+
// TestGetNumberSize tests the pagination GetNumberSize method.
88+
func TestGetNumberSize(t *testing.T) {
89+
// At first check the 'PageNumberPagination'.
90+
p := &Pagination{Type: PageNumberPagination, Size: 3, Offset: 9}
91+
number, size := p.GetNumberSize()
92+
93+
assert.Equal(t, 9, number)
94+
assert.Equal(t, 3, size)
95+
96+
t.Run("LimitOffsetTyped", func(t *testing.T) {
97+
// Check the 'LimitOffsetPagination' with defined fields.
98+
p = &Pagination{Size: 3, Offset: 10}
99+
number, size = p.GetNumberSize()
100+
assert.Equal(t, 3, size)
101+
assert.Equal(t, 4, number)
102+
103+
// Check the values with zero values.
104+
p = &Pagination{Size: 10}
105+
number, size = p.GetNumberSize()
106+
assert.Equal(t, 10, size)
107+
assert.Equal(t, 1, number)
108+
})
109+
}

query/process-lists.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,16 @@ func beforeListFunc(ctx context.Context, s *Scope) error {
8080

8181
return nil
8282
}
83+
84+
// checkPaginationFunc is the process func that checks the validity of the pagination
85+
func checkPaginationFunc(ctx context.Context, s *Scope) error {
86+
if _, ok := s.StoreGet(processErrorKey); ok {
87+
return nil
88+
}
89+
90+
if s.Pagination == nil {
91+
return nil
92+
}
93+
94+
return s.Pagination.IsValid()
95+
}

query/processor.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func init() {
4747
RegisterProcessFunc(ProcessHookAfterGet, afterGetFunc)
4848

4949
// List
50+
RegisterProcessFunc(ProcessCheckPagination, checkPaginationFunc)
5051
RegisterProcessFunc(ProcessHookBeforeList, beforeListFunc)
5152
RegisterProcessFunc(ProcessList, listFunc)
5253
RegisterProcessFunc(ProcessHookAfterList, afterListFunc)

query/scope-pagination.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func (s *Scope) Limit(limit, offset int) error {
1515
}
1616

1717
s.Pagination = &Pagination{Size: limit, Offset: offset}
18-
if err := s.Pagination.Check(); err != nil {
18+
if err := s.Pagination.IsValid(); err != nil {
1919
return err
2020
}
2121
return nil
@@ -27,8 +27,8 @@ func (s *Scope) Page(number, size int) error {
2727
return errors.NewDet(class.QueryPaginationAlreadySet, "pagination already set")
2828
}
2929

30-
s.Pagination = &Pagination{Size: size, Offset: number}
31-
if err := s.Pagination.Check(); err != nil {
30+
s.Pagination = &Pagination{Size: size, Offset: number, Type: PageNumberPagination}
31+
if err := s.Pagination.IsValid(); err != nil {
3232
return err
3333
}
3434
return nil

0 commit comments

Comments
 (0)