import { and, eq } from 'drizzle-orm'; import type { FinancialCadence, FinancialSurfaceKind } from '@/lib/types'; import { db, getSqliteClient } from '@/lib/server/db'; import { withFinancialIngestionSchemaRetry } from '@/lib/server/db/financial-ingestion-schema'; import { companyFinancialBundle } from '@/lib/server/db/schema'; export const CURRENT_COMPANY_FINANCIAL_BUNDLE_VERSION = 15; type CompanyFinancialBundleRecord = { id: number; ticker: string; surface_kind: FinancialSurfaceKind; cadence: FinancialCadence; bundle_version: number; source_snapshot_ids: number[]; source_signature: string; payload: Record; created_at: string; updated_at: string; }; function toBundleRecord(row: typeof companyFinancialBundle.$inferSelect): CompanyFinancialBundleRecord { return { id: row.id, ticker: row.ticker, surface_kind: row.surface_kind, cadence: row.cadence, bundle_version: row.bundle_version, source_snapshot_ids: row.source_snapshot_ids ?? [], source_signature: row.source_signature, payload: row.payload, created_at: row.created_at, updated_at: row.updated_at }; } export async function getCompanyFinancialBundle(input: { ticker: string; surfaceKind: FinancialSurfaceKind; cadence: FinancialCadence; }) { const [row] = await db .select() .from(companyFinancialBundle) .where(and( eq(companyFinancialBundle.ticker, input.ticker.trim().toUpperCase()), eq(companyFinancialBundle.surface_kind, input.surfaceKind), eq(companyFinancialBundle.cadence, input.cadence) )) .limit(1); return row ? toBundleRecord(row) : null; } export async function upsertCompanyFinancialBundle(input: { ticker: string; surfaceKind: FinancialSurfaceKind; cadence: FinancialCadence; sourceSnapshotIds: number[]; sourceSignature: string; payload: Record; }) { const now = new Date().toISOString(); const [saved] = await withFinancialIngestionSchemaRetry({ client: getSqliteClient(), context: 'company-financial-bundle-upsert', operation: async () => await db .insert(companyFinancialBundle) .values({ ticker: input.ticker.trim().toUpperCase(), surface_kind: input.surfaceKind, cadence: input.cadence, bundle_version: CURRENT_COMPANY_FINANCIAL_BUNDLE_VERSION, source_snapshot_ids: input.sourceSnapshotIds, source_signature: input.sourceSignature, payload: input.payload, created_at: now, updated_at: now }) .onConflictDoUpdate({ target: [ companyFinancialBundle.ticker, companyFinancialBundle.surface_kind, companyFinancialBundle.cadence ], set: { bundle_version: CURRENT_COMPANY_FINANCIAL_BUNDLE_VERSION, source_snapshot_ids: input.sourceSnapshotIds, source_signature: input.sourceSignature, payload: input.payload, updated_at: now } }) .returning() }); return toBundleRecord(saved); } export async function deleteCompanyFinancialBundlesForTicker(ticker: string) { return await db .delete(companyFinancialBundle) .where(eq(companyFinancialBundle.ticker, ticker.trim().toUpperCase())); } const __companyFinancialBundlesInternals = { BUNDLE_VERSION: CURRENT_COMPANY_FINANCIAL_BUNDLE_VERSION };