mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-28 14:18:04 -05:00
Migrate setHistoryByTeamId to Kysely
This commit is contained in:
@@ -1,8 +1,18 @@
|
|||||||
import { sql } from "kysely";
|
import { sql } from "kysely";
|
||||||
import { jsonArrayFrom } from "kysely/helpers/sqlite";
|
import { jsonArrayFrom } from "kysely/helpers/sqlite";
|
||||||
import { db } from "~/db/sql";
|
import { db } from "~/db/sql";
|
||||||
|
import { TournamentMatchStatus } from "~/db/tables";
|
||||||
import type { Unwrapped } from "~/utils/types";
|
import type { Unwrapped } from "~/utils/types";
|
||||||
|
|
||||||
|
const opponentOneId = sql<number>`"TournamentMatch"."opponentOne" ->> '$.id'`;
|
||||||
|
const opponentTwoId = sql<number>`"TournamentMatch"."opponentTwo" ->> '$.id'`;
|
||||||
|
const opponentOneScore = sql<
|
||||||
|
number | null
|
||||||
|
>`"TournamentMatch"."opponentOne" ->> '$.score'`;
|
||||||
|
const opponentTwoScore = sql<
|
||||||
|
number | null
|
||||||
|
>`"TournamentMatch"."opponentTwo" ->> '$.score'`;
|
||||||
|
|
||||||
export type FindMatchById = NonNullable<Unwrapped<typeof findMatchById>>;
|
export type FindMatchById = NonNullable<Unwrapped<typeof findMatchById>>;
|
||||||
export async function findMatchById(id: number) {
|
export async function findMatchById(id: number) {
|
||||||
const row = await db
|
const row = await db
|
||||||
@@ -52,12 +62,12 @@ export async function findMatchById(id: number) {
|
|||||||
innerEb(
|
innerEb(
|
||||||
"TournamentTeamMember.tournamentTeamId",
|
"TournamentTeamMember.tournamentTeamId",
|
||||||
"=",
|
"=",
|
||||||
sql<number>`"TournamentMatch"."opponentOne" ->> '$.id'`,
|
opponentOneId,
|
||||||
),
|
),
|
||||||
innerEb(
|
innerEb(
|
||||||
"TournamentTeamMember.tournamentTeamId",
|
"TournamentTeamMember.tournamentTeamId",
|
||||||
"=",
|
"=",
|
||||||
sql<number>`"TournamentMatch"."opponentTwo" ->> '$.id'`,
|
opponentTwoId,
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
@@ -112,3 +122,109 @@ export async function userParticipationByTournamentId(tournamentId: number) {
|
|||||||
.groupBy("playerMatches.userId")
|
.groupBy("playerMatches.userId")
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type FindByTournamentTeamIdItem = Unwrapped<
|
||||||
|
typeof findByTournamentTeamId
|
||||||
|
>;
|
||||||
|
export function findByTournamentTeamId(tournamentTeamId: number) {
|
||||||
|
return db
|
||||||
|
.selectFrom("TournamentMatch")
|
||||||
|
.innerJoin(
|
||||||
|
"TournamentRound",
|
||||||
|
"TournamentRound.id",
|
||||||
|
"TournamentMatch.roundId",
|
||||||
|
)
|
||||||
|
.innerJoin(
|
||||||
|
"TournamentGroup",
|
||||||
|
"TournamentGroup.id",
|
||||||
|
"TournamentMatch.groupId",
|
||||||
|
)
|
||||||
|
.innerJoin("TournamentTeam as otherTeam", (join) =>
|
||||||
|
join.on((eb) =>
|
||||||
|
eb.or([
|
||||||
|
eb.and([
|
||||||
|
eb(opponentOneId, "!=", tournamentTeamId),
|
||||||
|
eb(opponentOneId, "=", eb.ref("otherTeam.id")),
|
||||||
|
]),
|
||||||
|
eb.and([
|
||||||
|
eb(opponentTwoId, "!=", tournamentTeamId),
|
||||||
|
eb(opponentTwoId, "=", eb.ref("otherTeam.id")),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.select(({ eb }) => [
|
||||||
|
"TournamentMatch.id as tournamentMatchId",
|
||||||
|
opponentOneScore.as("opponentOneScore"),
|
||||||
|
opponentTwoScore.as("opponentTwoScore"),
|
||||||
|
"otherTeam.name as otherTeamName",
|
||||||
|
"otherTeam.id as otherTeamId",
|
||||||
|
"TournamentRound.number as roundNumber",
|
||||||
|
"TournamentRound.stageId",
|
||||||
|
"TournamentGroup.number as groupNumber",
|
||||||
|
jsonArrayFrom(
|
||||||
|
eb
|
||||||
|
.selectFrom("TournamentMatchGameResult")
|
||||||
|
.select([
|
||||||
|
"TournamentMatchGameResult.mode",
|
||||||
|
"TournamentMatchGameResult.stageId",
|
||||||
|
"TournamentMatchGameResult.source",
|
||||||
|
sql<number>`"TournamentMatchGameResult"."winnerTeamId" = ${tournamentTeamId}`.as(
|
||||||
|
"wasWinner",
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.whereRef(
|
||||||
|
"TournamentMatchGameResult.matchId",
|
||||||
|
"=",
|
||||||
|
"TournamentMatch.id",
|
||||||
|
)
|
||||||
|
.orderBy("TournamentMatchGameResult.number", "asc"),
|
||||||
|
).as("matches"),
|
||||||
|
jsonArrayFrom(
|
||||||
|
eb
|
||||||
|
.selectFrom("User")
|
||||||
|
.innerJoin(
|
||||||
|
"TournamentMatchGameResultParticipant",
|
||||||
|
"TournamentMatchGameResultParticipant.userId",
|
||||||
|
"User.id",
|
||||||
|
)
|
||||||
|
.innerJoin(
|
||||||
|
"TournamentMatchGameResult",
|
||||||
|
"TournamentMatchGameResult.id",
|
||||||
|
"TournamentMatchGameResultParticipant.matchGameResultId",
|
||||||
|
)
|
||||||
|
.innerJoin("TournamentTeamMember", (join) =>
|
||||||
|
join
|
||||||
|
.onRef("TournamentTeamMember.userId", "=", "User.id")
|
||||||
|
.onRef(
|
||||||
|
"TournamentTeamMember.tournamentTeamId",
|
||||||
|
"=",
|
||||||
|
"otherTeam.id",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.select([
|
||||||
|
"User.id",
|
||||||
|
"User.username",
|
||||||
|
"User.discordAvatar",
|
||||||
|
"User.discordId",
|
||||||
|
"User.customUrl",
|
||||||
|
])
|
||||||
|
.whereRef(
|
||||||
|
"TournamentMatchGameResult.matchId",
|
||||||
|
"=",
|
||||||
|
"TournamentMatch.id",
|
||||||
|
)
|
||||||
|
.distinct(),
|
||||||
|
).as("players"),
|
||||||
|
])
|
||||||
|
.where((eb) =>
|
||||||
|
eb.or([
|
||||||
|
eb(opponentOneId, "=", tournamentTeamId),
|
||||||
|
eb(opponentTwoId, "=", tournamentTeamId),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
.where("TournamentMatch.status", ">=", TournamentMatchStatus.Completed)
|
||||||
|
.orderBy("TournamentGroup.number", "asc")
|
||||||
|
.orderBy("TournamentRound.number", "asc")
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
import type { Tables } from "~/db/tables";
|
import type { Tables } from "~/db/tables";
|
||||||
|
import type { FindByTournamentTeamIdItem } from "~/features/tournament-bracket/TournamentMatchRepository.server";
|
||||||
import type { ModeShort, StageId } from "~/modules/in-game-lists/types";
|
import type { ModeShort, StageId } from "~/modules/in-game-lists/types";
|
||||||
import { sourceTypes } from "~/modules/tournament-map-list-generator/constants";
|
import { sourceTypes } from "~/modules/tournament-map-list-generator/constants";
|
||||||
import type { TournamentMaplistSource } from "~/modules/tournament-map-list-generator/types";
|
import type { TournamentMaplistSource } from "~/modules/tournament-map-list-generator/types";
|
||||||
import invariant from "~/utils/invariant";
|
import invariant from "~/utils/invariant";
|
||||||
import { logger } from "~/utils/logger";
|
import { logger } from "~/utils/logger";
|
||||||
import { findRoundsByTournamentId } from "../queries/findRoundsByTournamentId.server";
|
import type { findRoundsByTournamentId } from "../queries/findRoundsByTournamentId.server";
|
||||||
import {
|
|
||||||
type SetHistoryByTeamIdItem,
|
|
||||||
setHistoryByTeamId,
|
|
||||||
} from "../queries/setHistoryByTeamId.server";
|
|
||||||
|
|
||||||
export interface PlayedSet {
|
export interface PlayedSet {
|
||||||
tournamentMatchId: number;
|
tournamentMatchId: number;
|
||||||
@@ -78,15 +75,12 @@ export function winCounts(sets: PlayedSet[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function tournamentTeamSets({
|
export function tournamentTeamSets({
|
||||||
tournamentTeamId,
|
sets,
|
||||||
tournamentId,
|
allRounds,
|
||||||
}: {
|
}: {
|
||||||
tournamentTeamId: number;
|
sets: FindByTournamentTeamIdItem[];
|
||||||
tournamentId: number;
|
allRounds: ReturnType<typeof findRoundsByTournamentId>;
|
||||||
}): PlayedSet[] {
|
}): PlayedSet[] {
|
||||||
const sets = setHistoryByTeamId(tournamentTeamId);
|
|
||||||
const allRounds = findRoundsByTournamentId(tournamentId);
|
|
||||||
|
|
||||||
return sets.map((set) => {
|
return sets.map((set) => {
|
||||||
const round =
|
const round =
|
||||||
allRounds.find((round) => round.stageId === set.stageId) ?? allRounds[0];
|
allRounds.find((round) => round.stageId === set.stageId) ?? allRounds[0];
|
||||||
@@ -157,7 +151,7 @@ function parseTournamentMaplistSource(source: string): TournamentMaplistSource {
|
|||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
function flipScoreIfNeeded(set: SetHistoryByTeamIdItem): [number, number] {
|
function flipScoreIfNeeded(set: FindByTournamentTeamIdItem): [number, number] {
|
||||||
const score: [number, number] = [
|
const score: [number, number] = [
|
||||||
set.opponentOneScore ?? 0,
|
set.opponentOneScore ?? 0,
|
||||||
set.opponentTwoScore ?? 0,
|
set.opponentTwoScore ?? 0,
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import type { LoaderFunctionArgs } from "react-router";
|
import type { LoaderFunctionArgs } from "react-router";
|
||||||
import { tournamentDataCached } from "~/features/tournament-bracket/core/Tournament.server";
|
import { tournamentDataCached } from "~/features/tournament-bracket/core/Tournament.server";
|
||||||
|
import * as TournamentMatchRepository from "~/features/tournament-bracket/TournamentMatchRepository.server";
|
||||||
import { tournamentTeamPageParamsSchema } from "~/features/tournament-bracket/tournament-bracket-schemas.server";
|
import { tournamentTeamPageParamsSchema } from "~/features/tournament-bracket/tournament-bracket-schemas.server";
|
||||||
import { parseParams } from "~/utils/remix.server";
|
import { parseParams } from "~/utils/remix.server";
|
||||||
import { tournamentTeamSets, winCounts } from "../core/sets.server";
|
import { tournamentTeamSets, winCounts } from "../core/sets.server";
|
||||||
|
import { findRoundsByTournamentId } from "../queries/findRoundsByTournamentId.server";
|
||||||
|
|
||||||
export const loader = async ({ params }: LoaderFunctionArgs) => {
|
export const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||||
const { id: tournamentId, tid: tournamentTeamId } = parseParams({
|
const { id: tournamentId, tid: tournamentTeamId } = parseParams({
|
||||||
@@ -15,7 +17,11 @@ export const loader = async ({ params }: LoaderFunctionArgs) => {
|
|||||||
throw new Response(null, { status: 404 });
|
throw new Response(null, { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const sets = tournamentTeamSets({ tournamentTeamId, tournamentId });
|
const setHistory =
|
||||||
|
await TournamentMatchRepository.findByTournamentTeamId(tournamentTeamId);
|
||||||
|
const allRounds = findRoundsByTournamentId(tournamentId);
|
||||||
|
|
||||||
|
const sets = tournamentTeamSets({ sets: setHistory, allRounds });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tournamentTeamId,
|
tournamentTeamId,
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
import * as R from "remeda";
|
|
||||||
import { sql } from "~/db/sql";
|
|
||||||
import type { Tables } from "~/db/tables";
|
|
||||||
import type { ModeShort, StageId } from "~/modules/in-game-lists/types";
|
|
||||||
import { parseDBArray } from "~/utils/sql";
|
|
||||||
|
|
||||||
const stm = sql.prepare(/* sql */ `
|
|
||||||
with "q1" as (
|
|
||||||
select
|
|
||||||
"m"."id" as "tournamentMatchId",
|
|
||||||
"m"."opponentOne" ->> '$.score' as "opponentOneScore",
|
|
||||||
"m"."opponentTwo" ->> '$.score' as "opponentTwoScore",
|
|
||||||
"otherTeam"."name" as "otherTeamName",
|
|
||||||
"otherTeam"."id" as "otherTeamId",
|
|
||||||
"round"."number" as "roundNumber",
|
|
||||||
"round"."stageId" as "stageId",
|
|
||||||
"group"."number" as "groupNumber",
|
|
||||||
json_group_array(
|
|
||||||
json_object(
|
|
||||||
'mode',
|
|
||||||
"r"."mode",
|
|
||||||
'stageId',
|
|
||||||
"r"."stageId",
|
|
||||||
'wasWinner',
|
|
||||||
"r"."winnerTeamId" == @tournamentTeamId,
|
|
||||||
'source',
|
|
||||||
"r"."source"
|
|
||||||
)
|
|
||||||
) as "matches"
|
|
||||||
from "TournamentMatch" as "m"
|
|
||||||
left join "TournamentMatchGameResult" as "r" on "m"."id" = "r"."matchId"
|
|
||||||
left join "TournamentRound" as "round" on "m"."roundId" = "round"."id"
|
|
||||||
left join "TournamentGroup" as "group" on "m"."groupId" = "group"."id"
|
|
||||||
left join "TournamentTeam" as "otherTeam" on
|
|
||||||
(
|
|
||||||
"m"."opponentOne" ->> '$.id' != @tournamentTeamId
|
|
||||||
and
|
|
||||||
"m"."opponentOne" ->> '$.id' = "otherTeam"."id"
|
|
||||||
) or
|
|
||||||
(
|
|
||||||
"m"."opponentTwo" ->> '$.id' != @tournamentTeamId
|
|
||||||
and
|
|
||||||
"m"."opponentTwo" ->> '$.id' = "otherTeam"."id"
|
|
||||||
)
|
|
||||||
where
|
|
||||||
(
|
|
||||||
"m"."opponentOne" ->> '$.id' = @tournamentTeamId
|
|
||||||
or
|
|
||||||
"m"."opponentTwo" ->> '$.id' = @tournamentTeamId
|
|
||||||
)
|
|
||||||
and "m"."status" >= 4
|
|
||||||
group by "m"."id"
|
|
||||||
order by "groupNumber" asc, "roundNumber" asc, "r"."number" asc
|
|
||||||
)
|
|
||||||
select
|
|
||||||
"q1".*,
|
|
||||||
json_group_array(
|
|
||||||
json_object(
|
|
||||||
'id',
|
|
||||||
"u"."id",
|
|
||||||
'username',
|
|
||||||
"u"."username",
|
|
||||||
'discordAvatar',
|
|
||||||
"u"."discordAvatar",
|
|
||||||
'discordId',
|
|
||||||
"u"."discordId",
|
|
||||||
'customUrl',
|
|
||||||
"u"."customUrl"
|
|
||||||
)
|
|
||||||
) as "players"
|
|
||||||
from "q1"
|
|
||||||
left join "TournamentMatchGameResult" as "r" on "q1"."tournamentMatchId" = "r"."matchId"
|
|
||||||
left join "TournamentMatchGameResultParticipant" as "p" on "r"."id" = "p"."matchGameResultId"
|
|
||||||
left join "User" as "u" on "p"."userId" = "u"."id"
|
|
||||||
-- filters out own team results
|
|
||||||
inner join "TournamentTeamMember" as "m" on "p"."userId" = "m"."userId"
|
|
||||||
and "m"."tournamentTeamId" == "q1"."otherTeamId"
|
|
||||||
group by "q1"."tournamentMatchId"
|
|
||||||
`);
|
|
||||||
|
|
||||||
export interface SetHistoryByTeamIdItem {
|
|
||||||
tournamentMatchId: number;
|
|
||||||
opponentOneScore: number | null;
|
|
||||||
opponentTwoScore: number | null;
|
|
||||||
otherTeamName: string;
|
|
||||||
otherTeamId: number;
|
|
||||||
roundNumber: number;
|
|
||||||
stageId: number;
|
|
||||||
groupNumber: number;
|
|
||||||
matches: {
|
|
||||||
stageId: StageId;
|
|
||||||
source: Tables["TournamentMatchGameResult"]["source"];
|
|
||||||
mode: ModeShort;
|
|
||||||
wasWinner: number;
|
|
||||||
}[];
|
|
||||||
players: Array<
|
|
||||||
Pick<
|
|
||||||
Tables["User"],
|
|
||||||
"id" | "username" | "discordAvatar" | "discordId" | "customUrl"
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setHistoryByTeamId(
|
|
||||||
tournamentTeamId: number,
|
|
||||||
): Array<SetHistoryByTeamIdItem> {
|
|
||||||
const rows = stm.all({ tournamentTeamId }) as any[];
|
|
||||||
|
|
||||||
return rows.map((row) => {
|
|
||||||
return {
|
|
||||||
...row,
|
|
||||||
matches: parseDBArray(row.matches),
|
|
||||||
// TODO: there is probably a way to do this in SQL
|
|
||||||
players: R.uniqueBy(parseDBArray(row.players), (u) => u.id),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user