Files
score-system/scripts/seed.ts
2026-07-05 13:46:16 +01:00

223 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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...');
// 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...');
const { hash } = await import('../src/lib/server/password.js');
let passwordHash = await hash('password');
await db
.insert(schema.scorers)
.values({
id: crypto.randomUUID(),
username: 'admin',
role: '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 (auto-generated from event types × divisions, ordered by division then event type)
const eventNameMap = new Map<string, number>();
for (const division of dbDivisions) {
for (const eventType of dbEventTypes) {
const [inserted] = await db
.insert(schema.registeredEvents)
.values({
eventType: eventType.id,
division: division.id,
state: 0,
timeCompleted: null,
teamWinner: null
})
.returning();
console.log(
` → Registered Event [id:${inserted.id}]: ${eventType.name} | ${division.name}`
);
eventNameMap.set(`${eventType.name}|${division.name}`, 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);
});