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.2 KB · 35 lines typescript
Raw Blame History
1import { sql } from 'drizzle-orm';2import type { FastifyPluginAsyncZod } from 'fastify-type-provider-zod';3import { z } from 'zod';4import { paginate } from '../lib/envelope.js';5import { pageQuery } from '../lib/pagination.js';6import { AnyList, camel, num, ok, respond } from '../lib/respond.js';78export const changeRoutes: FastifyPluginAsyncZod = async (app) => {9  app.get('/changes', { schema: { tags: ['changes'], summary: 'Entity change history (created/updated/trial_added/approval_added/ranking_changed/merged/deprecated)', querystring: z.object({ entityType: z.string().optional(), entityId: z.string().optional(), kind: z.string().optional(), since: z.string().optional().describe('ISO date lower bound'), ...pageQuery }), response: ok(AnyList, true) } }, async (req) => {10    const q = req.query;11    const conds = [sql`true`];12    if (q.entityType) conds.push(sql`e.entity_type = ${q.entityType}`);13    if (q.entityId) conds.push(sql`e.entity_id = ${q.entityId}`);14    if (q.kind) conds.push(sql`e.kind = ${q.kind}`);15    if (q.since) conds.push(sql`e.created_at >= ${q.since}::timestamptz`);16    const rows = await app.db.execute<Record<string, unknown> & { total: string }>(sql`17      SELECT e.id, e.entity_type, e.entity_id, e.kind, e.summary, e.before, e.after, e.ingest_run_id, e.created_at, r.connector_id, r.source_id,18        CASE e.entity_type WHEN 'cancer' THEN (SELECT canonical_name FROM cancers WHERE id = e.entity_id) WHEN 'gene' THEN (SELECT symbol FROM genes WHERE id = e.entity_id) WHEN 'drug' THEN (SELECT name FROM drugs WHERE id = e.entity_id) WHEN 'trial' THEN (SELECT nct_id FROM clinical_trials WHERE id = e.entity_id) END AS entity_name,19        count(*) OVER() AS total20      FROM change_events e LEFT JOIN ingest_runs r ON r.id = e.ingest_run_id21      WHERE ${sql.join(conds, sql` AND `)} ORDER BY e.created_at DESC, e.id DESC LIMIT ${q.limit} OFFSET ${q.offset}`);22    const total = rows.length ? num(rows[0]!.total) : 0;23    const data = rows.map((r) => {24      const { total: _t, source_id: _s, ...rest } = r;25      return camel(rest);26    });27    return respond(28      app,29      data,30      rows.map((r) => r.source_id as string | null),31      paginate(total, q.limit, q.offset),32    );33  });34};35