func handleEntries(w http.ResponseWriter, r *http.Request) { ctx := context.Background() filter := fmt.Sprintf(`logName = "projects/%s/logs/testlog"`, *projectID) it := client.Entries(ctx, logadmin.Filter(filter)) var entries []*logging.Entry nextTok, err := iterator.NewPager(it, 5, r.URL.Query().Get("pageToken")).NextPage(&entries) if err != nil { http.Error(w, fmt.Sprintf("problem getting the next page: %v", err), http.StatusInternalServerError) return } data := struct { Entries []*logging.Entry Next string }{ entries, nextTok, } var buf bytes.Buffer if err := pageTemplate.Execute(&buf, data); err != nil { http.Error(w, fmt.Sprintf("problem executing page template: %v", err), http.StatusInternalServerError) } if _, err := buf.WriteTo(w); err != nil { log.Printf("writing response: %v", err) } }
// Test the iterator's behavior when used with iterator.Pager. func testPaging(vWant reflect.Value, create func() interface{}, next func(interface{}) (interface{}, error)) (string, bool) { // Test page sizes that are smaller, equal to, and greater than the length // of the expected sequence. for _, pageSize := range []int{1, 2, vWant.Len(), vWant.Len() + 10} { wantPages := wantedPages(vWant, pageSize) // Test the Pager in two ways. // First, by creating a single Pager and calling NextPage in a loop, // ignoring the page token except for detecting the end of the // iteration. it := create().(iterator.Pageable) pager := iterator.NewPager(it, pageSize, "") msg, ok := testPager(fmt.Sprintf("ignore page token, pageSize %d", pageSize), vWant.Type(), wantPages, func(_ string, pagep interface{}) (string, error) { return pager.NextPage(pagep) }) if !ok { return msg, false } // Second, by creating a new Pager for each page, passing in the page // token from the previous page, as would be done in a web handler. it = create().(iterator.Pageable) msg, ok = testPager(fmt.Sprintf("use page token, pageSize %d", pageSize), vWant.Type(), wantPages, func(pageToken string, pagep interface{}) (string, error) { return iterator.NewPager(it, pageSize, pageToken).NextPage(pagep) }) if !ok { return msg, false } } return "", true }
// Verify that, for an iterator that uses PageInfo.next to implement its Next // method, using Next and NextPage together result in an error. func TestNextWithNextPage(t *testing.T) { client := &Client{&service{end: 11}} var items []int // Calling Next before NextPage. it := client.Items(ctx) it.Next() _, err := iterator.NewPager(it, 1, "").NextPage(&items) if err == nil { t.Error("NextPage after Next: got nil, want error") } _, err = it.Next() if err == nil { t.Error("Next after NextPage: got nil, want error") } // Next between two calls to NextPage. it = client.Items(ctx) p := iterator.NewPager(it, 1, "") p.NextPage(&items) _, err = it.Next() if err == nil { t.Error("Next after NextPage: got nil, want error") } _, err = p.NextPage(&items) if err == nil { t.Error("second NextPage after Next: got nil, want error") } }
// Verify that we turn various potential reflection panics into errors. func TestNextPageReflectionErrors(t *testing.T) { client := &Client{&service{end: 1}} p := iterator.NewPager(client.Items(ctx), 1, "") // Passing the nil interface value. _, err := p.NextPage(nil) if err == nil { t.Error("nil: got nil, want error") } // Passing a non-slice. _, err = p.NextPage(17) if err == nil { t.Error("non-slice: got nil, want error") } // Passing a slice of the wrong type. var bools []bool _, err = p.NextPage(&bools) if err == nil { t.Error("wrong type: got nil, want error") } // Using a slice of the right type, but not passing a pointer to it. var ints []int _, err = p.NextPage(ints) if err == nil { t.Error("not a pointer: got nil, want error") } }
// The example demonstrates how to use a Pager to request a page from a given token. func Example_pageToken() { const pageSize = 5 const pageToken = "1337" p := iterator.NewPager(Primes(0), pageSize, pageToken) var items []int nextPage, err := p.NextPage(&items) if err != nil { log.Fatalf("Iterator paging failed: %v", err) } fmt.Printf("Primes: %v\nToken: %q\n", items, nextPage) // Output: // Primes: [1361 1367 1373 1381 1399] // Token: "1400" }
// This example demonstrates how to use a Pager to page through an iterator in a loop. func Example_pageLoop() { const pageSize = 25 ctx := context.Background() p := iterator.NewPager(client.Items(ctx), pageSize, "" /* start from the beginning */) for { var items []int pageToken, err := p.NextPage(&items) if err != nil { // TODO: handle error. } fmt.Println(items) if pageToken == "" { break } } }
func TestPager(t *testing.T) { const pageSize = 4 for _, svc := range []service{ {end: 0}, {end: 3}, {end: 3, zeroes: true}, {end: 11}, {end: 11, max: 2}, {end: 11, zeroes: true}, {end: 11, max: 2, zeroes: true}, } { var want [][]int switch svc.end { case 0: want = nil case 3: want = [][]int{{0, 1, 2}} case 11: want = [][]int{{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10}} default: t.Fatalf("unexpected svc.end %d", svc.end) } client := &Client{&svc} it := client.Items(ctx) p := iterator.NewPager(it, pageSize, "") var got [][]int for { var items []int tok, err := p.NextPage(&items) if err != nil { t.Fatalf("%v: %v", svc, err) } if tok != "" || len(items) != 0 { // edge case: 0-length sequence got = append(got, items) } if tok == "" { break } } if !reflect.DeepEqual(got, want) { t.Errorf("%v: got %v, want %v", svc, got, want) } } }
// This example demonstrates how to use a Pager to page through an iterator in a loop. func Example_pageLoop() { // Find all primes up to 42, in pages of size 5. const max = 42 const pageSize = 5 p := iterator.NewPager(Primes(max), pageSize, "" /* start from the beginning */) for page := 0; ; page++ { var items []int pageToken, err := p.NextPage(&items) if err != nil { log.Fatalf("Iterator paging failed: %v", err) } fmt.Printf("Page %d: %v\n", page, items) if pageToken == "" { break } } // Output: // Page 0: [2 3 5 7 11] // Page 1: [13 17 19 23 29] // Page 2: [31 37 41] }
// This example demonstrates how to use Pager to support // pagination on a web site. func Example_webHandler(w http.ResponseWriter, r *http.Request) { const pageSize = 25 it := client.Items(ctx) var items []int pageToken, err := iterator.NewPager(it, pageSize, r.URL.Query().Get("pageToken")).NextPage(&items) if err != nil { http.Error(w, fmt.Sprintf("getting next page: %v", err), http.StatusInternalServerError) } data := struct { Items []int Next string }{ items, pageToken, } var buf bytes.Buffer if err := pageTemplate.Execute(&buf, data); err != nil { http.Error(w, fmt.Sprintf("executing page template: %v", err), http.StatusInternalServerError) } w.Header().Set("Content-Type", "text/html; charset=utf-8") if _, err := buf.WriteTo(w); err != nil { log.Printf("writing response: %v", err) } }