SPB Git forge

spb/cancerindex

Public
37commits 1branches 0releases
2.9 MBsize
maindefault branch
10 days agolast push
TypeScript 97.2% SQL 1.5% CSS 0.6% JavaScript 0.5%
1.5 KB · 38 lines typescript
Raw Blame History
1/** Pure helpers for ranking rows (no DB, no server-only) — shared by the cancer Rankings tab and tests. */23export interface ScopedRankingRow {4  metric_slug: string;5  scope_key: string;6}78/** Year encoded in a scope key ("…|year=2021|…"); 0 when absent or "latest". */9export function scopeYear(scopeKey: string): number {10  const m = /year=(\d{4})/.exec(scopeKey);11  return m ? Number(m[1]) : 0;12}1314/** Scope key with the year component removed — identifies the (geo, sex, age, level) scope across years. */15export function scopeWithoutYear(scopeKey: string): string {16  return scopeKey17    .split('|')18    .filter((part) => !part.startsWith('year='))19    .join('|');20}2122/**23 * Keep one row per (metric, scope-without-year): the latest year. Earlier yearly snapshots are24 * left to the ranking pages. Input order is preserved for the surviving rows; ties on year keep25 * the first row seen.26 */27export function latestYearPerScope<T extends ScopedRankingRow>(rows: T[]): { rows: T[]; hidden: number } {28  const latest = new Map<string, { row: T; year: number; index: number }>();29  rows.forEach((r, index) => {30    const key = `${r.metric_slug}|${scopeWithoutYear(r.scope_key)}`;31    const year = scopeYear(r.scope_key);32    const cur = latest.get(key);33    if (!cur || year > cur.year) latest.set(key, { row: r, year, index: cur?.index ?? index });34  });35  const kept = [...latest.values()].sort((a, b) => a.index - b.index).map((x) => x.row);36  return { rows: kept, hidden: rows.length - kept.length };37}38