Files
score-system/scripts/seed.ts

218 lines
7.6 KiB
TypeScript

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<string, any>[] {
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...');
// Disable foreign keys globally during setup to prevent structural mismatches
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 client.execute('DELETE FROM sqlite_sequence');
console.log('Database reset complete. Seeding...');
// --- 1. 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})`);
}
// --- 2. 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}`);
}
// --- 2.5 Brackets (Added Section) ---
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}`);
}
// --- 2.75 resultPresets ---
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}`
);
}
// --- 3. 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`);
}
// Maps for dynamic relational lookups
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); // Look up newly seeded 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])); // Map names to IDs
const resultPresetMap = new Map(dbResults.map((b) => [b.presetName, b.id])); // Map names to IDs
// --- 4. 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}`
);
}
// --- 5. 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]));
// --- 6. Registered Events ---
const eventNameMap = new Map<string, number>();
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 the textual event name (e.g., "100m Sprint") to the generated DB ID
eventNameMap.set(`${row.event_type}|${row.division}`, inserted.id);
}
// --- 7. Registered Players ---
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}`);
// Dynamic look up of the bracket row's primary key ID using the CSV text
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, // Using the real relational ID instead of raw value
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 Foreign Key constraints now that the data is built cleanly
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);
});