feat(bookstack-api-m6n): implement pagination iterator with iter.Seq2

Add generic listAll helper using Go 1.23+ iter.Seq2 for memory-efficient
pagination. Implement ListAll() on BooksService and PagesService.
Tests cover multi-page iteration, early break, errors, and empty results.
This commit is contained in:
Oliver Jakoubek 2026-01-30 09:51:35 +01:00
commit 6944d50512
6 changed files with 170 additions and 5 deletions

50
iterator.go Normal file
View file

@ -0,0 +1,50 @@
package bookstack
import (
"context"
"encoding/json"
"fmt"
"iter"
)
const defaultPageSize = 100
// listAllResponse is used internally to get both data and total from paginated endpoints.
type listAllResponse struct {
Data json.RawMessage `json:"data"`
Total int `json:"total"`
}
// listAll returns an iterator that paginates through all results for the given path.
func listAll[T any](ctx context.Context, c *Client, path string) iter.Seq2[T, error] {
return func(yield func(T, error) bool) {
offset := 0
for {
var resp listAllResponse
url := fmt.Sprintf("%s?count=%d&offset=%d", path, defaultPageSize, offset)
if err := c.do(ctx, "GET", url, nil, &resp); err != nil {
var zero T
yield(zero, err)
return
}
var items []T
if err := json.Unmarshal(resp.Data, &items); err != nil {
var zero T
yield(zero, fmt.Errorf("unmarshaling page data: %w", err))
return
}
for _, item := range items {
if !yield(item, nil) {
return
}
}
offset += len(items)
if offset >= resp.Total || len(items) == 0 {
return
}
}
}
}