Skip to content

fix: reuse cursor-carried total count instead of recounting each page - #9

Merged
DrSkillIssue merged 1 commit into
mainfrom
fix/count-redundant
May 29, 2026
Merged

DrSkillIssue merged 1 commit into
mainfrom
fix/count-redundant

Conversation

@DrSkillIssue

Copy link
Copy Markdown
Owner

IncludeCount re-ran COUNT(*) on every page even though the total was already embedded in the cursor. The cached value was only consulted when IncludeCount was false. Deep pagination with a count therefore paid a full COUNT scan per page.

Now a cursor-carried count is reused as-is; COUNT(*) runs only on a cursor-less (first-of-chain) request and rides the cursor forward. Changing the query is itself a cursor-less request, so the count recomputes against the new filter there.

  • Centralize the count decision in TotalCountResolver (was duplicated across PaginationExecutor, KeysetQueryExecutor, KeysetProjectionExecutor)
  • Add PaginationCount (None sentinel + AsNullable), replacing the scattered -1 / > 0 / >= 0 count-absence handling
  • Document the cursor-query contract (a cursor is bound to its filter)
  • Bump 3.0.1 -> 3.0.2

Behavior change: with IncludeCount, later pages in a chain report the count computed on the first page rather than a freshly recomputed one.

IncludeCount re-ran COUNT(*) on every page even though the total was
already embedded in the cursor — the cached value was only consulted
when IncludeCount was false. Deep pagination with a count therefore
paid a full COUNT scan per page.

Now a cursor-carried count is reused as-is; COUNT(*) runs only on a
cursor-less (first-of-chain) request and rides the cursor forward.
Changing the query is itself a cursor-less request, so the count
recomputes against the new filter there.

- Centralize the count decision in TotalCountResolver (was duplicated
  across PaginationExecutor, KeysetQueryExecutor, KeysetProjectionExecutor)
- Add PaginationCount (None sentinel + AsNullable), replacing the
  scattered -1 / > 0 / >= 0 count-absence handling
- Document the cursor-query contract (a cursor is bound to its filter)
- Bump 3.0.1 -> 3.0.2

Behavior change: with IncludeCount, later pages in a chain report the
count computed on the first page rather than a freshly recomputed one.
Identical for correct usage (pagination resets on filter change).
@DrSkillIssue
DrSkillIssue merged commit 65fe486 into main May 29, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant