Each limit/offset list method gains an iterator twin that walks pages transparently and stops on the first short page — same endpoints, no new API surface: Python generators (iter_tenant_streams / _stream_events / _windows / _checkpoints / iter_fork_evidence / iter_tenant_ivc_epochs), TypeScript async iterators (for await ... of client.iterTenantStreamEvents(...)), and a Go Iterator with Next(ctx) returning (nil, nil) at exhaustion, plus Iter* twins on the client. Tests drain a 3-page mocked response set in order and confirm a short first page ends iteration after exactly one request. READMEs updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
81 lines
2.6 KiB
Go
81 lines
2.6 KiB
Go
package attesto
|
|
|
|
import "context"
|
|
|
|
// PageFunc fetches one limit/offset page of list results.
|
|
type PageFunc func(ctx context.Context, limit, offset int) ([]M, error)
|
|
|
|
// Iterator walks limit/offset pages of a list endpoint transparently, stopping
|
|
// on the first short page. Same endpoints, no new API surface.
|
|
type Iterator struct {
|
|
fetch PageFunc
|
|
pageSize int
|
|
buffer []M
|
|
offset int
|
|
done bool
|
|
}
|
|
|
|
// NewIterator wraps any limit/offset PageFunc. pageSize <= 0 defaults to 100.
|
|
func NewIterator(fetch PageFunc, pageSize int) *Iterator {
|
|
if pageSize <= 0 {
|
|
pageSize = 100
|
|
}
|
|
return &Iterator{fetch: fetch, pageSize: pageSize}
|
|
}
|
|
|
|
// Next returns the next item, or (nil, nil) when the listing is exhausted.
|
|
func (it *Iterator) Next(ctx context.Context) (M, error) {
|
|
if len(it.buffer) == 0 && !it.done {
|
|
page, err := it.fetch(ctx, it.pageSize, it.offset)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
it.offset += it.pageSize
|
|
if len(page) < it.pageSize {
|
|
it.done = true
|
|
}
|
|
it.buffer = page
|
|
}
|
|
if len(it.buffer) == 0 {
|
|
return nil, nil
|
|
}
|
|
item := it.buffer[0]
|
|
it.buffer = it.buffer[1:]
|
|
return item, nil
|
|
}
|
|
|
|
// IterTenantStreamEvents returns an iterator over a stream's events.
|
|
func (c *Client) IterTenantStreamEvents(streamID string, pageSize int) *Iterator {
|
|
return NewIterator(func(ctx context.Context, limit, offset int) ([]M, error) {
|
|
return c.ListTenantStreamEvents(ctx, streamID, limit, offset)
|
|
}, pageSize)
|
|
}
|
|
|
|
// IterTenantWindows returns an iterator over a stream's windows.
|
|
func (c *Client) IterTenantWindows(streamID string, pageSize int) *Iterator {
|
|
return NewIterator(func(ctx context.Context, limit, offset int) ([]M, error) {
|
|
return c.ListTenantWindows(ctx, streamID, limit, offset)
|
|
}, pageSize)
|
|
}
|
|
|
|
// IterTenantCheckpoints returns an iterator over a stream's checkpoints.
|
|
func (c *Client) IterTenantCheckpoints(streamID string, pageSize int) *Iterator {
|
|
return NewIterator(func(ctx context.Context, limit, offset int) ([]M, error) {
|
|
return c.ListTenantCheckpoints(ctx, streamID, limit, offset)
|
|
}, pageSize)
|
|
}
|
|
|
|
// IterForkEvidence returns an iterator over a stream's fork evidence.
|
|
func (c *Client) IterForkEvidence(streamID string, pageSize int) *Iterator {
|
|
return NewIterator(func(ctx context.Context, limit, offset int) ([]M, error) {
|
|
return c.ListForkEvidence(ctx, streamID, limit, offset)
|
|
}, pageSize)
|
|
}
|
|
|
|
// IterTenantIVCEpochs returns an iterator over a stream's IVC epochs.
|
|
func (c *Client) IterTenantIVCEpochs(streamID string, pageSize int) *Iterator {
|
|
return NewIterator(func(ctx context.Context, limit, offset int) ([]M, error) {
|
|
return c.ListTenantIVCEpochs(ctx, streamID, limit, offset)
|
|
}, pageSize)
|
|
}
|