import { PrismaClient, type HolidayCalendarEntry } from "@prisma/client"; import { buildHolidayCalendarSeedDefinitions } from "./holiday-calendar-seed-data.js"; import { loadWorkspaceEnv } from "./load-workspace-env.js"; import { assertCapaKrakenDbTarget } from "./safe-destructive-env.js"; loadWorkspaceEnv(); const prisma = new PrismaClient(); const YEARS = [2026, 2027]; const SEED_SOURCE = "seed:holiday-calendars:2026-2027"; type ExistingCalendar = { id: string; entries: Pick[]; }; function toUtcDate(isoDate: string): Date { return new Date(`${isoDate}T00:00:00.000Z`); } function dateKey(value: Date): string { return value.toISOString().slice(0, 10); } async function findScopedCalendar(input: { countryId: string; scopeType: "COUNTRY" | "STATE" | "CITY"; stateCode?: string | undefined; metroCityId?: string | undefined; }): Promise { return prisma.holidayCalendar.findFirst({ where: { countryId: input.countryId, scopeType: input.scopeType, stateCode: input.scopeType === "STATE" ? input.stateCode ?? null : null, metroCityId: input.scopeType === "CITY" ? input.metroCityId ?? null : null, }, select: { id: true, entries: { select: { id: true, date: true, source: true, }, }, }, }); } async function main() { assertCapaKrakenDbTarget("db:seed:holidays"); console.log("Seeding holiday calendars for 2026-2027..."); const countries = await prisma.country.findMany({ select: { id: true, code: true, name: true, metroCities: { select: { id: true, name: true, }, }, }, orderBy: { code: "asc" }, }); const activeGermanStatesRows = await prisma.resource.findMany({ where: { isActive: true, country: { code: "DE" }, federalState: { not: null }, }, select: { federalState: true }, distinct: ["federalState"], }); const definitions = buildHolidayCalendarSeedDefinitions({ availableCountryCodes: countries.map((country) => country.code), availableCitiesByCountry: Object.fromEntries( countries.map((country) => [ country.code, country.metroCities.map((city) => city.name), ]), ), activeGermanStates: activeGermanStatesRows .map((row) => row.federalState) .filter((stateCode): stateCode is string => Boolean(stateCode)), years: YEARS, }); const countryByCode = new Map(countries.map((country) => [country.code, country])); const cityByCountryAndName = new Map( countries.flatMap((country) => country.metroCities.map((city) => [`${country.code}:${city.name}`, city] as const), ), ); let createdCalendars = 0; let reusedCalendars = 0; let createdEntries = 0; let updatedEntries = 0; let skippedManualEntries = 0; for (const definition of definitions) { const country = countryByCode.get(definition.countryCode); if (!country) { continue; } const metroCity = definition.cityName ? cityByCountryAndName.get(`${definition.countryCode}:${definition.cityName}`) : null; if (definition.scopeType === "CITY" && !metroCity) { console.warn( `Skipping city calendar ${definition.name}: city ${definition.cityName ?? "?"} not found.`, ); continue; } let calendar = await findScopedCalendar({ countryId: country.id, scopeType: definition.scopeType, stateCode: definition.stateCode, metroCityId: metroCity?.id, }); if (!calendar) { calendar = await prisma.holidayCalendar.create({ data: { name: definition.name, scopeType: definition.scopeType, countryId: country.id, stateCode: definition.scopeType === "STATE" ? definition.stateCode ?? null : null, metroCityId: definition.scopeType === "CITY" ? metroCity?.id ?? null : null, priority: definition.priority, isActive: true, }, select: { id: true, entries: { select: { id: true, date: true, source: true, }, }, }, }); createdCalendars += 1; } else { reusedCalendars += 1; } const entriesByDate = new Map(calendar.entries.map((entry) => [dateKey(entry.date), entry])); for (const entry of definition.entries) { const existingEntry = entriesByDate.get(entry.date); if (!existingEntry) { await prisma.holidayCalendarEntry.create({ data: { holidayCalendarId: calendar.id, date: toUtcDate(entry.date), name: entry.name, isRecurringAnnual: entry.isRecurringAnnual, source: SEED_SOURCE, }, }); createdEntries += 1; continue; } if (existingEntry.source && existingEntry.source !== SEED_SOURCE) { skippedManualEntries += 1; continue; } await prisma.holidayCalendarEntry.update({ where: { id: existingEntry.id }, data: { name: entry.name, isRecurringAnnual: entry.isRecurringAnnual, source: SEED_SOURCE, }, }); updatedEntries += 1; } } console.log(` calendars created: ${createdCalendars}`); console.log(` calendars reused: ${reusedCalendars}`); console.log(` entries created: ${createdEntries}`); console.log(` entries updated: ${updatedEntries}`); console.log(` manual entries preserved: ${skippedManualEntries}`); } main() .catch((error) => { console.error(error); process.exit(1); }) .finally(() => prisma.$disconnect());