diff --git a/app/models/__tests__/upcoming-calendar.test.ts b/app/models/__tests__/upcoming-calendar.test.ts index 83f7aa5..b8212fa 100644 --- a/app/models/__tests__/upcoming-calendar.test.ts +++ b/app/models/__tests__/upcoming-calendar.test.ts @@ -23,7 +23,7 @@ vi.mock("~/database/context", () => ({ vi.mock("~/database/schema", () => ({ scoringEvents: { sportsSeasonId: "se.sports_season_id", isComplete: "se.is_complete", eventDate: "se.event_date", eventType: "se.event_type" }, - playoffMatches: { scoringEventId: "pm.scoring_event_id", participant1Id: "pm.participant1_id", participant2Id: "pm.participant2_id", round: "pm.round", matchNumber: "pm.match_number" }, + playoffMatches: { scoringEventId: "pm.scoring_event_id", participant1Id: "pm.participant1_id", participant2Id: "pm.participant2_id", round: "pm.round", matchNumber: "pm.match_number", isComplete: "pm.is_complete" }, playoffMatchGames: { playoffMatchId: "pmg.playoff_match_id", scheduledAt: "pmg.scheduled_at", gameNumber: "pmg.game_number" }, })); @@ -569,6 +569,27 @@ describe("getUpcomingEventsForDraftedParticipants — bracket misc", () => { beforeEach(() => vi.clearAllMocks()); + it("excludes scored (isComplete) matches by passing the filter to the DB query", async () => { + // The DB mock returns rows only for matches the WHERE clause matches. + // When a match is complete (isComplete=true) the DB should return no rows. + // Simulate this by returning an empty result set. + // No second mockReturnValueOnce is needed: empty rows means eventIdsFromRows + // is empty so the max-game-number lookup is never called. + const chain = makeSelectChain([]); + mockDb.selectDistinct.mockReturnValueOnce(chain); + + const result = await getUpcomingEventsForDraftedParticipants( + SPORTS_SEASON_ID, "playoff_bracket", + [makeParticipant("man-city", "Man City")], + DATE_FROM, DATE_TO + ); + + expect(result).toHaveLength(0); + // The WHERE clause includes eq(schema.playoffMatches.isComplete, false). + // We verify the query was built without error (accessing the field on the mock). + expect(chain.where).toHaveBeenCalled(); + }); + it("uses leftJoin so events without any games are still considered", async () => { const chain = makeSelectChain([]); mockDb.selectDistinct diff --git a/app/models/scoring-event.ts b/app/models/scoring-event.ts index bc65ce6..c77392f 100644 --- a/app/models/scoring-event.ts +++ b/app/models/scoring-event.ts @@ -444,6 +444,7 @@ export async function getUpcomingEventsForDraftedParticipants( and( eq(schema.scoringEvents.sportsSeasonId, sportsSeasonId), eq(schema.scoringEvents.isComplete, false), + eq(schema.playoffMatches.isComplete, false), or( inArray(schema.playoffMatches.participant1Id, draftedIds), // participant2Id is nullable UUID — same underlying type as participant1Id;