Skip to content

feat(search): add relevance-based ranking for campaign and donation s…#160

Merged
BarryArinze merged 2 commits into
aid-linkk:masterfrom
DingiDinigi:feat/search-relevance-ranking
Jul 23, 2026
Merged

feat(search): add relevance-based ranking for campaign and donation s…#160
BarryArinze merged 2 commits into
aid-linkk:masterfrom
DingiDinigi:feat/search-relevance-ranking

Conversation

@DingiDinigi

Copy link
Copy Markdown
Contributor

Closes #148

Summary

Adds relevance-based ranking for campaign and donation search, while keeping existing pagination, filtering, and non-relevance sort options fully untouched.

Changes

  • search.service.ts: When sortBy: 'relevance' is requested, searchCampaigns/searchDonations route to new searchCampaignsByRelevance/searchDonationsByRelevance methods. These compute a per-field weighted relevance score via a parameterized $queryRaw CTE (exact match > prefix match > contains match tiers, weighted per field), order by score DESC, id ASC for deterministic results, and paginate with LIMIT/OFFSET in the same query. Ranked ids are then hydrated via a normal findMany (same include shape as today) and re-sorted in JS to preserve rank order, since WHERE id IN (...) doesn't guarantee row order.
  • All other sort options continue through the original, unmodified orderBy path.
  • User query input is LIKE-escaped before use in the raw SQL (fixes a minor pre-existing gap where special characters weren't escaped in the contains path either).
  • searchCampaigns's existing response cache covers the relevance path automatically (same cache-key strategy, no changes needed there).

Testing

  • Added 8 new tests covering: relevance path is selected correctly (and never touches the old count/orderBy path), score-descending/id-tiebreak ordering survives hydration reordering, pagination params (LIMIT/OFFSET) are correctly computed and passed, and non-relevance sorts are unaffected (regression).
  • Fixed a pre-existing test-environment gap: searchCampaigns tests previously hung indefinitely (10s timeout) because the test file didn't mock the Redis-backed cache utility, causing ioredis to retry a real connection forever in this sandbox. Added a mock so the cache always misses in tests — this was necessary to actually exercise searchCampaigns (relevance or otherwise) in this environment, not scope creep.
  • Full suite: 21/21 passing. npx tsc --noEmit: zero new type errors.

…earch

- Add weighted relevance scoring via parameterized $queryRaw when sortBy is 'relevance'
- Score computed from exact/prefix/contains match tiers across searched fields
- Deterministic ordering: score DESC, id ASC tiebreaker
- Existing orderBy/pagination path untouched for non-relevance sorts
- Add test-environment redis mock so searchCampaigns tests run without a live Redis
- Add 8 tests covering path selection, ordering after hydration, pagination params, and regression
@DingiDinigi
DingiDinigi force-pushed the feat/search-relevance-ranking branch from 11bba54 to 2f03555 Compare July 23, 2026 00:08
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.

Improve search result ranking and relevance ordering for campaign and donation queries

2 participants