Skip to content

Commit 91ffcdf

Browse files
authored
refactor!: unify the two pagination stacks into one (#202)
PR: #202
1 parent 1897c99 commit 91ffcdf

31 files changed

Lines changed: 1825 additions & 1261 deletions

CLAUDE.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,14 @@ unpublished and not listed below: `sdk-shrink-test`, a test-only R8 shrink-survi
4949
Key `sdk-core` packages (`org.dexpace.sdk.core.*`): `client` (the `HttpClient`/`AsyncHttpClient` transport
5050
SPIs), `http.request` / `http.response` / `http.common` (immutable models), `http.context` (context promotion
5151
chain), `http.sse` (WHATWG Server-Sent Events),
52-
`http.paging` (`PagedIterable`), `http.pipeline` (+`.steps` — stage-based sync/async pipeline runtime),
52+
`http.pipeline` (+`.steps` — stage-based sync/async pipeline runtime),
5353
`auth` (credentials, RFC 7235 challenges, Digest), `pipeline` (+`.step`, `.step.retry` — recovery-aware
5454
Request/Response/Execution pipeline primitives),
55-
`pagination` (Paginator + 4 strategies), `serde` (incl. `Tristate`), `instrumentation` (+`.metrics`), `io`,
55+
`pagination` (unified paging: `Page` (raw per-page `Response`, `Closeable`) / `PageInfo`,
56+
`Paginator`/`AsyncPaginator` with item- and page-level views, the auto-closing `CloseablePages`
57+
view returned by `byPage()`, `PagedIterable`, 3 strategies, internal `PageWalker` driver),
58+
`serde` (incl. `Tristate`),
59+
`instrumentation` (+`.metrics`), `io`,
5660
`config`, `util`, `generics`. The full package map with highlights is in `README.md`.
5761

5862
`docs/` (read before structural changes): `architecture.md`, `http.md`, `io.md`, `pipelines.md`,

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,8 @@ See [docs/pipelines.md](docs/pipelines.md) for the step-author walkthrough.
270270
| `http.pipeline` | Sync (`HttpStep` / `HttpPipeline` / `HttpPipelineBuilder` / `PipelineNext` / `Stage`) and async (`AsyncHttpStep` / `AsyncHttpPipeline` / `AsyncHttpPipelineBuilder` / `AsyncPipelineNext`) pipeline machinery, plus `AsyncPipelineBridges`. |
271271
| `http.pipeline.steps` | Concrete steps: `RetryStep`, `RedirectStep`, `AuthStep`, `KeyCredentialAuthStep`, `BearerTokenAuthStep`, `InstrumentationStep`, `SetDateStep`, and their `*Options` / `*Condition` types. |
272272
| `http.sse` | `ServerSentEventReader` (WHATWG spec), `ServerSentEvent`, `ServerSentEventListener`, `BufferedSource.readServerSentEvents()`. |
273-
| `http.paging` | `PagedIterable<T>`, `PagedResponse<T>`, `PagingOptions` with `byPage()` and `stream()` accessors. |
274273
| `auth` | `Credential` sealed hierarchy (`KeyCredential`, `NamedKeyCredential`, `BearerToken`), `BearerTokenProvider`, `AuthScheme`, per-operation `AuthRequirement` / `AuthDescriptor` with `AuthDescriptorResolver` precedence ladder, RFC 7235 challenge parser, `BasicChallengeHandler`, `DigestChallengeHandler`, `CompositeChallengeHandler`. |
275-
| `pagination` | `Paginator<T>` (with a `maxPages` safety cap) over cursor / page-number / link-header `PaginationStrategy` implementations, plus `Page<T>` / `SimplePage<T>`. Token-style APIs use `CursorPaginationStrategy` with the query-param name set (e.g. `"page_token"`). |
274+
| `pagination` | Unified paging surface: `Page<T>` (exposes the raw per-page `Response`; `Closeable`) / `PageInfo<T>`; `Paginator<T>` / `AsyncPaginator<T>` (strategy-driven, sync + async, each carrying a `maxPages` safety cap) exposing item-level (`iterateAll` / `streamAll`, which eager-close each page) and page-level views — sync `byPage` returns the auto-closing `CloseablePages` view (wrap in `use {}` / try-with-resources), async `forEachPageAsync` delivers a live page valid only during the consumer callback — over cursor / page-number / link-header `PaginationStrategy` implementations; `PagedIterable<T>` (functional, transport-agnostic first/next-page fetchers); and the internal `PageWalker` driver shared by the sync paths. Token-style APIs use `CursorPaginationStrategy` with the query-param name set (e.g. `"page_token"`). |
276275
| `operation` | `OperationParams` — SPI projecting an operation's typed inputs (path / query / header / body) into a `Request` and the context chain, via `toRequest(baseUrl)` / `toRequestContext(baseUrl, dispatch)`. |
277276
| `pipeline` | Recovery-aware primitives: `RequestPipeline`, `ResponsePipeline`, `ExecutionPipeline` over a sealed `ResponseOutcome`, with steps (`pipeline.step`, `pipeline.step.retry`) like `RetryStep`, `ResponseRecoveryStep`, `IdempotencyKeyStep`, `ClientIdentityStep`. |
278277
| `serde` | `Serde`, `Serializer`, `Deserializer` abstractions, `Tristate<T>` (absent / null / present), and `SerdeException` (the unchecked failure adapters translate codec errors into). |

docs/architecture.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,11 @@ java-sdk/
7979
http/response/ Response, ResponseBody, LoggableResponseBody, Status, typed exception hierarchy
8080
http/common/ Headers, MediaType, Protocol, CommonMediaTypes, ETag, HttpRange, conditions
8181
http/context/ Call/dispatch/request/exchange contexts + ContextStore
82-
http/paging/ PagedIterable, PagedResponse, PagingOptions
8382
http/pipeline/ Stage-based sync/async pipeline runtime (+ .steps)
8483
http/sse/ WHATWG Server-Sent Events reader/listener/events
8584
auth/ Credentials, RFC 7235 challenge parsing, Basic/Digest/Composite handlers
8685
pipeline/ Recovery-aware Request/Response/Execution pipeline primitives (+ .step, .step.retry)
87-
pagination/ Paginator + cursor/page-number/token/link-header strategies
86+
pagination/ Unified paging: Page (raw per-page Response, Closeable)/PageInfo, Paginator/AsyncPaginator (item- + page-level views), CloseablePages, PagedIterable, strategies, PageWalker driver
8887
client/ HttpClient + AsyncHttpClient interfaces (transport SPI)
8988
serde/ Serialization abstractions + Tristate
9089
instrumentation/ Tracing, spans, scopes, logging (+ .metrics)
@@ -344,16 +343,21 @@ for usage examples.
344343

345344
### Pagination
346345

347-
**Packages**: `org.dexpace.sdk.core.pagination`, `org.dexpace.sdk.core.http.paging`
346+
**Package**: `org.dexpace.sdk.core.pagination`
348347

349-
Two complementary surfaces for walking multi-page responses.
348+
One unified package for walking multi-page responses, offering two complementary entry styles
349+
(strategy-driven and functional) over a single `Page` type that exposes the raw per-page `Response`.
350350

351351
| Type | Role |
352352
|-----------------------------------------------------------------|-----------------------------------------------------------------------|
353-
| `Paginator<T>` | Lazily iterates pages by re-issuing requests through an `HttpClient`; carries a `maxPages` safety cap |
354-
| `PaginationStrategy<T>` | Computes the next-page request (or stops) from the current page |
353+
| `Page<T>` / `PageInfo<T>` | `Page<T>` exposes the raw per-page `Response` and is `Closeable`: its `items` are materialized and its `statusCode` / `headers` / `request` survive `close()`, while the raw response body/connection is live only while the page is current. `PageInfo<T>` is the strategy's parse result (items + next request) |
354+
| `CloseablePages<T>` | Auto-closing, single-use page-level view returned by `byPage()`: closes each page as you advance past it and closes the page still held on view-`close()`; exposes `iterator()` / `stream()`. Wrap in `use {}` (Kotlin) / try-with-resources (Java) so an early break still releases the held page |
355+
| `Paginator<T>` | Strategy-driven sync paginator over an `HttpClient`; exposes item-level (`iterateAll` / `streamAll`, which eager-close each page so item consumers carry no close burden) and page-level (`byPage`, returning a `CloseablePages`) views; carries a `maxPages` safety cap |
356+
| `AsyncPaginator<T>` | Non-blocking counterpart over an `AsyncHttpClient` (`forEachAsync` / `collectAllAsync` / `forEachPageAsync`); `forEachPageAsync` delivers a live page valid only during the consumer callback (the driver closes it as soon as the callback returns) |
357+
| `PaginationStrategy<T>` | Parses a response into a `PageInfo` — items plus the next-page request (or `null` to stop) |
355358
| `CursorPaginationStrategy` / `PageNumberPaginationStrategy` / `LinkHeaderPaginationStrategy` | The shipped strategies |
356-
| `PagedIterable<T>` | First/next-page fetcher abstraction over `PagedResponse`, with its own `maxPages` cap |
359+
| `PagedIterable<T>` | Functional, transport-agnostic first/next-page fetcher abstraction, with its own `maxPages` cap |
360+
| `PageWalker<T>` (internal) | Shared driver behind the sync paths, exposing a live-page iterator, an eager-closing item iterator, and an item stream |
357361

358362
Token-style APIs (`next_page_token`, `pageToken`, …) are handled by `CursorPaginationStrategy`
359363
constructed with the query-param name set (e.g. `"page_token"`), so no separate token strategy is needed.
@@ -730,14 +734,13 @@ they should construct a fresh one.
730734
| `http.response.exception` | HttpException, HttpExceptionFactory, Retryable, RequestTimeoutException (and siblings), NetworkException |
731735
| `http.common` | Headers, MediaType, CommonMediaTypes, Protocol, ETag, HttpRange, RequestConditions |
732736
| `http.context` | CallContext, DispatchContext, RequestContext, ExchangeContext, ContextStore |
733-
| `http.paging` | PagedIterable, PagedResponse, PagingOptions |
734737
| `http.pipeline` | HttpPipeline, HttpPipelineBuilder, HttpStep, Stage, AsyncHttpPipeline (+ `.steps`) |
735738
| `http.sse` | ServerSentEvent, ServerSentEventReader, ServerSentEventListener |
736739
| `auth` | Credential, KeyCredential, BearerToken, ChallengeHandler, Basic/Digest/CompositeChallengeHandler, AuthChallengeParser |
737740
| `pipeline` | RequestPipeline, ResponsePipeline, ExecutionPipeline, ResponseOutcome |
738741
| `pipeline.step` | PipelineStep, RequestPipelineStep, ResponsePipelineStep, ResponseRecoveryStep, ClientIdentityStep, IdempotencyKeyStep |
739742
| `pipeline.step.retry`| RetryStep, RetrySettings, BackoffCalculator, RetryAfterParser |
740-
| `pagination` | Paginator, PaginationStrategy, Cursor/PageNumber/Token/LinkHeader strategies, Page |
743+
| `pagination` | Page (Closeable; raw per-page Response), PageInfo, CloseablePages, Paginator, AsyncPaginator, PaginationStrategy, Cursor/PageNumber/LinkHeader strategies, PagedIterable, PageWalker (internal) |
741744
| `client` | HttpClient, AsyncHttpClient |
742745
| `serde` | Serde, Serializer, Deserializer, Tristate |
743746
| `instrumentation` | InstrumentationContext, Span, NoopSpan, NoopInstrumentationContext, Tracer, TracingScope, TraceIdType, ClientLogger |

docs/implementation-plan.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ defaults (per Square: `FAIL_ON_UNKNOWN_PROPERTIES=false`, `WRITE_DATES_AS_TIMEST
372372

373373
### WU-9: Pagination primitives
374374

375+
> Superseded by #30 (pagination unification): `Page` now exposes the raw per-page `Response` and is `Closeable` (materialized `items` and derived `statusCode` / `headers` / `request` survive `close()`), strategies return `PageInfo` (`nextRequest == null` = end of stream), and `SimplePage` was removed.
376+
375377
**Status: shipped.** `Page`, `Paginator`, `PaginationStrategy`, and the three strategies
376378
(`Cursor` / `PageNumber` / `LinkHeader`) are in `sdk-core/.../pagination`, alongside
377379
helper types `SimplePage` and `RequestRebuilder`. `Paginator` gained a `maxPages` safety cap

docs/refs-comparison.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ below records where each scheme's design was sourced from:
230230
### Pagination
231231

232232
`Paginator<T>` + `Page<T>` ship in `sdk-core`, driven by a `PaginationStrategy` (cursor,
233-
page-number, token, link-header), and `http.paging.PagedIterable` wraps the result. Reference
233+
page-number, token, link-header), and `pagination.PagedIterable` wraps the result. Reference
234234
designs we drew on:
235235

236236
- **Square**: `SyncPagingIterable<T>` (`Iterable<T>` lazy iterator), `SyncPage<T>` (per-page holder), `BiDirectionalPage<T>` (forward + backward cursors), `CustomPager<T>` (user-implementation stub for HATEOAS).

0 commit comments

Comments
 (0)