Use closures to count and mark.
diff --git a/pagination.go b/pagination.go
index 4b646a1..b0930e8 100644
--- a/pagination.go
+++ b/pagination.go
@@ -109,7 +109,7 @@
LastHTTPResponse
// lastMark is a captured function that returns the final entry on a given page.
- lastMark func(MarkerPage) (string, error)
+ lastMark func(Page) (string, error)
}
// NextPageURL generates the URL for the page of results after this one.
@@ -133,20 +133,23 @@
initialURL string
fetchNextPage func(string) (Page, error)
+
+ countPage func(Page) (int, error)
}
// NewPager constructs a manually-configured pager.
-// Supply the URL for the first page and a function that requests a specific page given a URL.
-func NewPager(initialURL string, fetchNextPage func(string) (Page, error)) Pager {
+// Supply the URL for the first page, a function that requests a specific page given a URL, and a function that counts a page.
+func NewPager(initialURL string, fetchNextPage func(string) (Page, error), countPage func(Page) (int, error)) Pager {
return Pager{
initialURL: initialURL,
fetchNextPage: fetchNextPage,
+ countPage: countPage,
}
}
// NewSinglePager constructs a Pager that "iterates" over a single Page.
// Supply the URL to request.
-func NewSinglePager(client *ServiceClient, onlyURL string) Pager {
+func NewSinglePager(client *ServiceClient, onlyURL string, countPage func(Page) (int, error)) Pager {
consumed := false
single := func(_ string) (Page, error) {
if !consumed {
@@ -168,11 +171,12 @@
return Pager{
initialURL: "",
fetchNextPage: single,
+ countPage: countPage,
}
}
// NewLinkedPager creates a Pager that uses a "links" element in the JSON response to locate the next page.
-func NewLinkedPager(client *ServiceClient, initialURL string) Pager {
+func NewLinkedPager(client *ServiceClient, initialURL string, countPage func(Page) (int, error)) Pager {
fetchNextPage := func(url string) (Page, error) {
resp, err := request(client, url)
if err != nil {
@@ -190,12 +194,15 @@
return Pager{
initialURL: initialURL,
fetchNextPage: fetchNextPage,
+ countPage: countPage,
}
}
// NewMarkerPager creates a Pager that iterates over successive pages by issuing requests with a "marker" parameter set to the
// final element of the previous Page.
-func NewMarkerPager(client *ServiceClient, initialURL string, lastMark func(MarkerPage) (string, error)) Pager {
+func NewMarkerPager(client *ServiceClient, initialURL string,
+ lastMark func(Page) (string, error), countPage func(Page) (int, error)) Pager {
+
fetchNextPage := func(currentURL string) (Page, error) {
resp, err := request(client, currentURL)
if err != nil {
@@ -213,6 +220,7 @@
return Pager{
initialURL: initialURL,
fetchNextPage: fetchNextPage,
+ countPage: countPage,
}
}
@@ -226,6 +234,14 @@
return err
}
+ count, err := p.countPage(currentPage)
+ if err != nil {
+ return err
+ }
+ if count == 0 {
+ return nil
+ }
+
ok, err := handler(currentPage)
if err != nil {
return err
diff --git a/pagination_test.go b/pagination_test.go
index a1c59bb..eb773bd 100644
--- a/pagination_test.go
+++ b/pagination_test.go
@@ -42,7 +42,15 @@
fmt.Fprintf(w, `{ "ints": [1, 2, 3] }`)
})
- return NewSinglePager(client, testhelper.Server.URL+"/only")
+ countPage := func(p Page) (int, error) {
+ is, err := ExtractSingleInts(p)
+ if err != nil {
+ return 0, err
+ }
+ return len(is), nil
+ }
+
+ return NewSinglePager(client, testhelper.Server.URL+"/only", countPage)
}
func TestEnumerateSinglePaged(t *testing.T) {
@@ -107,7 +115,15 @@
client := createClient()
- return NewLinkedPager(client, testhelper.Server.URL+"/page1")
+ countPage := func(p Page) (int, error) {
+ is, err := ExtractLinkedInts(p)
+ if err != nil {
+ return 0, err
+ }
+ return len(is), nil
+ }
+
+ return NewLinkedPager(client, testhelper.Server.URL+"/page1", countPage)
}
func TestEnumerateLinked(t *testing.T) {
@@ -174,18 +190,36 @@
client := createClient()
- return NewMarkerPager(client, testhelper.Server.URL+"/page", func(p MarkerPage) (string, error) {
+ lastMark := func(p Page) (string, error) {
items, err := ExtractMarkerStrings(p)
if err != nil {
return "", err
}
return items[len(items)-1], nil
- })
+ }
+
+ countPage := func(p Page) (int, error) {
+ items, err := ExtractMarkerStrings(p)
+ if err != nil {
+ return 0, err
+ }
+ fmt.Printf("Counting items [%#v] = [%d]\n", items, len(items))
+ return len(items), nil
+ }
+
+ return NewMarkerPager(client, testhelper.Server.URL+"/page", lastMark, countPage)
}
func ExtractMarkerStrings(page Page) ([]string, error) {
content := page.(MarkerPage).Body.([]uint8)
- return strings.Split(string(content), "\n"), nil
+ parts := strings.Split(string(content), "\n")
+ results := make([]string, 0, len(parts))
+ for _, part := range parts {
+ if len(part) > 0 {
+ results = append(results, part)
+ }
+ }
+ return results, nil
}
func TestEnumerateMarker(t *testing.T) {