実装
package util
// Paginator paginator
type Paginator struct {
Limit int
Loop int
}
const defaultLimit = 50
// NewDefaultPaginator return Paginator
func NewDefaultPaginator() *Paginator {
return &Paginator{
Limit: defaultLimit,
}
}
// Pagination ページネーション
func (p *Paginator) Pagination(next func(p *Paginator) (bool, error)) error {
for {
isContinue, err := next(p)
if err != nil {
return err
}
if !isContinue {
break
}
p.Loop++
}
return nil
}
// IsBreak 総数から break 条件に達しているかチェック
func (p *Paginator) IsBreak(total int64) bool {
return p.Loop == int((total-1)/int64(p.Limit))+1
}
// Offset ページオフセット
func (p *Paginator) Offset() int {
return p.Loop * p.Limit
}
うさげ(テスト)
package util_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/voicyworld/total-sales-batch/internal/util"
)
func TestPagination(t *testing.T) {
p := util.NewDefaultPaginator()
num := 164
// 期待値 [1, 2, 3 ... 50, 1, 2, 3 ... 50 ...]
var expected []int
for i := 0; i < num; i++ {
expected = append(expected, i%50+1)
}
actualLoopCount := 0
actual := make([]int, num)
err := p.Pagination(func(p *util.Paginator) (bool, error) {
if p.IsBreak(int64(num)) {
return false, nil
}
max := p.Limit * (actualLoopCount + 1)
min := max - p.Limit
for i := 1; i <= p.Limit; i++ {
index := min + (i - 1)
if len(actual) <= index {
break
}
actual[index] = i
}
actualLoopCount++
return true, nil
})
assert.Nil(t, err)
assert.Equal(t, expected, actual)
assert.Equal(t, 4, actualLoopCount)
}
func TestIsBreak(t *testing.T) {
t.Parallel()
tests := []struct {
loop int
limit int
total int64
expected bool
}{
{0, 50, 1, false},
{1, 50, 1, true},
{0, 50, 50, false},
{1, 50, 50, true},
{1, 50, 51, false},
{2, 50, 51, true},
}
for i, tt := range tests {
t.Run(fmt.Sprint("case_", i), func(t *testing.T) {
p := &util.Paginator{
Limit: tt.limit,
Loop: tt.loop,
}
actual := p.IsBreak(tt.total)
assert.Equal(t, tt.expected, actual)
})
}
}
func TestOffset(t *testing.T) {
t.Parallel()
tests := []struct {
limit int
loop int
expected int
}{
{50, 0, 0},
{50, 1, 50},
{50, 2, 100},
}
for i, tt := range tests {
t.Run(fmt.Sprint("case_", i), func(t *testing.T) {
p := &util.Paginator{
Limit: tt.limit,
Loop: tt.loop,
}
actual := p.Offset()
assert.Equal(t, tt.expected, actual)
})
}
}