feat: EntityPagination.onEvent — an optional hook of what is being fetched - #147
Merged
Conversation
…tched - New `EntityPaginationEvent<O>`, a `sealed` hierarchy so a `switch` over it is exhaustive, with `EntityPaginationListener<O>` as the callback type: `EntityPaginationPageLoading`, `EntityPaginationPageLoaded` (entries, elapsedTime, isFinalPage), `EntityPaginationPageError` (error, stackTrace), `EntityPaginationPageSkipped` (`alreadyLoaded` / `inFlight` / `knownEmpty`), `EntityPaginationEnd` (finalPage, totalLength) and `EntityPaginationReset` (discardedPages, discardedEntitiesLength, isRefresh). Everything but the reset is an `EntityPaginationPageEvent`, carrying the page. - Delivered synchronously and in order, so the sequence is also correct for a synchronous `EntityPageLoader` (a `Stream` would only deliver in a later microtask, after a sync read already finished). Forward it to get a stream: `onEvent: myEventStream.add`. - `onEvent` is not `final`, so it can be attached after construction. A listener that throws is reported to the current `Zone` and does not break the fetch. Nothing is allocated (not even the fetch timer) while it is `null`. - `paginateByQuery`, `paginate` and `paginateAll` gained the optional `onEvent` parameter, on `EntitySource`, `EntityRepository` and `APIRepository`. - `_setPage` now reports whether it resolved the final page, so `EntityPaginationEnd` is emitted exactly once and *after* the `EntityPaginationPageLoaded` that caused it. - Version 1.12.0 -> 1.13.0. 15 new tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #147 +/- ##
==========================================
+ Coverage 67.68% 67.77% +0.08%
==========================================
Files 64 64
Lines 21544 21607 +63
==========================================
+ Hits 14583 14644 +61
- Misses 6961 6963 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an optional hook to
EntityPagination, notified of what is being fetched — for progress reporting and logging over a paginated read.The events
EntityPaginationEvent<O>issealed, so aswitchover it is exhaustive.Everything but the reset is an
EntityPaginationPageEvent, carrying thepage.EntityPaginationPageLoadingEntityPaginationPageLoadedentries,entriesLength,elapsedTime,isFinalPageEntityPaginationPageErrorerror,stackTrace,elapsedTimeEntityPaginationPageSkippedreason:alreadyLoaded/inFlight/knownEmptyEntityPaginationEndfinalPage,totalLengthEntityPaginationResetdiscardedPages,discardedEntitiesLength,isRefreshDesign notes
EntityPaginationsupports a synchronousEntityPageLoader(loadPagehas a sync fast path), so aStreamwould deliver every event in a later microtask — after a sync read already finished. A callback is the right primitive here; a stream is one line on top of it:onEvent: myEventStream.add.onEventis notfinal, so it can also be attached to an already builtEntityPagination. Only events emitted afterwards are seen.Zoneand does not break the fetch.onEventisnull— not even the fetch timer._setPagenow reports whether it resolved the final page, soEntityPaginationEndis emitted exactly once and after theEntityPaginationPageLoadedthat caused it (rather than from inside_setPage, i.e. before it).EntityPaginationResetis emitted after the state is cleared, so the pagination already reads as empty and the discarded state travels on the event.isRefreshdistinguishesrefresh()(which re-fetches those pages right after) from a pagination that was simply emptied.getRangeandrefreshstart every page at once, so all the fetches are announced before any completes. Asserted in the tests.paginateByQuery,paginateandpaginateAllgained the optionalonEventparameter onEntitySource,EntityRepositoryandAPIRepository, so the hook is reachable without building anEntityPaginationby hand.Tests
15 new cases in
bones_api_entity_pagination_test.dart(37 → 52): the event sequence of a full read, of an exact multiple of the page size, of an empty result and of a failure; the 3 skip reasons; the synchronous delivery; a listener attached after construction; a throwing listener; and thereset/refreshevents.Full suite green: 686 passing +
ensure_build, no failures. Generated code is unaffected (build_runnerreports all 5 outputssame).Version bumped 1.12.0 → 1.13.0 (
pubspec.yaml,BonesAPI.VERSION, CHANGELOG), with the hook documented in the README's pagination section.🤖 Generated with Claude Code