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%
2.7 KB · 84 lines typescript
Raw Blame History
1import 'server-only';2import { getDb, getSql, closeDb, schema } from '@cancerindex/database';34/** Server-side database handle for server components, route handlers and server actions. */5export const db = () => getDb();6export { getDb, getSql, closeDb, schema };7export type { Database } from '@cancerindex/database';8export { sql, eq, and, or, desc, asc, gte, lte, lt, gt, inArray, isNull, isNotNull, ilike, count, ne } from 'drizzle-orm';9import type { SQL } from 'drizzle-orm';1011// Tables re-exported explicitly (webpack handles `export *` chains, but explicit names keep the web12// bundle's dependency graph obvious and typecheck failures local).13export const {14  cancers,15  cancerAliases,16  cancerHierarchy,17  cancerCodes,18  anatomicalSites,19  cancerAnatomy,20  geographies,21  sources,22  ingestRuns,23  connectorCursors,24  sourceRecords,25  provenance,26  unresolvedLabels,27  changeEvents,28  auditLog,29  genes,30  geneAliases,31  variants,32  variantClinicalSignificance,33  genomicCohorts,34  cancerGeneFrequencies,35  drugs,36  drugAliases,37  drugApprovals,38  clinicalTrials,39  trialConditions,40  trialInterventions,41  trialLocations,42  publications,43  publicationEntityEdges,44  literatureCounts,45  civicEvidenceItems,46  knowledgeEdges,47  epidemiologyObservations,48  survivalObservations,49  metricDefinitions,50  rankingSnapshots,51  rankings,52  entityCounters,53} = schema;5455import { DatabaseUnavailableError, isConnectionError } from '@/lib/db-errors';56export { DatabaseUnavailableError, isConnectionError };5758/**59 * Run a query and swallow query-level errors ("relation does not exist", bad column, cast…) so60 * pages render an EmptyState instead of crashing when a table has not been created on this61 * environment yet. Connection-level errors are NOT swallowed: they are rethrown as62 * DatabaseUnavailableError so the route's error.tsx renders (and nothing misleading — a 404 or63 * an empty state — gets cached by ISR while the database is down).64 */65export async function safe<T>(fn: () => Promise<T>, fallback: T): Promise<T> {66  try {67    return await fn();68  } catch (err) {69    if (err instanceof DatabaseUnavailableError) throw err;70    if (isConnectionError(err)) {71      if (process.env.NODE_ENV !== 'production') console.error('[cancerindex/web] database unavailable:', (err as Error).message);72      throw new DatabaseUnavailableError(err);73    }74    if (process.env.NODE_ENV !== 'production') console.error('[cancerindex/web] query failed:', (err as Error).message);75    return fallback;76  }77}7879/** Execute a raw SQL query and return plain typed rows (drops the RowList metadata wrapper). */80export async function run<T>(query: SQL): Promise<T[]> {81  const res = await getDb().execute(query);82  return Array.from(res as unknown as Iterable<T>);83}84