Explorar o código

Update README to reflect v3 API

Jonathan D. Storm hai 6 meses
pai
achega
d116f05e39
Modificáronse 1 ficheiros con 102 adicións e 90 borrados
  1. 102 90
      README.md

+ 102 - 90
README.md

@@ -13,20 +13,20 @@ allows pagers to calculate page sizes and iterate over
 response aggregates.
 */
 type Page[T any] interface {
-	// Elems must return the items from the current page
-	Elems() []T
+  // Elems must return the items from the current page
+  Elems() []T
 }
 
 // Exposes the part of the client that depager understands.
 type Client[T any] interface {
-	// NextPage returns the next page or it returns an error
-	NextPage(
-		offset uint64, // item offset at which to start page
-	) (
-		page Page[T],
-		count uint64, // total count of all items being paged
-		err error,
-	)
+  // NextPage returns the next page or it returns an error
+  NextPage(
+    page Page[T],
+    offset uint64, // item offset at which to start page
+  ) (
+    count uint64, // total count of all items being paged
+    err error,
+  )
 }
 ```
 
@@ -34,11 +34,11 @@ And in return, *depager* provides the following:
 
 ```go
 type Pager[T any] interface {
-	// Iter is intended to be used in a for-range loop
-	Iter() <-chan T
+  // Iter is intended to be used in a for-range loop
+  Iter() <-chan T
 
-	// LastErr must return the first error encountered, if any
-	LastErr() error
+  // LastErr must return the first error encountered, if any
+  LastErr() error
 }
 
 ```
@@ -49,112 +49,124 @@ type Pager[T any] interface {
 package main
 
 import (
-    "context"
-    "fmt"
-    "log"
-    "net/http"
-    "net/url"
-    "os"
-
-    dp "idio.link/go/depager/v2"
+  "context"
+  "fmt"
+  "log"
+  "net/http"
+  "net/url"
+  "os"
+
+  dp "idio.link/go/depager/v3"
 )
 
 type MyClient struct {
-	pageSize uint64
-	// more fields
+  pageSize uint64
+  // more fields
 }
 
 func (c *MyClient) get(
-	uri *url.URL,
+  uri *url.URL,
 ) (head http.Header, body io.ReadCloser, err error) {
-	// do things
-	return
+  // do things
+  return
 }
 
 func (c *MyClient) pagify(
-	pathURI *url.URL,
-	first,
-	last uint64,
+  pathURI *url.URL,
+  first,
+  last uint64,
 ) (uri *url.URL) {
-	// glue path to base URI
-	return
+  // glue path to base URI
+  return
 }
 
-func (c *MyClient) Things(id int) dp.Pager[*Thing] {
-	// TODO validate; if used elsewhere, take boxed id instead
-	path := "/pile/%d/things"
-	subClient := &MySubclient[*Thing]{
-        MyClient: c,
-        path: url.Parse(fmt.Sprintf(path, id)),
-    }
-
-	return dp.NewPager(subClient, c.pageSize)
+func (c *MyClient) Things(id int) dp.Pager[Thing] {
+  // TODO validate; if used elsewhere, take boxed id instead
+  path := "/pile/%d/things"
+  subClient := &MySubclient[Thing]{
+    MyClient: c,
+    path:     url.Parse(fmt.Sprintf(path, id)),
+  }
+
+  // The page pool length determines the number of pages
+  // that depager will buffer. All pages must have equal,
+  // nonzero capacity. The capacity of the first page is
+  // taken to be the page size for all requests.
+  pagePool := make(chan Page[Thing], 4)
+  for i := 0; i < cap(pagePool); i++ {
+    tmp := MyAggregate[Thing](make([]Thing, 0, c.pageSize))
+    pagePool <- &tmp
+  }
+  return dp.NewPager(subClient, pagePool)
 }
 
 type MySubclient[T any] struct {
-	MyClient
+  MyClient
 
-	path *url.URL
+  path *url.URL
 }
 
 func (c *MySubclient[T]) NextPage(
-	offset uint64,
-) (page dp.Page[T], totalItems uint64, err error) {
-	/*
-	Different APIs use different conventions. Simply map 
-	`offset` to the apposite fields or headers with whatever
-	semantics the server expects.
-
-	Most days, the page size should be the largest that the
-	server is willing to accommodate.
-	*/
-	first := offset
-	last := first + c.pageSize - 1
-
-	uri := c.pagify(c.path, first, last)
-	header, body, err := c.get(uri)
-	page := &MyAggregate[T]{}
-	// parsing, etc.
-
-	/*
-	When returning the total count of all items to be paged,
-	if the server API only provides you the total number of
-	pages, simply calculate total*pageSize and return that.
-	*/
-	return page, totalItems, nil
+    page dp.Page[T],
+  offset uint64,
+) (totalItems uint64, err error) {
+  /*
+  Different APIs use different conventions. Simply map 
+  `offset` to the apposite fields or headers with whatever
+  semantics the server expects.
+
+  Most days, the page size should be the largest that the
+  server is willing to accommodate.
+  */
+  first := offset
+  last := first + c.pageSize - 1
+
+  uri := c.pagify(c.path, first, last)
+  header, body, err := c.get(uri)
+  // parsing, etc.
+
+  dst := *page.(*MyAggregate[T])
+  dst = dst[:min(cap(dst), len(src))]
+  copy(dst, src)                 // update values
+  *page.(*MyAggregate[T]) = dst  // update slice
+
+  /*
+  When returning the total count of all items to be paged,
+  if the server API only provides you the total number of
+  pages, simply calculate total*pageSize and return that.
+  */
+  return totalItems, nil
 }
 
-type MyAggregate[T any] struct {
-	Items []T `json:"items"`
-}
+type MyAggregate[T any] []T
 
 func (a *MyAggregate[T]) Elems() []T {
-	return a.Items
+  return []T(*a)
 }
 
 type Thing struct {
-	Id   int32	`json:"id"`
-	Name string `json:"name"`
+  Id   int32  `json:"id"`
+  Name string `json:"name"`
 }
 
 func main() {
-	ctx, _ := context.WithCancel(context.Background())
-	client := NewMyClient(...)
-	id := 82348
-	pager := client.Things(id)
-	for e := range pager.Iter() {
-		// there could be many pages; stay responsive!
-		if ctx.Err() != nil {
-				break
-		}
-		// do stuff with each thing
-	}
-
-	// finally, check for errors
-	if err := pager.LastErr(); err != nil {
-		log.Printf("do stuff with things: %v", err)
-		os.Exit(1)
-	}
+  ctx, _ := context.WithCancel(context.Background())
+  client := NewMyClient(...)
+  id := 82348
+  pager := client.Things(id)
+  for e := range pager.Iter() {
+    // there could be many pages; stay responsive!
+    if ctx.Err() != nil {
+        break
+    }
+    // do stuff with each thing
+  }
+
+  // finally, check for errors
+  if err := pager.LastErr(); err != nil {
+    log.Printf("do stuff with things: %v", err)
+    os.Exit(1)
+  }
 }
 ```