Skip to content

fix(web): query cases through PostgreSQL views - #340

Merged
berntpopp merged 1 commit into
berntpopp:mainfrom
robspan:web-postgres-cases-view-query
Aug 7, 2026
Merged

fix(web): query cases through PostgreSQL views#340
berntpopp merged 1 commit into
berntpopp:mainfrom
robspan:web-postgres-cases-view-query

Conversation

@robspan

@robspan robspan commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • group every projected case column when querying the migrated PostgreSQL cases view
  • add a real-PostgreSQL regression test to web-gate-postgres

Why

PostgreSQL cannot infer primary-key functional dependencies through the migrated cases view, so grouping only by c.id fails.

Validation

  • VARLENS_WEB=1 make ci
  • make web-gate-postgres
  • make agent-check

@berntpopp
berntpopp force-pushed the web-postgres-cases-view-query branch from 94dcb25 to 9aca951 Compare August 7, 2026 07:50

@berntpopp berntpopp left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — approve

Rebased onto main (330d736a) and reviewed in depth. This is not a cleanup PR: it fixes a bug that is live on main right now.

Root cause confirmed

Migration 0015_import_visibility — already merged — renames casescases_all and recreates cases as a VIEW. PostgreSQL only infers primary-key functional dependency for a base table, never through a view, so GROUP BY c.id while projecting c.name, c.file_path, … is rejected outright.

I verified this empirically by reverting only the source hunk and keeping the new test:

error: column "c.name" must appear in the GROUP BY clause or be used in an aggregate function

So case listing in web/Postgres mode is currently broken on main. This should land promptly.

The fix is complete, not partial

I audited every GROUP BY in src/main/storage/postgres/ (20 sites) against the two relations 0015 converts to views (cases, variants):

  • PostgresPanelsRepository GROUP BY p.id / gl.idpanels and gene_lists are base tables, so PK functional dependency is legal. Not affected.
  • PostgresCohortRepository:472 (GROUP BY v.case_id, c.name), PostgresCaseLifecycleRepository:148, getSummary's grouped subquery — all project exactly their grouped columns plus aggregates. Legal.
  • PostgresCasesQueryRepository.queryCasesthe only site that projected ungrouped columns from a view.

The new GROUP BY list matches the SELECT list exactly (7 c.* columns + cm.affected_status + cm.sex, with cohort_names/cohort_ids aggregated). Complete.

Count query is safe

countSql reuses whereSql but has no joins, which would break if a filter referenced cm.* or cg.*. It doesn't: all three predicates reference only c.name/c.id or are self-contained EXISTS subqueries. No latent breakage, and total_count stays consistent with the grouped row count.

Test quality

The e2e is a genuine regression guard, not a tautology — I confirmed it fails without the fix and passes with it. Isolated per-run schema, DROP SCHEMA … CASCADE cleanup in afterAll, correctly gated behind VARLENS_RUN_POSTGRES_E2E=1, and wired into make web-gate-postgres. The unit-test addition asserting each projected column appears in the GROUP BY is a nice cheap guard that runs without Postgres.

This gap is exactly why the bug shipped: the only prior coverage of /api/cases/list was openapi.test.ts, which asserts the route's schema, never executing the query.

Verification

  • make typecheck — clean
  • VARLENS_WEB=1 make test — 4785 passed (matches main baseline)
  • Postgres integration gate against a fresh DB — 15 passed / 1 skipped
  • New e2e — passes on the fix, fails without it
  • No console.*, no Electron/fuse/IPC invariants touched, no new SQL interpolation (only schemaName, via quoteIdentifier)

Non-blocking notes

  1. Grouping by 7 columns instead of 1 is a wider sort key, but cases is a small relation — immaterial.
  2. The test's fallback PG_URL uses port 55432 while .env.postgres.local in this repo uses 55434. Harmless (CI sets VARLENS_PG_URL), just noting the drift.
  3. Conflicts with #332 in the Makefile — both append a VARLENS_RUN_POSTGRES_E2E=1 line to web-gate-postgres. Trivial: merge the two file lists into one invocation.

@berntpopp
berntpopp marked this pull request as ready for review August 7, 2026 08:18
@berntpopp
berntpopp merged commit a10eed2 into berntpopp:main Aug 7, 2026
9 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.

2 participants