Adjust calendar event results table to deduplicate

This commit is contained in:
Kalle
2022-08-07 15:36:10 +03:00
parent af65d8eb77
commit 8fb4f515ad
6 changed files with 109 additions and 49 deletions

View File

@@ -23,6 +23,7 @@ Calendar
## Other
- [ ] Redirect to event page after submitting results
- [x] date input take in account time zone difference between server and client
- [x] User selector allow passing users from top level
- [x] Constants use CALENDAR_EVENT object

View File

@@ -7,7 +7,8 @@ import type {
Badge,
CalendarEventTag,
CalendarEventBadge,
CalendarEventWinner,
CalendarEventResultTeam,
CalendarEventResultPlayer,
} from "../types";
const createStm = sql.prepare(`
@@ -137,72 +138,108 @@ const updateCalendarEventParticipantsCountStm = sql.prepare(`
where "id" = $eventId
`);
const deleteCalendarEventWinnersByEventIdStm = sql.prepare(`
delete from "CalendarEventWinner"
const deleteCalendarEventResultTeamsByEventIdStm = sql.prepare(`
delete from "CalendarEventResultTeam"
where "eventId" = $eventId
`);
const insertCalendarEventWinnerStm = sql.prepare(`
insert into "CalendarEventWinner" (
const insertCalendarEventResultTeamStm = sql.prepare(`
insert into "CalendarEventResultTeam" (
"eventId",
"teamName",
"placement",
"name",
"placement"
) values (
$eventId,
$name,
$placement
)
returning *
`);
const insertCalendarEventResultPlayerStm = sql.prepare(`
insert into "CalendarEventResultPlayer" (
"teamId",
"userId",
"name"
) values (
$eventId,
$teamName,
$placement,
$teamId,
$userId,
$name
)
`);
export const upsertReportedScores = sql.transaction(
({
eventId,
participantCount,
winners,
results,
}: {
eventId: CalendarEvent["id"];
participantCount: CalendarEvent["participantCount"];
winners: Array<
Pick<CalendarEventWinner, "teamName" | "placement" | "userId" | "name">
>;
results: Array<{
teamName: CalendarEventResultTeam["name"];
placement: CalendarEventResultTeam["placement"];
players: Array<{
userId: CalendarEventResultPlayer["userId"];
name: CalendarEventResultPlayer["name"];
}>;
}>;
}) => {
updateCalendarEventParticipantsCountStm.run({ eventId, participantCount });
deleteCalendarEventWinnersByEventIdStm.run({ eventId });
deleteCalendarEventResultTeamsByEventIdStm.run({ eventId });
for (const winner of winners) {
insertCalendarEventWinnerStm.run({ ...winner, eventId });
for (const { players, ...teamArgs } of results) {
const teamInDb = insertCalendarEventResultTeamStm.get({
eventId,
name: teamArgs.teamName,
placement: teamArgs.placement,
}) as CalendarEventResultTeam;
for (const playerArgs of players) {
insertCalendarEventResultPlayerStm.run({
teamId: teamInDb.id,
userId: playerArgs.userId,
name: playerArgs.name,
});
}
}
}
);
const findWinnersByEventIdStm = sql.prepare(`
select
"teamName",
"placement",
"userId",
"name"
from "CalendarEventWinner"
where "eventId" = $eventId
"CalendarEventResultTeam"."id",
"CalendarEventResultTeam"."name" as "teamName",
"CalendarEventResultTeam"."placement",
"CalendarEventResultPlayer"."userId" as "playerId",
"CalendarEventResultPlayer"."name" as "playerName"
from "CalendarEventResultTeam"
join
"CalendarEventResultPlayer"
on
"CalendarEventResultPlayer"."teamId" = "CalendarEventResultTeam"."id"
where "CalendarEventResultTeam"."eventId" = $eventId
order by "placement" asc
`);
export function findWinnersByEventId(eventId: CalendarEvent["id"]) {
const rows = findWinnersByEventIdStm.all({ eventId }) as Array<
Pick<CalendarEventWinner, "teamName" | "placement" | "userId" | "name">
>;
const rows = findWinnersByEventIdStm.all({ eventId }) as Array<{
id: CalendarEventResultTeam["id"];
teamName: CalendarEventResultTeam["name"];
placement: CalendarEventResultTeam["placement"];
playerId: CalendarEventResultPlayer["userId"];
playerName: CalendarEventResultPlayer["name"];
}>;
const result: Array<{
teamName: CalendarEventWinner["teamName"];
placement: CalendarEventWinner["placement"];
teamName: CalendarEventResultTeam["name"];
placement: CalendarEventResultTeam["placement"];
players: Array<string | { id: number }>;
}> = [];
for (const row of rows) {
const team = result.find((team) => team.teamName === row.teamName);
const player = row.name ?? { id: row.userId! };
const player = row.playerName ?? { id: row.playerId! };
if (team) {
team.players.push(player);

View File

@@ -19,7 +19,7 @@ const NZAP_TEST_DISCORD_ID = "455039198672453645";
const NZAP_TEST_AVATAR = "f809176af93132c3db5f0a5019e96339"; // https://cdn.discordapp.com/avatars/455039198672453645/f809176af93132c3db5f0a5019e96339.webp?size=160
const NZAP_TEST_ID = 2;
const AMOUNT_OF_CALENDAR_EVENTS = 100;
const AMOUNT_OF_CALENDAR_EVENTS = 200;
const basicSeeds = [
adminUser,
@@ -48,7 +48,8 @@ export function seed() {
function wipeDB() {
const tablesToDelete = [
"CalendarEventDate",
"CalendarEventWinner",
"CalendarEventResultPlayer",
"CalendarEventResultTeam",
"CalendarEventBadge",
"CalendarEvent",
"User",
@@ -315,11 +316,15 @@ function patrons() {
}
}
function calendarEvents() {
const userIds = sql
function userIdsInRandomOrder() {
return sql
.prepare(`select "id" from "User" order by random()`)
.all()
.map((u) => u.id);
}
function calendarEvents() {
const userIds = userIdsInRandomOrder();
for (let id = 1; id <= AMOUNT_OF_CALENDAR_EVENTS; id++) {
const tags = shuffle(Object.keys(allTags)).filter((tag) => tag !== "BADGE");
@@ -369,7 +374,8 @@ function calendarEvents() {
});
const twoDayEvent = Math.random() > 0.9;
const startTime = faker.date.soon(42);
const startTime =
id % 2 === 0 ? faker.date.soon(42) : faker.date.recent(42);
startTime.setMinutes(0, 0, 0);
sql

View File

@@ -100,10 +100,15 @@ export interface CalendarEventDate {
startTime: number;
}
export interface CalendarEventWinner {
export interface CalendarEventResultTeam {
id: number;
eventId: number;
teamName: string;
name: string;
placement: number;
}
export interface CalendarEventResultPlayer {
teamId: number;
userId: number | null;
name: string | null;
}

View File

@@ -104,14 +104,14 @@ export const action: ActionFunction = async ({ request, params }) => {
db.calendarEvents.upsertReportedScores({
eventId: parsedParams.id,
participantCount: parsedInput.data.participantCount,
winners: parsedInput.data.team.flatMap((t) =>
t.players.map((player) => ({
teamName: t.teamName,
placement: t.placement,
userId: typeof player !== "string" ? player.id : null,
name: typeof player === "string" ? player : null,
}))
),
results: parsedInput.data.team.map((t) => ({
teamName: t.teamName,
placement: t.placement,
players: t.players.map((p) => ({
userId: typeof p === "string" ? null : p.id,
name: typeof p === "string" ? p : null,
})),
})),
});
return null;

View File

@@ -29,14 +29,24 @@ module.exports.up = function (db) {
db.prepare(
`
create table "CalendarEventWinner" (
create table "CalendarEventResultTeam" (
"id" integer primary key,
"eventId" integer not null,
"teamName" text not null,
"name" text not null,
"placement" integer not null,
foreign key ("eventId") references "CalendarEvent"("id") on delete cascade
) strict
`
).run();
db.prepare(
`
create table "CalendarEventResultPlayer" (
"teamId" integer not null,
"userId" integer,
"name" text,
foreign key ("eventId") references "CalendarEvent"("id") on delete cascade,
foreign key ("userId") references "User"("id") on delete cascade
foreign key ("teamId") references "CalendarEventResultTeam"("id") on delete cascade,
foreign key ("userId") references "User"("id") on delete restrict
) strict
`
).run();
@@ -57,7 +67,8 @@ module.exports.up = function (db) {
module.exports.down = function (db) {
for (const table of [
"CalendarEventDate",
"CalendarEventWinner",
"CalendarEventResultPlayer",
"CalendarEventResultTeam",
"CalendarEventBadge",
"CalendarEvent",
]) {