Files
sofa/lib/services/availability.ts
T
jakeandClaude Opus 4.6 29449fd02a Optimize database queries: add indexes, batch cron scans, transactional writes
Add covering indexes for recommendation rank ordering, title staleness scans,
and type+status filtering. Replace N+1 per-row staleness checks in cron jobs
with set-based batch queries. Wrap availability refresh in a transaction for
atomicity. Batch episode stills query and use existence check instead of
loading all rows for count.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:47:51 -05:00

67 lines
1.8 KiB
TypeScript

import { and, eq } from "drizzle-orm";
import { db } from "@/lib/db/client";
import { availabilityOffers, titles } from "@/lib/db/schema";
import { createLogger } from "@/lib/logger";
import { getWatchProviders } from "@/lib/tmdb/client";
const log = createLogger("availability");
export async function refreshAvailability(titleId: string) {
const title = db.select().from(titles).where(eq(titles.id, titleId)).get();
if (!title) return;
const data = await getWatchProviders(title.tmdbId, title.type);
const us = data.results?.US;
if (!us) {
log.debug(`No US providers for title ${titleId}`);
return;
}
const now = new Date();
const offerTypes = ["flatrate", "rent", "buy", "free", "ads"] as const;
db.transaction((tx) => {
// Delete existing offers for this title+region
tx.delete(availabilityOffers)
.where(
and(
eq(availabilityOffers.titleId, titleId),
eq(availabilityOffers.region, "US"),
),
)
.run();
for (const offerType of offerTypes) {
const providers = us[offerType];
if (!providers) continue;
for (const p of providers) {
tx.insert(availabilityOffers)
.values({
titleId,
region: "US",
providerId: p.provider_id,
providerName: p.provider_name,
logoPath: p.logo_path,
offerType,
link: us.link ?? null,
lastFetchedAt: now,
})
.onConflictDoNothing()
.run();
}
}
});
const total = offerTypes.reduce((n, t) => n + (us[t]?.length ?? 0), 0);
log.debug(`Refreshed availability for title ${titleId}: ${total} offers`);
}
export function getAvailability(titleId: string) {
return db
.select()
.from(availabilityOffers)
.where(eq(availabilityOffers.titleId, titleId))
.all();
}