diff --git a/scripts/sync.ts b/scripts/sync.ts index 0ad4fef..7b80bb3 100644 --- a/scripts/sync.ts +++ b/scripts/sync.ts @@ -37,7 +37,7 @@ function parseScore(score: RawScore | undefined) { } async function run() { - const client = postgres(DATABASE_URL!, { max: 5 }) + const client = postgres(DATABASE_URL!, { max: 2 }) const db = drizzle(client) const teamCache = new Map() @@ -94,17 +94,32 @@ async function run() { return (rows[0] as { id: number }).id } - async function syncGoals(matchId: number, teamId: number, rawGoals: RawGoal[], isOwnGoalTeamId: number) { - for (const g of rawGoals) { - if (!g.name) continue + type GoalRow = { teamId: number; name: string; minute: number | null; offset: number; penalty: boolean; owngoal: boolean } + + function collectGoals(teamId: number, rawGoals: RawGoal[], isOwnGoalTeamId: number): GoalRow[] { + return rawGoals.flatMap(g => { + if (!g.name) return [] const minute = g.minute != null ? parseInt(String(g.minute)) : null - const scoringTeamId = g.owngoal ? isOwnGoalTeamId : teamId - await db.execute(sql` - INSERT INTO goals (match_id, team_id, player_name, minute, minute_offset, is_penalty, is_own_goal) - VALUES (${matchId}, ${scoringTeamId}, ${g.name}, ${isNaN(minute!) ? null : minute}, - ${g.offset ?? 0}, ${g.penalty ?? false}, ${g.owngoal ?? false}) - `) - } + return [{ teamId: g.owngoal ? isOwnGoalTeamId : teamId, name: g.name, + minute: isNaN(minute!) ? null : minute, offset: g.offset ?? 0, + penalty: g.penalty ?? false, owngoal: g.owngoal ?? false }] + }) + } + + async function replaceGoals(matchId: number, rows: GoalRow[]) { + await db.transaction(async tx => { + await tx.execute(sql`DELETE FROM goals WHERE match_id = ${matchId}`) + if (rows.length > 0) { + // Single bulk INSERT — readers see old goals until commit, never an empty window + const vals = rows.map(g => + sql`(${matchId}, ${g.teamId}, ${g.name}, ${g.minute}, ${g.offset}, ${g.penalty}, ${g.owngoal})` + ) + await tx.execute(sql` + INSERT INTO goals (match_id, team_id, player_name, minute, minute_offset, is_penalty, is_own_goal) + VALUES ${sql.join(vals, sql`, `)} + `) + } + }) } console.log('\nSyncing 2026...') @@ -153,9 +168,11 @@ async function run() { const score = parseScore(m.score) const matchId = await upsertMatch(2026, m.round ?? 'Unknown', m.group ?? null, m.date ?? null, m.time ?? null, t1Id, t2Id, score, false) if (m.goals1?.length || m.goals2?.length) { - await db.execute(sql`DELETE FROM goals WHERE match_id = ${matchId}`) - if (m.goals1?.length) await syncGoals(matchId, t1Id, m.goals1, t2Id) - if (m.goals2?.length) await syncGoals(matchId, t2Id, m.goals2, t1Id) + const goalRows = [ + ...(m.goals1?.length ? collectGoals(t1Id, m.goals1, t2Id) : []), + ...(m.goals2?.length ? collectGoals(t2Id, m.goals2, t1Id) : []), + ] + await replaceGoals(matchId, goalRows) } matchCount++ goalCount += (m.goals1?.length ?? 0) + (m.goals2?.length ?? 0) @@ -188,8 +205,13 @@ async function run() { const t2Id = await upsertTeam(m.team2) const score = parseScore(m.score) const matchId = await upsertMatch(2026, m.round ?? 'Qualifier', null, m.date ?? null, m.time ?? null, t1Id, t2Id, score, true) - if (m.goals1?.length) await syncGoals(matchId, t1Id, m.goals1, t2Id) - if (m.goals2?.length) await syncGoals(matchId, t2Id, m.goals2, t1Id) + if (m.goals1?.length || m.goals2?.length) { + const goalRows = [ + ...(m.goals1?.length ? collectGoals(t1Id, m.goals1, t2Id) : []), + ...(m.goals2?.length ? collectGoals(t2Id, m.goals2, t1Id) : []), + ] + await replaceGoals(matchId, goalRows) + } } console.log(` Quali playoffs: ${qualiData.matches.length} matches`) }