vikunja/pkg
kolaente 116fb1e2e0 fix(search): rank exact task-index match before BM25 text relevance on ParadeDB
The BM25 relevance ranking added `pdb.score(tasks.id)` to the search SELECT
and ORDER BY. ParadeDB can only compute a score for a pure-ParadeDB query
shape, so two cases produced "pq: Unsupported query shape":

1. A numeric search (e.g. "#17") OR's the ParadeDB `|||` operators with a
   plain `"index" = N` equality in the same boolean group. Scoring that mixed
   group is unsupported.
2. When favorites are in scope, the `project_id IN (...) OR id IN (<favorites
   subquery>)` predicate is unsupported under pdb.score regardless of how the
   subquery is expressed (OR or UNION) - it just was never exercised because
   the ranking tests searched a single project with no favorites.

Both are now handled so each query ParadeDB scores is a supported shape:

- Numeric search runs as two arms: an exact `index = N` arm (no score, ranked
  first) and a text `|||` arm scored by pdb.score DESC. The arms are merged in
  Go (index matches first, deduped by task id) and paginated in memory; the
  count query keeps the combined `OR index = N` predicate (no score), which is
  a supported shape, so totalItems stays correct.
- The relevance arms reach favorites through a LEFT JOIN and scope on the
  joined column (`rank_favorites.entity_id IS NOT NULL`) instead of an
  id-IN-subquery, which ParadeDB can score.

Non-numeric (pure text) searches keep the single pdb.score-ordered query.
Non-ParadeDB databases are unchanged (no pdb.score, no ranking).

TestTaskSearchRelevanceRankingNumericIndex covers the numeric case: on
ParadeDB the exact-index task ranks first, then text matches by relevance; on
other databases it only asserts the matches are returned.

Validated against the CI-pinned ParadeDB image (paradedb 0.21.12): the full
pkg/models and pkg/webtests suites pass, including
TestTaskCollection_ReadAll/search_for_task_index and the HTTP search tests.
2026-06-19 22:52:26 +02:00
..
audit refactor(events): use a concrete doer on project and team events 2026-06-12 08:56:08 +00:00
caldav fix(caldav): escape user-controlled strings per RFC 5545 in VCALENDAR output 2026-04-09 15:44:04 +00:00
caldavtests fix(caldav): skip tests for known CalDAV bugs and fix timing issues 2026-04-02 11:34:55 +00:00
cmd fix(cli): guard last admin on scheduled CLI deletion path 2026-04-20 18:55:06 +00:00
config feat(config): add audit logging config keys 2026-06-12 08:56:08 +00:00
cron fix: correct license header references (#882) 2025-06-10 12:18:38 +02:00
db fix(db): interpolate table identifiers in truncate instead of binding them 2026-06-17 12:13:50 +00:00
doctor feat(auth): enforce OpenID Connect issuer uniqueness across providers 2026-03-30 22:41:50 +00:00
e2etests test(webhook): assert bad webhook is retried in no-duplicate test 2026-04-09 09:26:04 +00:00
events fix(notifications): use full user so notifications show display name 2026-06-18 20:57:05 +00:00
files docs(api/v2): tag task attachment fields for the v2 schema 2026-06-10 10:22:39 +00:00
health feat: introduce shared health check logic (#1073) 2025-07-02 21:01:41 +00:00
i18n chore(i18n): update translations via Crowdin 2026-05-27 02:31:52 +00:00
initialize feat(audit): wire request-meta middleware and writer initialization 2026-06-12 08:56:08 +00:00
license fix(license): degrade to free when servers unreachable or key rejected 2026-04-20 18:55:06 +00:00
log fix(mail): guard log calls in GetMailDomain and fix hostname-dependent tests 2026-04-03 18:30:39 +00:00
mail feat: add Atom feed for user notifications with API token auth (#2758) 2026-05-15 17:25:09 +02:00
metrics refactor(metrics): count entities on demand with a TTL cache 2026-05-30 13:48:01 +00:00
migration fix(auth): build OIDC end-session URL with RP-Initiated Logout params (#2943) 2026-06-19 18:27:33 +02:00
models fix(search): rank exact task-index match before BM25 text relevance on ParadeDB 2026-06-19 22:52:26 +02:00
modules fix(auth): build OIDC end-session URL with RP-Initiated Logout params (#2943) 2026-06-19 18:27:33 +02:00
notifications fix(notifications): strip remote images from notification emails 2026-06-11 06:53:37 +00:00
plugins test(plugins): add yaegi plugin integration tests 2026-03-30 20:44:46 +00:00
red fix: correct license header references (#882) 2025-06-10 12:18:38 +02:00
routes fix(auth): build OIDC end-session URL with RP-Initiated Logout params (#2943) 2026-06-19 18:27:33 +02:00
swagger [skip ci] Updated swagger docs 2026-06-19 16:52:13 +00:00
user feat(api/v2): add totp qr code endpoint 2026-06-17 18:39:38 +00:00
utils fix: add timeouts to Gravatar, Unsplash, and SSRF-safe HTTP clients 2026-04-09 07:31:08 +00:00
version fix: correct license header references (#882) 2025-06-10 12:18:38 +02:00
web fix(files): never cache file downloads in v1 or v2 2026-06-17 18:39:38 +00:00
websocket feat(time-tracking): let clients subscribe to timer events 2026-06-08 13:54:09 +00:00
webtests fix(auth): build OIDC end-session URL with RP-Initiated Logout params (#2943) 2026-06-19 18:27:33 +02:00
yaegi_symbols refactor(user): remove the now-empty listeners file 2026-05-30 13:48:01 +00:00