Skip to content

feat: add unpaginate util - #53

Merged
fratzinger merged 1 commit into
mainfrom
feat/unpaginate
Sep 14, 2026
Merged

fratzinger merged 1 commit into
mainfrom
feat/unpaginate

Conversation

@fratzinger

Copy link
Copy Markdown
Member

unpaginate

The lossy counterpart to toPaginated. Takes the result of a find that may or may not be paginated and yields the items:

export function unpaginate<R>(result: R[] | Paginated<R> | undefined | null): R[]
  • a plain array is returned as-is (same reference, no copy)
  • a paginated result yields its data
  • undefined/null yields []

This is the everyday case as soon as a service is consumed without knowing whether pagination is enabled for it or disabled via params.paginate: false. The pattern was already hand-rolled three times inside this repo.

total, limit and skip are dropped, so unpaginate(toPaginated(x)) round-trips but the reverse does not — the JSDoc says so explicitly. The returned array must be treated as read-only, like common/toArray.

changeMany now uses it in place of Array.isArray(found) ? found : (found?.data ?? []).

One thing to review

src/common/ now imports from src/utils/ for the first time — so far common has been a leaf layer. The import targets the file rather than the barrel, and unpaginate itself has only a type import, so a cycle is impossible. If the layering matters more than the single call site, changeMany can keep its ternary.

Drive-by: missing docs pages

replaceData and replaceResult had no .md, so they had no page on the docs site — missed when they were added in #32. Both JSDoc blocks already pointed at utils/replace-data.html and utils/replace-result.html, i.e. the @see links were dead. Frontmatter added for both; the three pagination utils (toPaginated, unpaginate, predicates/isPaginated) are now cross-linked.

Also carries the pagination tag additions to getResultIsArray and mutateResult.

Testing

pnpm test green: 134 files, 1449 passed / 2 skipped, no type errors, no lint errors. pnpm docs:build and pnpm build clean; the three new pages render.

Known, not addressed here

replaceResult writes only .data on a paginated result and leaves total untouched, so a length-changing replacement leaves a stale total (inherited by mutateResult via delegation, and untested — both tests only cover length-preserving cases). Arguably correct, since total is the number of matches in the database rather than the length of this page, but it is currently implicit. Left for a separate change.

🤖 Generated with Claude Code

The lossy counterpart to `toPaginated`: takes the result of a `find` that
may or may not be paginated and yields the items. A plain array is returned
as-is, a paginated result yields its `data`, and `undefined`/`null` yields an
empty array - so a `find` can be consumed without knowing whether pagination
is enabled for the service or disabled via `params.paginate: false`.

`changeMany` now uses it instead of hand-rolling the same ternary.

Also adds the docs frontmatter for `replaceData` and `replaceResult`, which
was missed when they were added in #32 - both JSDoc blocks already pointed at
`utils/replace-data.html` and `utils/replace-result.html`, pages that did not
exist.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying feathers-utils with  Cloudflare Pages  Cloudflare Pages

Latest commit: 5be4077
Status: ✅  Deploy successful!
Preview URL: https://5f7fa351.feathers-utils.pages.dev
Branch Preview URL: https://feat-unpaginate.feathers-utils.pages.dev

View logs

@fratzinger
fratzinger merged commit 9061216 into main Sep 14, 2026
9 checks passed
@fratzinger
fratzinger deleted the feat/unpaginate branch September 14, 2026 14:32
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