import { drizzle } from 'drizzle-orm/libsql'; import { eq } from 'drizzle-orm'; import { createClient } from '@libsql/client'; import * as schema from '../src/lib/server/db/schema.js'; import { parse } from 'csv-parse/sync'; import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const dataDir = join(__dirname, 'data'); if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is not set'); const client = createClient({ url: process.env.DATABASE_URL }); const db = drizzle(client, { schema }); function readCSV(filename: string): Record[] { const content = readFileSync(join(dataDir, filename), 'utf-8'); return parse(content, { columns: true, skip_empty_lines: true, cast: true }); } async function seed() { console.log('Resetting database...'); // Temporarily disable FK checks during reset await client.execute('PRAGMA foreign_keys = OFF'); await db.delete(schema.scoreLedger); await db.delete(schema.mainLedger); await db.delete(schema.registeredPlayers); await db.delete(schema.registeredEvents); await db.delete(schema.registeredResults); await db.delete(schema.resultPresets); await db.delete(schema.eventTypes); await db.delete(schema.scoringPresets); await db.delete(schema.brackets); await db.delete(schema.players); await db.delete(schema.divisions); await db.delete(schema.teams); await db.delete(schema.scorers); await db.delete(schema.sessions); await client.execute('DELETE FROM sqlite_sequence'); console.log('Database reset complete. Seeding...'); let passwordHash = await Bun.password.hash('password'); await db .insert(schema.scorers) .values({ id: crypto.randomUUID(), username: 'admin', passwordHash: passwordHash }); // Seed teams const teamsCSV = readCSV('teams.csv'); for (const row of teamsCSV) { await db.insert(schema.teams).values({ name: row.team_name, color: row.color }); console.log(` → Team: ${row.team_name} (${row.color})`); } // Seed divisions const divisionsCSV = readCSV('divisions.csv'); for (const row of divisionsCSV) { await db.insert(schema.divisions).values({ name: row.div_name }); console.log(` → Division: ${row.div_name}`); } // Seed brackets const bracketsCSV = readCSV('brackets.csv'); for (const row of bracketsCSV) { await db.insert(schema.brackets).values({ name: row.bracket_name }); console.log(` → Bracket: ${row.bracket_name}`); } // Seed result presets const resultPresetsCSV = readCSV('resultPresets.csv'); for (const row of resultPresetsCSV) { await db.insert(schema.resultPresets).values({ presetName: row.presetName, numberOfResults: row.numberOfResults, unit: row.unit, lowerIsBetter: row.lowerIsBetter, averageResults: row.averageResults }); console.log( ` → Result Preset ${row.presetName}: ${row.numberOfResults} results, measured in ${row.unit}` ); } // Seed scoring presets const scoringPresetsCSV = readCSV('scoringPresets.csv'); for (const row of scoringPresetsCSV) { await db.insert(schema.scoringPresets).values({ presetID: row.preset, placement: row.placement, points: row.points }); console.log(` → Preset ${row.preset}: placement ${row.placement} = ${row.points}pts`); } // Build lookup maps for relational seeding const dbTeams = await db.select().from(schema.teams); const dbDivisions = await db.select().from(schema.divisions); const dbResults = await db.select().from(schema.resultPresets); const dbBrackets = await db.select().from(schema.brackets); const teamMap = new Map(dbTeams.map((t) => [t.name, t.id])); const divisionMap = new Map(dbDivisions.map((d) => [d.name, d.id])); const divisionNameMap = new Map([...divisionMap.entries()].map(([name, id]) => [id, name])); const bracketMap = new Map(dbBrackets.map((b) => [b.name, b.id])); const resultPresetMap = new Map(dbResults.map((b) => [b.presetName, b.id])); // Seed players const playersCSV = readCSV('players.csv'); for (const row of playersCSV) { const teamId = teamMap.get(row.team); const divisionId = divisionMap.get(row.division); if (!teamId) throw new Error(`Team "${row.team}" not found`); await db.insert(schema.players).values({ firstName: row.firstName, lastName: row.lastName, team: teamId, division: divisionId || null }); console.log( ` → Player: ${row.firstName} ${row.lastName} | team ${teamId} | division ${divisionId}` ); } // Seed event types const eventTypesCSV = readCSV('eventTypes.csv'); for (const row of eventTypesCSV) { const presetId = resultPresetMap.get(row.resultPreset); if (!presetId) throw new Error(`Team "${row.resultPreset}" not found`); await db.insert(schema.eventTypes).values({ name: row.event_name, scoringPreset: row.preset, resultPreset: presetId }); console.log( ` → Event Type: ${row.event_name} (preset ${row.preset}, resultPreset: ${row.resultPreset})` ); } const dbEventTypes = await db.select().from(schema.eventTypes); const eventTypeMap = new Map(dbEventTypes.map((et) => [et.name, et.id])); // Seed registered events const eventNameMap = new Map(); const registeredEventsCSV = readCSV('registeredEvents.csv'); for (const row of registeredEventsCSV) { const eventTypeId = eventTypeMap.get(row.event_type); const teamId = teamMap.get(row.winner); const divisionId = divisionMap.get(row.division); if (!eventTypeId) throw new Error(`Event Type "${row.event_type}" not found`); if (!divisionId) throw new Error(`Division "${row.division}" not found`); const [inserted] = await db .insert(schema.registeredEvents) .values({ eventType: eventTypeId, division: divisionId, state: row.event_state || 0, timeCompleted: row.time_completed || null, teamWinner: teamId || null }) .returning(); console.log( ` → Registered Event [id:${inserted.id}]: ${row.event_type} | ${row.division}, winner: ${teamId}, ${row.winner}` ); // Map event name|division to the generated event ID eventNameMap.set(`${row.event_type}|${row.division}`, inserted.id); } // Seed registered players (linking players to events) const dbPlayers = await db.select().from(schema.players); const playerMap = new Map(dbPlayers.map((p) => [`${p.firstName} ${p.lastName}`, p])); const registeredPlayersCSV = readCSV('registeredPlayers.csv'); for (const row of registeredPlayersCSV) { const player = playerMap.get(row.player_registered); const divisionName = divisionNameMap.get(player?.division ?? -1); const actualEventId = eventNameMap.get(`${row.event_registered}|${divisionName}`); const bracketId = bracketMap.get(row.bracket); if (!player) throw new Error(`Player "${row.player_registered}" not found`); if (!actualEventId) throw new Error( `Registered Event "${row.event_registered}" for division "${divisionName}" not found` ); if (!bracketId) throw new Error(`Bracket "${row.bracket}" not found in database`); await db.insert(schema.registeredPlayers).values({ playerID: player.id, registeredEventID: actualEventId, bracket: bracketId, placement: row.player_placement || 0 }); console.log( ` → Registered Player: ${row.player_registered} → ${row.event_registered} (division: ${divisionName}, bracket: ${row.bracket} [id:${bracketId}]) [eventId:${actualEventId}]` ); } // Re-enable FK checks await client.execute('PRAGMA foreign_keys = ON'); console.log('\n✅ Seeding complete!'); client.close(); } seed().catch((err) => { console.error('❌ Seed failed:', err); process.exit(1); });