| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import { pool } from "@workspace/db"; |
| import { |
| PostgresCausalNetwork, |
| type CausalEdge, |
| type LiteratureBucket, |
| type LocalCausalNet, |
| type PgQueryable, |
| } from "@workspace/networks"; |
| import { logger } from "./logger"; |
|
|
| let _store: PostgresCausalNetwork | null = null; |
| let _ready: Promise<void> | null = null; |
| let _disabled = false; |
|
|
| |
| |
| |
| const pgQueryable: PgQueryable = pool; |
|
|
| function instance(): PostgresCausalNetwork { |
| if (!_store) _store = new PostgresCausalNetwork(pgQueryable); |
| return _store; |
| } |
|
|
| |
| |
| |
| export async function ensureCausalStoreReady(): Promise<boolean> { |
| if (_disabled) return false; |
| if (!_ready) { |
| _ready = instance() |
| .ensureSchema() |
| .catch((err) => { |
| _disabled = true; |
| logger.warn( |
| { err: err?.message ?? String(err) }, |
| "PostgresCausalNetwork unavailable; falling back to JSONL store", |
| ); |
| }); |
| } |
| await _ready; |
| return !_disabled; |
| } |
|
|
| export async function causalGetEdge( |
| edge_id: string, |
| ): Promise<CausalEdge | undefined> { |
| if (!(await ensureCausalStoreReady())) return undefined; |
| try { |
| return await instance().getEdge(edge_id); |
| } catch (err) { |
| logger.warn({ err, edge_id }, "PostgresCausalNetwork.getEdge failed"); |
| return undefined; |
| } |
| } |
|
|
| export async function causalEdgesForPaper( |
| paper_id: string, |
| ): Promise<CausalEdge[]> { |
| if (!(await ensureCausalStoreReady())) return []; |
| try { |
| return await instance().edgesForPaper(paper_id); |
| } catch (err) { |
| logger.warn({ err, paper_id }, "PostgresCausalNetwork.edgesForPaper failed"); |
| return []; |
| } |
| } |
|
|
| export async function causalSubgraphLocalNets( |
| paper_ids: string[], |
| ): Promise<LocalCausalNet[]> { |
| if (!(await ensureCausalStoreReady())) return []; |
| try { |
| const sub = await instance().subgraph(paper_ids); |
| return sub.listPaperIds().map((pid) => sub.getLocalNet(pid)!).filter(Boolean); |
| } catch (err) { |
| logger.warn({ err, paper_ids }, "PostgresCausalNetwork.subgraph failed"); |
| return []; |
| } |
| } |
|
|
| export async function causalListBuckets(): Promise<LiteratureBucket[]> { |
| if (!(await ensureCausalStoreReady())) return []; |
| try { |
| return await instance().listBuckets(); |
| } catch (err) { |
| logger.warn({ err }, "PostgresCausalNetwork.listBuckets failed"); |
| return []; |
| } |
| } |
|
|
| export async function causalEdgesInBucket( |
| bucket_id: string, |
| ): Promise<CausalEdge[]> { |
| if (!(await ensureCausalStoreReady())) return []; |
| try { |
| return await instance().edgesInBucket(bucket_id); |
| } catch (err) { |
| logger.warn({ err, bucket_id }, "PostgresCausalNetwork.edgesInBucket failed"); |
| return []; |
| } |
| } |
|
|
| export async function causalGetBucket( |
| bucket_id: string, |
| ): Promise<LiteratureBucket | undefined> { |
| if (!(await ensureCausalStoreReady())) return undefined; |
| try { |
| return await instance().getBucket(bucket_id); |
| } catch (err) { |
| logger.warn({ err, bucket_id }, "PostgresCausalNetwork.getBucket failed"); |
| return undefined; |
| } |
| } |
|
|
| |
| |
| |
| export function getCausalStore(): PostgresCausalNetwork | null { |
| return _disabled ? null : instance(); |
| } |
|
|