Files
Neon-Desk/lib/server/repos/company-overview-cache.ts

103 lines
2.8 KiB
TypeScript

import { and, eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/bun-sqlite';
import type { CompanyAnalysis } from '@/lib/types';
import { getSqliteClient } from '@/lib/server/db';
import { companyOverviewCache, schema } from '@/lib/server/db/schema';
export const CURRENT_COMPANY_OVERVIEW_CACHE_VERSION = 1;
type CompanyOverviewCacheRecord = {
id: number;
user_id: string;
ticker: string;
cache_version: number;
source_signature: string;
payload: CompanyAnalysis;
created_at: string;
updated_at: string;
};
function toRecord(row: typeof companyOverviewCache.$inferSelect): CompanyOverviewCacheRecord {
return {
id: row.id,
user_id: row.user_id,
ticker: row.ticker,
cache_version: row.cache_version,
source_signature: row.source_signature,
payload: row.payload as CompanyAnalysis,
created_at: row.created_at,
updated_at: row.updated_at
};
}
function getDb() {
return drizzle(getSqliteClient(), { schema });
}
export async function getCompanyOverviewCache(input: { userId: string; ticker: string }) {
const normalizedTicker = input.ticker.trim().toUpperCase();
if (!normalizedTicker) {
return null;
}
const [row] = await getDb()
.select()
.from(companyOverviewCache)
.where(and(
eq(companyOverviewCache.user_id, input.userId),
eq(companyOverviewCache.ticker, normalizedTicker)
))
.limit(1);
return row ? toRecord(row) : null;
}
export async function upsertCompanyOverviewCache(input: {
userId: string;
ticker: string;
sourceSignature: string;
payload: CompanyAnalysis;
}) {
const now = new Date().toISOString();
const normalizedTicker = input.ticker.trim().toUpperCase();
const [saved] = await getDb()
.insert(companyOverviewCache)
.values({
user_id: input.userId,
ticker: normalizedTicker,
cache_version: CURRENT_COMPANY_OVERVIEW_CACHE_VERSION,
source_signature: input.sourceSignature,
payload: input.payload as unknown as Record<string, unknown>,
created_at: now,
updated_at: now
})
.onConflictDoUpdate({
target: [companyOverviewCache.user_id, companyOverviewCache.ticker],
set: {
cache_version: CURRENT_COMPANY_OVERVIEW_CACHE_VERSION,
source_signature: input.sourceSignature,
payload: input.payload as unknown as Record<string, unknown>,
updated_at: now
}
})
.returning();
return toRecord(saved);
}
async function deleteCompanyOverviewCache(input: { userId: string; ticker: string }) {
const normalizedTicker = input.ticker.trim().toUpperCase();
return await getDb()
.delete(companyOverviewCache)
.where(and(
eq(companyOverviewCache.user_id, input.userId),
eq(companyOverviewCache.ticker, normalizedTicker)
));
}
const __companyOverviewCacheInternals = {
CACHE_VERSION: CURRENT_COMPANY_OVERVIEW_CACHE_VERSION
};