import { pgTable, text, integer, bigserial, index, uniqueIndex, boolean, jsonb, real } from 'drizzle-orm/pg-core'; import { ciId, createdAt, updatedAt } from './_common.js'; /** Publications (CLAUDE.md §10.6, §342): one entity per paper across PubMed/DOI/Europe PMC. */ export const publications = pgTable( 'publications', { id: ciId().primaryKey(), // CI-PUB-… pmid: text('pmid'), doi: text('doi'), pmcid: text('pmcid'), title: text('title').notNull(), abstract: text('abstract'), // stored only where NLM terms permit (abstract text may carry publisher copyright; we store it for indexing, display truncated with link) journal: text('journal'), journalIso: text('journal_iso'), pubDate: text('pub_date'), pubYear: integer('pub_year'), publicationTypes: text('publication_types').array().notNull().default([]), meshTerms: jsonb('mesh_terms').$type>().notNull().default([]), authors: jsonb('authors').$type>().notNull().default([]), language: text('language'), isPreprint: boolean('is_preprint').notNull().default(false), retracted: boolean('retracted').notNull().default(false), retractionNotice: text('retraction_notice'), nctIds: text('nct_ids').array().notNull().default([]), citedByCount: integer('cited_by_count'), sourceRecordId: integer('source_record_id'), ingestRunId: text('ingest_run_id'), createdAt: createdAt(), updatedAt: updatedAt(), }, (t) => [uniqueIndex('publications_pmid_uq').on(t.pmid), index('publications_doi_idx').on(t.doi), index('publications_year_idx').on(t.pubYear), index('publications_retracted_idx').on(t.retracted)], ); /** publication → entity links (CLAUDE.md §165-166, §271): extraction method + status preserved. */ export const publicationEntityEdges = pgTable( 'publication_entity_edges', { id: bigserial('id', { mode: 'number' }).primaryKey(), publicationId: ciId('publication_id').notNull(), entityType: text('entity_type').notNull(), // cancer | gene | variant | drug | biomarker | trial entityId: text('entity_id').notNull(), method: text('method').notNull(), // mesh | dictionary | registry_reference | civic_curation | ner | llm | curator confidence: real('confidence'), status: text('status').notNull().default('candidate'), // candidate | validated | rejected sourceId: ciId('source_id'), ingestRunId: text('ingest_run_id'), createdAt: createdAt(), }, (t) => [uniqueIndex('pub_entity_edges_uq').on(t.publicationId, t.entityType, t.entityId, t.method), index('pub_entity_edges_entity_idx').on(t.entityType, t.entityId)], ); /** Research activity counts per cancer from PubMed queries — the formula (query string) is stored (CLAUDE.md §251). */ export const literatureCounts = pgTable( 'literature_counts', { id: bigserial('id', { mode: 'number' }).primaryKey(), cancerId: ciId('cancer_id').notNull(), windowKey: text('window_key').notNull(), // all | 12m | 5y | 10y | y2015 … windowStart: text('window_start'), windowEnd: text('window_end'), query: text('query').notNull(), // exact PubMed query used count: integer('count').notNull(), provenanceId: integer('provenance_id').notNull(), computedAt: updatedAt(), }, (t) => [uniqueIndex('literature_counts_uq').on(t.cancerId, t.windowKey), index('literature_counts_window_idx').on(t.windowKey, t.count)], );