mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-03-21 18:04:39 -05:00
Fix Swiss generate match ups internal server error by introducing neverthrow
This commit is contained in:
parent
fa60d0d03f
commit
b2ff16426d
|
|
@ -8,6 +8,7 @@ import * as TournamentRepository from "~/features/tournament/TournamentRepositor
|
|||
import * as Progression from "~/features/tournament-bracket/core/Progression";
|
||||
import invariant from "~/utils/invariant";
|
||||
import {
|
||||
errorToastIfErr,
|
||||
errorToastIfFalsy,
|
||||
parseParams,
|
||||
parseRequestPayload,
|
||||
|
|
@ -180,17 +181,15 @@ export const action: ActionFunction = async ({ params, request }) => {
|
|||
|
||||
const bracket = tournament.bracketByIdx(data.bracketIdx);
|
||||
errorToastIfFalsy(bracket, "Bracket not found");
|
||||
errorToastIfFalsy(
|
||||
bracket.type === "swiss",
|
||||
"Can't advance non-swiss bracket",
|
||||
);
|
||||
|
||||
const matches = Swiss.generateMatchUps({
|
||||
bracket,
|
||||
groupId: data.groupId,
|
||||
});
|
||||
|
||||
await TournamentRepository.insertSwissMatches(matches);
|
||||
errorToastIfErr(matches);
|
||||
|
||||
await TournamentRepository.insertSwissMatches(matches.value);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ describe("Swiss", () => {
|
|||
const matches = Swiss.generateMatchUps({
|
||||
bracket,
|
||||
groupId: 4443,
|
||||
});
|
||||
})._unsafeUnwrap();
|
||||
|
||||
it("finds new opponents for each team in the last round", () => {
|
||||
for (const match of matches) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// separate from brackets-manager as this wasn't part of the original brackets-manager library
|
||||
|
||||
import blossom from "edmonds-blossom-fixed";
|
||||
import { err, ok } from "neverthrow";
|
||||
import * as R from "remeda";
|
||||
import type { TournamentRepositoryInsertableMatch } from "~/features/tournament/TournamentRepository.server";
|
||||
import { TOURNAMENT } from "~/features/tournament/tournament-constants";
|
||||
|
|
@ -173,18 +174,19 @@ export function generateMatchUps({
|
|||
}: {
|
||||
bracket: Bracket;
|
||||
groupId: number;
|
||||
}): Array<TournamentRepositoryInsertableMatch> {
|
||||
}) {
|
||||
// lets consider only this groups matches
|
||||
// in the case that there are more than one group
|
||||
const groupsMatches = bracket.data.match.filter(
|
||||
(m) => m.group_id === groupId,
|
||||
);
|
||||
|
||||
invariant(groupsMatches.length > 0, "No matches found for group");
|
||||
if (groupsMatches.length === 0) return err("No matches found for group");
|
||||
if (bracket.type !== "swiss") return err("Bracket is not Swiss type");
|
||||
|
||||
// new matches can't be generated till old are over
|
||||
if (!everyMatchOver(groupsMatches)) {
|
||||
throw new Error("Not all matches are over");
|
||||
return err("Not all matches are over");
|
||||
}
|
||||
|
||||
const groupsTeams = groupsMatches
|
||||
|
|
@ -247,7 +249,7 @@ export function generateMatchUps({
|
|||
}),
|
||||
);
|
||||
|
||||
return result;
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
interface SwissPairingTeam {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
import type { Params, UIMatch } from "@remix-run/react";
|
||||
import type { Namespace, TFunction } from "i18next";
|
||||
import { nanoid } from "nanoid";
|
||||
import type { Ok, Result } from "neverthrow";
|
||||
import type { z } from "zod/v4";
|
||||
import type { navItems } from "~/components/layout/nav-items";
|
||||
import { s3UploadHandler } from "~/features/img-upload";
|
||||
|
|
@ -208,6 +209,19 @@ export function errorToastIfFalsy(
|
|||
throw errorToastRedirect(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* To be used in loader or action function. Asserts that the provided `Result` value is an `Ok` variant of the `neverthrow` library.
|
||||
*
|
||||
* If the value is an `Err`, shows an error toast to the user with the error message. The function will stop execution by throwing a redirect meaning it is safe to operate on the value after this function call.
|
||||
*/
|
||||
export function errorToastIfErr<T, E extends string>(
|
||||
value: Result<T, E>,
|
||||
): asserts value is Ok<T, never> {
|
||||
if (value.isErr()) {
|
||||
throw errorToastRedirect(value.error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Throws a redirect triggering an error toast with given message. */
|
||||
export function errorToast(message: string) {
|
||||
throw errorToastRedirect(message);
|
||||
|
|
|
|||
14
package-lock.json
generated
14
package-lock.json
generated
|
|
@ -37,6 +37,7 @@
|
|||
"lru-cache": "^11.1.0",
|
||||
"markdown-to-jsx": "^7.7.6",
|
||||
"nanoid": "^5.1.5",
|
||||
"neverthrow": "^8.2.0",
|
||||
"node-cron": "3.0.3",
|
||||
"nprogress": "^0.2.0",
|
||||
"openskill": "^4.1.0",
|
||||
|
|
@ -5645,7 +5646,6 @@
|
|||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
|
|
@ -13125,6 +13125,18 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/neverthrow": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/neverthrow/-/neverthrow-8.2.0.tgz",
|
||||
"integrity": "sha512-kOCT/1MCPAxY5iUV3wytNFUMUolzuwd/VF/1KCx7kf6CutrOsTie+84zTGTpgQycjvfLdBBdvBvFLqFD2c0wkQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-linux-x64-gnu": "^4.24.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.74.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz",
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
"lru-cache": "^11.1.0",
|
||||
"markdown-to-jsx": "^7.7.6",
|
||||
"nanoid": "^5.1.5",
|
||||
"neverthrow": "^8.2.0",
|
||||
"node-cron": "3.0.3",
|
||||
"nprogress": "^0.2.0",
|
||||
"openskill": "^4.1.0",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user