Skip to content

Commit f382a96

Browse files
feat(extension): add limit/number pagintation extension
1 parent b0bd1a2 commit f382a96

File tree

6 files changed

+120
-8
lines changed

6 files changed

+120
-8
lines changed

extension/limit.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package extension
22

33
import (
44
"context"
5-
"github.com/velmie/q2sql"
5+
66
"github.com/velmie/qparser"
7+
8+
"github.com/velmie/q2sql"
79
)
810

911
// DefaultLimit is the extension that sets the query limit if it has not been set

extension/limit_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package extension
22

33
import (
44
"context"
5-
"github.com/velmie/q2sql"
6-
"github.com/velmie/qparser"
75
"strconv"
86

7+
"github.com/velmie/qparser"
8+
9+
"github.com/velmie/q2sql"
10+
911
"testing"
1012
)
1113

extension/pagination.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ import (
1212

1313
const Unlimited = int64(-1)
1414

15+
type LimitOffsetPaginationParams struct {
16+
MaxLimit int64
17+
MaxOffset int64
18+
LimitParameterName string
19+
OffsetParameterName string
20+
}
21+
1522
// LimitOffsetPagination is the extension
1623
// that sets limit and offset based on the corresponding fields of the given query.Page
1724
func LimitOffsetPagination(maxLimit, maxOffset int64) q2sql.Extension {
@@ -44,3 +51,37 @@ func LimitOffsetPagination(maxLimit, maxOffset int64) q2sql.Extension {
4451
return nil
4552
}
4653
}
54+
55+
// LimitNumberPagination is the extension
56+
// that sets limit and offset based on the corresponding fields of the given query.Page
57+
// where offset is a result of the expression limit * (number - 1)
58+
func LimitNumberPagination(maxLimit int64) q2sql.Extension {
59+
return func(_ context.Context, query *qparser.Query, builder *q2sql.SelectBuilder) error {
60+
page := query.Page
61+
if page == nil {
62+
return nil
63+
}
64+
if page.Limit == "" {
65+
return nil
66+
}
67+
limit, err := strconv.ParseUint(page.Limit, 10, 32)
68+
if err != nil {
69+
return fmt.Errorf("page limit must be unsigned integer, got %q", page.Limit)
70+
}
71+
if maxLimit != Unlimited && int64(limit) > maxLimit {
72+
return fmt.Errorf("page limit cannot be greater than %d", maxLimit)
73+
}
74+
builder.Limit(limit)
75+
76+
if page.Number != "" {
77+
number, err := strconv.ParseUint(page.Number, 10, 32)
78+
if err != nil {
79+
return fmt.Errorf("page number must be unsigned integer, got %q", page.Number)
80+
}
81+
if number != 1 {
82+
builder.Offset(limit * (number - 1))
83+
}
84+
}
85+
return nil
86+
}
87+
}

extension/pagination_test.go

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import (
1111
"github.com/velmie/q2sql"
1212
)
1313

14-
type paginationTest struct {
14+
type limitOffsetPaginationTest struct {
1515
p q2sql.Extension
1616
q *qparser.Query
1717
expectedErr bool
1818
limit int64
1919
offset int64
2020
}
2121

22-
var paginationTests = []paginationTest{
22+
var limitOffsetPaginationTests = []limitOffsetPaginationTest{
2323
{
2424
p: LimitOffsetPagination(Unlimited, Unlimited),
2525
q: &qparser.Query{Page: &qparser.Page{Offset: "10"}},
@@ -62,7 +62,72 @@ var paginationTests = []paginationTest{
6262

6363
func TestLimitOffsetPagination(t *testing.T) {
6464
ctx := context.Background()
65-
for i, tt := range paginationTests {
65+
for i, tt := range limitOffsetPaginationTests {
66+
meta := fmt.Sprintf("test %d", i)
67+
b := new(q2sql.SelectBuilder)
68+
err := tt.p(ctx, tt.q, b)
69+
if !tt.expectedErr && err != nil {
70+
t.Errorf("%s, unexpected error %s", meta, err)
71+
continue
72+
} else if err != nil {
73+
continue
74+
}
75+
if tt.limit > 0 && strconv.FormatInt(tt.limit, 10) != b.LimitPart {
76+
t.Errorf("%s, unexpected limit part, want %d, got %s", meta, tt.limit, b.LimitPart)
77+
}
78+
if tt.offset > 0 && strconv.FormatInt(tt.offset, 10) != b.OffsetPart {
79+
t.Errorf("%s, unexpected offset part, want %d, got %s", meta, tt.offset, b.OffsetPart)
80+
}
81+
}
82+
}
83+
84+
type limitNumberPaginationTest struct {
85+
p q2sql.Extension
86+
q *qparser.Query
87+
expectedErr bool
88+
limit int64
89+
offset int64
90+
}
91+
92+
var limitNumberPaginationTests = []limitNumberPaginationTest{
93+
{
94+
p: LimitNumberPagination(Unlimited),
95+
q: &qparser.Query{Page: &qparser.Page{Number: "10"}},
96+
expectedErr: false,
97+
},
98+
{
99+
p: LimitNumberPagination(Unlimited),
100+
q: &qparser.Query{Page: &qparser.Page{Limit: "invalid"}},
101+
expectedErr: true,
102+
},
103+
{
104+
p: LimitNumberPagination(Unlimited),
105+
q: &qparser.Query{Page: &qparser.Page{Limit: "1", Number: "invalid"}},
106+
expectedErr: true,
107+
},
108+
{
109+
p: LimitNumberPagination(Unlimited),
110+
q: &qparser.Query{Page: &qparser.Page{Limit: "10", Number: "1"}},
111+
expectedErr: false,
112+
limit: 10,
113+
},
114+
{
115+
p: LimitNumberPagination(Unlimited),
116+
q: &qparser.Query{Page: &qparser.Page{Limit: "50", Number: "10"}},
117+
expectedErr: false,
118+
limit: 50,
119+
offset: 450,
120+
},
121+
{
122+
p: LimitNumberPagination(5),
123+
q: &qparser.Query{Page: &qparser.Page{Limit: "500"}},
124+
expectedErr: true,
125+
},
126+
}
127+
128+
func TestLimitNumberPagination(t *testing.T) {
129+
ctx := context.Background()
130+
for i, tt := range limitNumberPaginationTests {
66131
meta := fmt.Sprintf("test %d", i)
67132
b := new(q2sql.SelectBuilder)
68133
err := tt.p(ctx, tt.q, b)

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module github.com/velmie/q2sql
22

3-
go 1.16
3+
go 1.17
44

5-
require github.com/velmie/qparser v0.1.0
5+
require github.com/velmie/qparser v0.2.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
github.com/velmie/qparser v0.1.0 h1:26GnJrk5LAFNvtGzJIcyUmhdn/u3cguvj400ZC/7flI=
22
github.com/velmie/qparser v0.1.0/go.mod h1:zApXCR5OzV0Txeqvg9R6hj0lKo8Msd9cKrpMsrEP3LA=
3+
github.com/velmie/qparser v0.2.0 h1:Mn3RGzrwH/rDfagY1wZUvMqzRtmwugchxc6zdls/KyU=
4+
github.com/velmie/qparser v0.2.0/go.mod h1:zApXCR5OzV0Txeqvg9R6hj0lKo8Msd9cKrpMsrEP3LA=

0 commit comments

Comments
 (0)