Skip to content

Keep search results ordered when batch-loading persons#132

Merged
atomantic merged 1 commit into
mainfrom
cos/sys-a5765c61-feature-ideas-mqx52lbc/agent-82110013
Jun 28, 2026
Merged

Keep search results ordered when batch-loading persons#132
atomantic merged 1 commit into
mainfrom
cos/sys-a5765c61-feature-ideas-mqx52lbc/agent-82110013

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

The SQLite search path (searchWithSqlitegetPersonsBatch) was silently losing its sort order. searchWithSqlite computes the result order with ORDER BY display_name and passes the ordered ids to getPersonsBatch, but that loader fetched rows with WHERE person_id IN (...) — which SQLite returns in table (rowid) order, not in the order of the IN list. The requested ordering was discarded, so the default (unsorted) search view in SearchPage appeared randomly ordered.

The fix indexes the fetched rows by id and assembles the result by iterating the input personIds, so the caller's order is preserved and ids with no matching row are skipped. This is a single-pass change — the loop now emits in order directly instead of assembling in DB order and re-sorting.

While here, this removes the dead searchService.quickSearch and searchService.searchGlobal methods (no callers anywhere — the live quick-search route in person.routes.ts has its own inline SQL) and the now-unused idMappingService import. These were the last remaining N+1 person-load loops in the search service, closing out PLAN "Next Up" #4.

Test plan

  • New tests/unit/services/databaseBatch.spec.ts pins the batch loader's contract: returns persons in the caller-requested order (not SQLite table order), drops requested ids with no row, returns [] for an empty list. The order test fails without the fix (mock returns table order, test asserts requested order).
  • npx tsc -p server/tsconfig.json --noEmit — clean.
  • Full suite: npx vitest run tests/unit tests/integration — 165 passed.

`searchWithSqlite` computes its result order with `ORDER BY display_name`
and passes the ordered ids to `getPersonsBatch`. That loader fetched rows
with `WHERE person_id IN (...)`, which SQLite returns in table (rowid)
order — silently discarding the requested order, so the default search
view appeared randomly sorted. Assemble persons by iterating the input
`personIds` (looking each row up in a by-id map) so the caller's order is
preserved and ids with no row are skipped.

Also removes the dead `searchService.quickSearch` and `searchGlobal`
methods (no callers anywhere — the live quick-search route has its own
inline SQL) and the now-unused `idMappingService` import. These were the
last remaining N+1 person-load loops in the search service, closing out
PLAN "Next Up" #4. New unit tests guard the batch loader's ordering and
missing-id behavior.
@atomantic atomantic merged commit f591932 into main Jun 28, 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