SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
1.7 KB · 35 lines typescript
Raw Blame History
1import 'server-only';2import { and, desc, eq, lte, sql } from '@/lib/db';3import { db, fxRates } from '@/lib/db';45/**6 * Convert an amount to USD at the rate of a given date (never today's rate for historical values).7 * fx_rates convention: base='USD', quote=<currency>, rate = units of quote per 1 USD.8 * Falls back to the latest rate on/before the date; returns null when no rate exists.9 */10export async function toUsdAt(amount: number, currency: string, date: string | null): Promise<{ usd: number; rate: number; fxDate: string } | null> {11  if (currency === 'USD') return { usd: amount, rate: 1, fxDate: date ?? new Date().toISOString().slice(0, 10) };12  const d = date ?? new Date().toISOString().slice(0, 10);13  const rows = await db()14    .select({ rate: fxRates.rate, date: fxRates.date })15    .from(fxRates)16    .where(and(eq(fxRates.base, 'USD'), eq(fxRates.quote, currency), lte(fxRates.date, d)))17    .orderBy(desc(fxRates.date))18    .limit(1);19  const r = rows[0];20  if (!r || !r.rate) return null;21  return { usd: amount / r.rate, rate: r.rate, fxDate: String(r.date) };22}2324/** Latest USD→currency rate for display conversion. 1 when unknown (caller shows USD then). */25export async function latestRate(currency: string): Promise<number | null> {26  if (currency === 'USD') return 1;27  const rows = await db().select({ rate: fxRates.rate }).from(fxRates).where(and(eq(fxRates.base, 'USD'), eq(fxRates.quote, currency))).orderBy(desc(fxRates.date)).limit(1);28  return rows[0]?.rate ?? null;29}3031export async function fxCoverage(): Promise<number> {32  const rows = (await db().execute(sql`select count(*)::int as n from fx_rates`)) as unknown as Array<{ n: number }>;33  return rows[0]?.n ?? 0;34}35