diff --git a/backend/src/db/functions/noteworthy_matches.py b/backend/src/db/functions/noteworthy_matches.py index 889b238a..017f22fe 100644 --- a/backend/src/db/functions/noteworthy_matches.py +++ b/backend/src/db/functions/noteworthy_matches.py @@ -55,14 +55,14 @@ def callback(session: SessionType): matches.add_columns( func.greatest(red_score_col, blue_score_col).label("max_score") ) - .order_by(desc("max_score"), asc(MatchORM.time)) # type: ignore + .order_by(desc("max_score").nullslast(), asc(MatchORM.time)) # type: ignore .limit(30) .all() ) combined_score_matches = ( matches.add_columns((red_score_col + blue_score_col).label("sum_score")) # type: ignore - .order_by(desc("sum_score"), asc(MatchORM.time)) # type: ignore + .order_by(desc("sum_score").nullslast(), asc(MatchORM.time)) # type: ignore .limit(30) .all() ) @@ -73,7 +73,7 @@ def callback(session: SessionType): "losing_score" ), ) - .order_by(desc("losing_score"), asc(MatchORM.time)) # type: ignore + .order_by(desc("losing_score").nullslast(), asc(MatchORM.time)) # type: ignore .limit(30) .all() ) @@ -86,7 +86,7 @@ def callback(session: SessionType): "max_auto_score" ) ) - .order_by(desc("max_auto_score"), asc("time")) # type: ignore + .order_by(desc("max_auto_score").nullslast(), asc("time")) # type: ignore .limit(30) .all() ) @@ -97,7 +97,7 @@ def callback(session: SessionType): "max_teleop_score" ) ) - .order_by(desc("max_teleop_score"), asc("time")) # type: ignore + .order_by(desc("max_teleop_score").nullslast(), asc("time")) # type: ignore .limit(30) .all() ) @@ -108,7 +108,7 @@ def callback(session: SessionType): "max_endgame_score" ) ) - .order_by(desc("max_endgame_score"), asc("time")) # type: ignore + .order_by(desc("max_endgame_score").nullslast(), asc("time")) # type: ignore .limit(30) .all() ) diff --git a/frontend/src/api/storage.tsx b/frontend/src/api/storage.tsx index d5b17b19..f7db1ebe 100644 --- a/frontend/src/api/storage.tsx +++ b/frontend/src/api/storage.tsx @@ -37,19 +37,14 @@ export function decompress(buffer: any) { return data; } -async function query( +const inFlight: { [storageKey: string]: Promise } = {}; + +async function fetchAndStore( storageKey: string, apiPath: string, checkBucket: boolean, - minLength: number, expiry: number ) { - const cacheData = await getWithExpiry(storageKey); - if (cacheData && (minLength === 0 || cacheData?.length > minLength)) { - log(`Used Local Storage: ${storageKey}`); - return cacheData; - } - const start = performance.now(); let buffer = null; @@ -85,4 +80,26 @@ async function query( } } +async function query( + storageKey: string, + apiPath: string, + checkBucket: boolean, + minLength: number, + expiry: number +) { + const cacheData = await getWithExpiry(storageKey); + if (cacheData && (minLength === 0 || cacheData?.length > minLength)) { + log(`Used Local Storage: ${storageKey}`); + return cacheData; + } + + if (!inFlight[storageKey]) { + inFlight[storageKey] = fetchAndStore(storageKey, apiPath, checkBucket, expiry).finally(() => { + delete inFlight[storageKey]; + }); + } + + return inFlight[storageKey]; +} + export default query; diff --git a/frontend/src/pages/match/[match_id].tsx b/frontend/src/pages/match/[match_id].tsx index 258e97ae..a90dbfc9 100644 --- a/frontend/src/pages/match/[match_id].tsx +++ b/frontend/src/pages/match/[match_id].tsx @@ -23,7 +23,7 @@ const InnerPage = () => { useEffect(() => { const fetchMatchData = async () => { - if (!match_id || data) return; + if (!match_id || data?.match?.key == match_id) return; try { const matchData = await getMatch(match_id as string); diff --git a/frontend/src/pagesContent/event/[event_id]/simulation.tsx b/frontend/src/pagesContent/event/[event_id]/simulation.tsx index 9fbd8e36..d12084c9 100644 --- a/frontend/src/pagesContent/event/[event_id]/simulation.tsx +++ b/frontend/src/pagesContent/event/[event_id]/simulation.tsx @@ -137,7 +137,7 @@ const SimulationSection = ({ eventId, data }: { eventId: string; data: EventData rank: i + 1, num: teamEvent.team, team: teamEvent?.team_name, - epa: round(teamEvent?.epa?.total_points?.mean ?? 0, 1), + epa: round(teamEvent?.epa?.breakdown?.total_points ?? 0, 1), rankMean: rankMean[teamEvent.team] ? round(rankMean[teamEvent.team], 2) : "", rank5: rank5[teamEvent.team] ? round(rank5[teamEvent.team], 2) : "", rank50: rank50[teamEvent.team] ? round(rank50[teamEvent.team], 2) : "", @@ -158,7 +158,7 @@ const SimulationSection = ({ eventId, data }: { eventId: string; data: EventData return { num: teamEvent.team, team: teamEvent?.team_name, - epa: round(teamEvent?.epa?.total_points?.mean ?? 0, 1), + epa: round(teamEvent?.epa?.breakdown?.total_points ?? 0, 1), rankMean: rankMean[teamEvent.team] ? round(rankMean[teamEvent.team], 2) : "", RPMean: RPMean[teamEvent.team] ? round(RPMean[teamEvent.team], 2) : "", ...probsObj, diff --git a/frontend/src/pagesContent/event/[event_id]/worker.ts b/frontend/src/pagesContent/event/[event_id]/worker.ts index 3300ebe8..b82e9205 100644 --- a/frontend/src/pagesContent/event/[event_id]/worker.ts +++ b/frontend/src/pagesContent/event/[event_id]/worker.ts @@ -570,7 +570,7 @@ async function _strengthOfSchedule(data: EventData, simCount: number, postEvent: currTeamOpponents.length; const deltaEPA = epaAvg + 2 * avgPartnerEPA - 3 * avgOpponentEPA; - const distrib = Gaussian(0, (epaSd * epaSd * 5) / N); + const distrib = Gaussian(0, (epaSd * epaSd * 5) / N || 1e-9); const epaPercentile = 1 - distrib.cdf(deltaEPA); const overallPercentile = (rankPercentile + rpPercentile + epaPercentile) / 3; diff --git a/frontend/src/pagesContent/match/[match_id]/imageRow.tsx b/frontend/src/pagesContent/match/[match_id]/imageRow.tsx index 01f43d49..dd16134c 100644 --- a/frontend/src/pagesContent/match/[match_id]/imageRow.tsx +++ b/frontend/src/pagesContent/match/[match_id]/imageRow.tsx @@ -1,6 +1,6 @@ "use client"; -import React, { useEffect, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import Image from "next/image"; @@ -10,8 +10,10 @@ import { getMediaUrls } from "../../../utils"; const ImageRow = ({ data }: { data: MatchData }) => { const [media, setMedia] = useState(null); - const reverseBlue = [...data?.match?.alliances?.blue?.team_keys].reverse(); - const teams = data?.match?.alliances?.red?.team_keys?.concat(reverseBlue); + const teams = useMemo(() => { + const reverseBlue = [...data?.match?.alliances?.blue?.team_keys].reverse(); + return data?.match?.alliances?.red?.team_keys?.concat(reverseBlue); + }, [data]); const year = data.year.year; useEffect(() => {