Add totalItems mode, sort key lowercasing, and simplified ordering

Layer the remaining concepts from the original PR on top of the
split-query foundation:

- totalItems parameter on REST API (GET and POST) and CatalogApi
- TotalItemsMode type replacing internal skipTotalItems boolean
- Sort field key lowercasing for search table comparison
- whereNotNull(search.value) on the list CTE to exclude truncated values
- Simplified ORDER BY (NULLS LAST removed since NULL values are
  already excluded by whereNotNull)
- New tests for NULL sort field values and multi-valued sort field
  totalItems accuracy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2026-05-21 11:52:37 +02:00
parent 74c5fbbafd
commit 8f20cc2f52
20 changed files with 339 additions and 69 deletions
@@ -0,0 +1,9 @@
---
'@backstage/plugin-catalog-backend': minor
---
`/entities/by-query` now accepts a `totalItems` parameter (`'include'` or `'exclude'`, default `'include'`) that controls whether the response's `totalItems` count is computed. Pass `'exclude'` to skip the count entirely when the caller doesn't need it — useful for cursor-paginated user interfaces that only display the count cosmetically. The accepted values list is forward-compatible: future modes (e.g. approximate counts) can be added without breaking existing callers.
The internal `queryEntities` implementation has also been refactored to run the list and count queries concurrently via `Promise.all`. The list query is now a single statement that the planner can drive with `LIMIT` short-circuiting (no longer wrapped in a multi-reference CTE that forced materialization). Together with `totalItems: 'exclude'` this materially improves the wall-clock time of paginated catalog list views — particularly cursor-paginated user interfaces and second-page-and-onwards traffic where the count is already cached on the cursor.
The internal `QueryEntitiesInitialRequest.skipTotalItems` option has been replaced by `totalItems: 'include' | 'exclude'`. Note that `skipTotalItems` was never exposed as a REST API parameter, so this is only a TypeScript-level change affecting direct callers of `EntitiesCatalog.queryEntities`.
@@ -0,0 +1,5 @@
---
'@backstage/catalog-client': minor
---
`CatalogApi.queryEntities` now accepts a `totalItems` option (`'include'` or `'exclude'`, default `'include'`) on initial requests. Pass `'exclude'` to skip the `totalItems` count when the caller doesn't need it.