113 lines
3.3 KiB
TypeScript
113 lines
3.3 KiB
TypeScript
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<string, unknown>;
|
|
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<string, unknown>;
|
|
}) {
|
|
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
|
|
};
|