spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
1import { sql } from 'drizzle-orm';2import type { Database } from '@cancerindex/database';3import type { SourceRef } from './envelope.js';45/**6 * Load source references for the envelope. Accepts CI-SOURCE ids and/or connector slugs (ranking7 * snapshots store slugs for count metrics and ids for epidemiology scopes).8 */9export async function loadSources(db: Database, refs: Iterable<string | null | undefined>): Promise<SourceRef[]> {10 const ids = new Set<string>();11 const slugs = new Set<string>();12 for (const r of refs) {13 if (!r) continue;14 if (r.startsWith('CI-SOURCE-')) ids.add(r);15 else slugs.add(r);16 }17 if (ids.size === 0 && slugs.size === 0) return [];18 const rows = await db.execute<{ id: string; slug: string; name: string; license: string | null; attribution: string | null; homepage: string | null }>(sql`19 SELECT id, slug, name, license, attribution, homepage FROM sources20 WHERE id = ANY(${sql.param([...ids])}::text[]) OR slug = ANY(${sql.param([...slugs])}::text[])21 ORDER BY slug`);22 return rows.map((r) => ({ id: r.id, slug: r.slug, name: r.name, license: r.license, attribution: r.attribution, url: r.homepage }));23}2425/** Collect a column from rows (null-safe). */26export function pluck<T extends Record<string, unknown>>(rows: readonly T[], ...keys: Array<keyof T>): string[] {27 const out: string[] = [];28 for (const r of rows) for (const k of keys) if (typeof r[k] === 'string') out.push(r[k] as string);29 return out;30}3132/** Sources that contributed codes, aliases or hierarchy edges to a set of cancers. */33export async function cancerStructuralSourceIds(db: Database, cancerIds: string[]): Promise<string[]> {34 if (cancerIds.length === 0) return [];35 const rows = await db.execute<{ source_id: string }>(sql`36 SELECT DISTINCT source_id FROM (37 SELECT source_id FROM cancer_codes WHERE cancer_id = ANY(${sql.param(cancerIds)}::text[]) AND source_id IS NOT NULL38 UNION SELECT source_id FROM cancer_aliases WHERE cancer_id = ANY(${sql.param(cancerIds)}::text[]) AND source_id IS NOT NULL39 UNION SELECT source_id FROM cancer_hierarchy WHERE (child_id = ANY(${sql.param(cancerIds)}::text[]) OR parent_id = ANY(${sql.param(cancerIds)}::text[])) AND source_id IS NOT NULL40 ) s`);41 return rows.map((r) => r.source_id);42}4344/** Most recent successful ingest finish — used for the dataRelease label. Cached by the caller. */45export async function latestDataAsOf(db: Database): Promise<Date | undefined> {46 const rows = await db.execute<{ t: string | null }>(sql`SELECT max(finished_at)::text AS t FROM ingest_runs WHERE status IN ('succeeded','partial')`);47 const t = rows[0]?.t;48 return t ? new Date(t) : undefined;49}50