Skip to content

Instantly share code, notes, and snippets.

@danieleli
Last active October 17, 2015 18:54
Show Gist options
  • Save danieleli/7de3762e880dab4031d2 to your computer and use it in GitHub Desktop.
Save danieleli/7de3762e880dab4031d2 to your computer and use it in GitHub Desktop.
package paging
import "fmt"
// SearchWindow contains start and stop
// and a default method for spliting the
// window into smaller windows
type SearchWindow struct {
start int64
stop int64
}
func (w *SearchWindow) SplitWindow() (SearchWindow, SearchWindow) {
midPoint := w.start + ((w.stop - w.start) / 2)
w1 := SearchWindow{
start: w.start,
stop: midPoint,
}
w2 := SearchWindow{
start: midPoint + 1,
stop: w.stop,
}
return w1, w2
}
// IntSearch is the interface for the remote api
type IntSearcher interface {
Search(inputs SearchWindow) []int
}
// PagedSearchCommand encapsulates paging logic
type PagedSearchCommand struct {
remoteApi IntSearcher
maxPageSize int
debug bool
}
func (cmd *PagedSearchCommand) Execute(w SearchWindow) []int {
if cmd.debug {
fmt.Println("Window: ", w)
}
items := cmd.remoteApi.Search(w)
if len(items) <= cmd.maxPageSize {
return items
}
w1, w2 := w.SplitWindow()
firstHalf := cmd.Execute(w1)
secondHalf := cmd.Execute(w2)
return append(firstHalf, secondHalf...)
}
package paging
import (
"testing"
"fmt"
)
func TestMe(t *testing.T) {
for _, datum := range testData {
datum.RunTest(t)
}
}
var testData = []testDatum{
{"Stop(10000) exceeeds total available(99)", 5, 70, 10000, 30},
{"PageSize(5) < total available(99)", 5, 1, 30, 30},
{"MaxPageSize > total available(99)", 99000, 1, 9000, 99},
{"MaxPageSize = total returned(99)", 10, 1, 10, 10},
{"MaxPageSize == returnCount - 1", 9, 1, 10, 10},
{"MaxPageSize == returnCount + 1", 11, 1, 10, 10},
{"MaxPageSize == 1", 1, 1, 10, 10},
}
type testDatum struct {
name string
max int
start int
stop int
expectedCount int
}
func (me *testDatum) RunTest(t *testing.T) {
fmt.Println("Test Name: ", me.name)
api := NewMockApi(me.max)
pagedSearch := PagedSearchCommand{
remoteApi: api,
maxPageSize: me.max,
}
w := SearchWindow{
start: int64(me.start),
stop: int64(me.stop),
}
items := pagedSearch.Execute (w)
actualCount := len(items)
if actualCount != me.expectedCount {
fmt.Println(items)
fmt.Printf("\nexpected %v \nactual %v\n", me.expectedCount, actualCount)
t.FailNow()
}
}
// ---------
// MockApi
// ---------
func NewMockApi(maxPageSize int) *MockApi {
values := []int{}
for i := 0; i < 100; i++ {
values = append(values, i)
}
api := MockApi{
values: values,
maxPageSize: int64(maxPageSize),
}
return &api
}
type MockApi struct {
values []int
maxPageSize int64
}
func (api *MockApi) Search(w SearchWindow) []int {
allItemCount := int64(len(api.values))
rtn := []int{}
for i := w.start; i <= w.stop; i++ {
hasMoreValues := i < allItemCount
isMaxSize := (i - w.start) > api.maxPageSize
if !hasMoreValues || isMaxSize {
return rtn
}
rtn = append(rtn, api.values[i])
}
return rtn
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment