mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-01 00:24:13 -05:00
SQL solution migration to Kysely + getting rid of routes folder (#1530)
* Kysely initial * Badges initial * Badge routes migrated * Badges migrated * Calendar work * Fix one type problem * Calendar work * findResultsByUserId work * Calendar reworking finished * PlusSuggestions work * Migrated suggestions * Builds progress * Migrated builds * Admin migrated * Migrate articles * User search * Faster getUser * Selectable/insertable as global * Refresh prod db script + patronTier index * identifierToUserId * updateProfile * findByIdentifier * More indexes * User upsert * upsertLite * findAllPlusMembers * updateResultHighlights * updateMany * User finished migration * Fix types * Fix PlusVotingResult typing * PlusVotingRepository WIP * Migrated resultsByMonthYear * Migrated plusVotes (done with db. related migrations) * Plus code to features folder * Fix TODOs * Export * Fix range * Migrate some user pages * Move rest user routes * Move /play * Map list generator * Front page * Move map list generation logic * Move plus voting logic * Info * API * Adjust TODOs * theme * Auth * Remove TODO
This commit is contained in:
parent
e166ae4e0f
commit
c8ea75ebb6
|
|
@ -15,7 +15,10 @@ module.exports = {
|
|||
"plugin:react-hooks/recommended",
|
||||
],
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{ argsIgnorePattern: "^_", ignoreRestSiblings: true },
|
||||
],
|
||||
"no-constant-condition": ["error", { checkLoops: false }],
|
||||
"no-console": ["warn", { allow: ["warn", "error"] }],
|
||||
"no-warning-comments": ["warn", { terms: ["xxx"] }],
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import type { Badge as BadgeDBType } from "~/db/types";
|
||||
import { badgeUrl } from "~/utils/urls";
|
||||
import { Image } from "./Image";
|
||||
|
||||
|
|
@ -8,7 +7,7 @@ export function Badge({
|
|||
isAnimated,
|
||||
size,
|
||||
}: {
|
||||
badge: Pick<BadgeDBType, "displayName" | "code" | "hue">;
|
||||
badge: { displayName: string; hue?: number | null; code: string };
|
||||
onClick?: () => void;
|
||||
isAnimated: boolean;
|
||||
size: number;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import type {
|
|||
UserWithPlusTier,
|
||||
} from "~/db/types";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { useUser } from "~/modules/auth";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import type {
|
||||
Ability as AbilityType,
|
||||
ModeShort,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { isRouteErrorResponse, useRouteError } from "@remix-run/react";
|
||||
import { Button } from "~/components/Button";
|
||||
import { useUser } from "~/modules/auth";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import {
|
||||
ERROR_GIRL_IMAGE_PATH,
|
||||
LOG_IN_URL,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { type AxisOptions, Chart as ReactChart } from "react-charts";
|
|||
import type { TooltipRendererProps } from "react-charts/types/components/TooltipRenderer";
|
||||
import { useTranslation } from "~/hooks/useTranslation";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { Theme, useTheme } from "~/modules/theme";
|
||||
import { Theme, useTheme } from "~/features/theme/core/provider";
|
||||
|
||||
export default function Chart({
|
||||
options,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import {
|
|||
nonDamagingSpecialWeaponIds,
|
||||
specialWeaponIds,
|
||||
} from "~/modules/in-game-lists/weapon-ids";
|
||||
import { type SerializedMapPoolEvent } from "~/routes/calendar/map-pool-events";
|
||||
import { type SerializedMapPoolEvent } from "~/features/calendar/routes/map-pool-events";
|
||||
import type { Unpacked } from "~/utils/types";
|
||||
import {
|
||||
gearImageUrl,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useCatch, useLocation } from "@remix-run/react";
|
|||
import clsx from "clsx";
|
||||
import type * as React from "react";
|
||||
import { useMatches } from "react-router";
|
||||
import { useUser } from "~/modules/auth";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import type { RootLoaderData } from "~/root";
|
||||
import { SideNav } from "app/components/layout/SideNav";
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
type StageId,
|
||||
} from "~/modules/in-game-lists";
|
||||
import { modes, stageIds } from "~/modules/in-game-lists";
|
||||
import { MapPool } from "~/modules/map-pool-serializer";
|
||||
import { MapPool } from "~/features/map-list-generator/core/map-pool";
|
||||
import { modeImageUrl, stageImageUrl } from "~/utils/urls";
|
||||
import { Button } from "~/components/Button";
|
||||
import { split, startsWith } from "~/utils/strings";
|
||||
|
|
@ -15,7 +15,7 @@ import { CrossIcon } from "./icons/Cross";
|
|||
import { ArrowLongLeftIcon } from "./icons/ArrowLongLeft";
|
||||
import * as React from "react";
|
||||
import type { CalendarEvent } from "~/db/types";
|
||||
import type { SerializedMapPoolEvent } from "~/routes/calendar/map-pool-events";
|
||||
import type { SerializedMapPoolEvent } from "~/features/calendar/routes/map-pool-events";
|
||||
import { assertType } from "~/utils/types";
|
||||
import { MapPoolEventsCombobox } from "./Combobox";
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { useFetcher } from "@remix-run/react";
|
|||
import clsx from "clsx";
|
||||
import * as React from "react";
|
||||
import { useDebounce } from "react-use";
|
||||
import type { UserSearchLoaderData } from "~/routes/u";
|
||||
import type { UserSearchLoaderData } from "~/features/user-search/routes/u";
|
||||
import { Avatar } from "./Avatar";
|
||||
import { useTranslation } from "~/hooks/useTranslation";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useTranslation } from "~/hooks/useTranslation";
|
||||
import { Theme, useTheme } from "~/modules/theme";
|
||||
import { MoonIcon } from "../icons/Moon";
|
||||
import { SunIcon } from "../icons/Sun";
|
||||
import { SunAndMoonIcon } from "../icons/SunAndMoon";
|
||||
import { Theme, useTheme } from "~/features/theme/core/provider";
|
||||
|
||||
const ThemeIcons = {
|
||||
[Theme.LIGHT]: SunIcon,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { useTranslation } from "~/hooks/useTranslation";
|
||||
import { Theme, useTheme } from "~/modules/theme";
|
||||
import { Button } from "../Button";
|
||||
import { MoonIcon } from "../icons/Moon";
|
||||
import { SunIcon } from "../icons/Sun";
|
||||
import { SunAndMoonIcon } from "../icons/SunAndMoon";
|
||||
import { Popover } from "../Popover";
|
||||
import { SelectedThemeIcon } from "./SelectedThemeIcon";
|
||||
import { Theme, useTheme } from "~/features/theme/core/provider";
|
||||
|
||||
const ThemeIcons = {
|
||||
[Theme.LIGHT]: SunIcon,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Link } from "@remix-run/react";
|
||||
import { useTranslation } from "~/hooks/useTranslation";
|
||||
import { useUser } from "~/modules/auth";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { userPage } from "~/utils/urls";
|
||||
import { Avatar } from "../Avatar";
|
||||
import { LogInIcon } from "../icons/LogIn";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import allTags from "~/routes/calendar/tags.json";
|
||||
import allTags from "~/features/calendar/tags.json";
|
||||
import type { CalendarEventTag } from "./db/types";
|
||||
import type { BuildAbilitiesTupleWithUnknown } from "./modules/in-game-lists";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
import * as users from "./models/users/queries.server";
|
||||
import * as plusSuggestions from "./models/plusSuggestions/queries.server";
|
||||
import * as plusVotes from "./models/plusVotes/queries.server";
|
||||
import * as badges from "./models/badges/queries.server";
|
||||
import * as calendarEvents from "./models/calendar/queries.server";
|
||||
import * as builds from "./models/builds/queries.server";
|
||||
|
||||
export const db = {
|
||||
users,
|
||||
plusSuggestions,
|
||||
plusVotes,
|
||||
badges,
|
||||
calendarEvents,
|
||||
builds,
|
||||
};
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"BadgeManager" ("badgeId", "userId")
|
||||
values
|
||||
(@badgeId, @userId)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"TournamentBadgeOwner" ("badgeId", "userId")
|
||||
values
|
||||
(@badgeId, @userId)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"BadgeManager"
|
||||
where
|
||||
"badgeId" = @badgeId
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"TournamentBadgeOwner"
|
||||
where
|
||||
"badgeId" = @badgeId
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
select
|
||||
"Badge"."id",
|
||||
"Badge"."code",
|
||||
"Badge"."displayName",
|
||||
"Badge"."hue"
|
||||
from
|
||||
"Badge"
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
select
|
||||
"Badge"."code",
|
||||
"Badge"."displayName",
|
||||
"Badge"."id",
|
||||
"Badge"."hue",
|
||||
count("BadgeOwner"."badgeId") as count
|
||||
from
|
||||
"BadgeOwner"
|
||||
join "Badge" on "Badge"."id" = "BadgeOwner"."badgeId"
|
||||
where
|
||||
"BadgeOwner"."userId" = @userId
|
||||
group by
|
||||
"BadgeOwner"."badgeId",
|
||||
"BadgeOwner"."userId"
|
||||
order by
|
||||
"Badge"."id" = (
|
||||
select
|
||||
"favoriteBadgeId"
|
||||
from
|
||||
"User"
|
||||
where
|
||||
"id" = @userId
|
||||
) desc,
|
||||
"Badge"."id" asc
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
select
|
||||
"Badge"."id",
|
||||
"Badge"."code",
|
||||
"Badge"."displayName",
|
||||
"Badge"."hue"
|
||||
from
|
||||
"BadgeManager"
|
||||
join "Badge" on "Badge"."id" = "BadgeManager"."badgeId"
|
||||
where
|
||||
"userId" = @userId
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
select
|
||||
"User"."id",
|
||||
"User"."discordId",
|
||||
"User"."discordName",
|
||||
"User"."discordDiscriminator"
|
||||
from
|
||||
"BadgeManager"
|
||||
join "User" on "User"."id" = "BadgeManager"."userId"
|
||||
where
|
||||
"BadgeManager"."badgeId" = @id
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
select
|
||||
count("BadgeOwner"."badgeId") as count,
|
||||
"User"."id",
|
||||
"User"."discordId",
|
||||
"User"."discordName",
|
||||
"User"."discordDiscriminator"
|
||||
from
|
||||
"BadgeOwner"
|
||||
join "User" on "User"."id" = "BadgeOwner"."userId"
|
||||
where
|
||||
"BadgeOwner"."badgeId" = @id
|
||||
group by
|
||||
"User"."id"
|
||||
order by
|
||||
count desc,
|
||||
"User"."discordName" collate nocase asc
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
import { sql } from "../../sql";
|
||||
import type { Badge, User } from "../../types";
|
||||
|
||||
import deleteManyManagersSql from "./deleteManyManagers.sql";
|
||||
import createManagerSql from "./createManager.sql";
|
||||
import deleteManyOwnersSql from "./deleteManyOwners.sql";
|
||||
import createOwnerSql from "./createOwner.sql";
|
||||
import findByOwnerIdSql from "./findByOwnerId.sql";
|
||||
import findAllSql from "./findAll.sql";
|
||||
import ownersByBadgeIdSql from "./ownersByBadgeId.sql";
|
||||
import managersByBadgeIdSql from "./managersByBadgeId.sql";
|
||||
import managedByUserIdSql from "./managedByUserId.sql";
|
||||
|
||||
const deleteManyManagersStm = sql.prepare(deleteManyManagersSql);
|
||||
const createManagerStm = sql.prepare(createManagerSql);
|
||||
export const upsertManyManagers = sql.transaction(
|
||||
({
|
||||
badgeId,
|
||||
managerIds,
|
||||
}: {
|
||||
badgeId: Badge["id"];
|
||||
managerIds: Array<User["id"]>;
|
||||
}) => {
|
||||
deleteManyManagersStm.run({
|
||||
badgeId,
|
||||
});
|
||||
|
||||
for (const userId of managerIds) {
|
||||
createManagerStm.run({
|
||||
userId,
|
||||
badgeId,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const deleteManyOwnersStm = sql.prepare(deleteManyOwnersSql);
|
||||
const createOwnerStm = sql.prepare(createOwnerSql);
|
||||
export const upsertManyOwners = sql.transaction(
|
||||
({
|
||||
badgeId,
|
||||
ownerIds,
|
||||
}: {
|
||||
badgeId: Badge["id"];
|
||||
ownerIds: Array<User["id"]>;
|
||||
}) => {
|
||||
deleteManyOwnersStm.run({
|
||||
badgeId,
|
||||
});
|
||||
|
||||
for (const userId of ownerIds) {
|
||||
createOwnerStm.run({
|
||||
userId,
|
||||
badgeId,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const findByOwnerIdStm = sql.prepare(findByOwnerIdSql);
|
||||
|
||||
export type FindByOwnerId = Array<
|
||||
Pick<Badge, "code" | "displayName" | "id" | "hue"> & {
|
||||
count: number;
|
||||
}
|
||||
>;
|
||||
|
||||
export function findByOwnerId(userId: User["id"]) {
|
||||
return findByOwnerIdStm.all({ userId }) as FindByOwnerId;
|
||||
}
|
||||
|
||||
const findAllStm = sql.prepare(findAllSql);
|
||||
|
||||
export type FindAll = Array<Pick<Badge, "id" | "displayName" | "code" | "hue">>;
|
||||
|
||||
export function all() {
|
||||
return findAllStm.all() as FindAll;
|
||||
}
|
||||
|
||||
export type OwnersByBadgeId = Array<
|
||||
Pick<User, "id" | "discordId" | "discordName" | "discordDiscriminator"> & {
|
||||
count: number;
|
||||
}
|
||||
>;
|
||||
|
||||
const ownersByBadgeIdStm = sql.prepare(ownersByBadgeIdSql);
|
||||
export function ownersByBadgeId(id: Badge["id"]) {
|
||||
return ownersByBadgeIdStm.all({ id }) as OwnersByBadgeId;
|
||||
}
|
||||
|
||||
export type ManagersByBadgeId = Array<
|
||||
Pick<User, "id" | "discordId" | "discordName" | "discordDiscriminator">
|
||||
>;
|
||||
|
||||
const managersByBadgeIdStm = sql.prepare(managersByBadgeIdSql);
|
||||
export function managersByBadgeId(id: Badge["id"]) {
|
||||
return managersByBadgeIdStm.all({ id }) as ManagersByBadgeId;
|
||||
}
|
||||
|
||||
const managedByUserIdStm = sql.prepare(managedByUserIdSql);
|
||||
|
||||
export function managedByUserId(userId: User["id"]) {
|
||||
return managedByUserIdStm.all({ userId }) as Array<
|
||||
Pick<Badge, "id" | "code" | "displayName" | "hue">
|
||||
>;
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
select
|
||||
count(*) as "count"
|
||||
from
|
||||
"Build"
|
||||
where
|
||||
"Build"."ownerId" = @userId
|
||||
and (
|
||||
"Build"."private" = 0
|
||||
or "Build"."ownerId" = @loggedInUserId
|
||||
)
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
insert into
|
||||
"Build" (
|
||||
"ownerId",
|
||||
"title",
|
||||
"description",
|
||||
"modes",
|
||||
"headGearSplId",
|
||||
"clothesGearSplId",
|
||||
"shoesGearSplId",
|
||||
"private"
|
||||
)
|
||||
values
|
||||
(
|
||||
@ownerId,
|
||||
@title,
|
||||
@description,
|
||||
@modes,
|
||||
@headGearSplId,
|
||||
@clothesGearSplId,
|
||||
@shoesGearSplId,
|
||||
@private
|
||||
) returning *
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"BuildAbility" ("buildId", "gearType", "ability", "slotIndex")
|
||||
values
|
||||
(@buildId, @gearType, @ability, @slotIndex)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"BuildWeapon" ("buildId", "weaponSplId")
|
||||
values
|
||||
(@buildId, @weaponSplId)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"Build"
|
||||
where
|
||||
"id" = @id;
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
import { sql } from "~/db/sql";
|
||||
import type {
|
||||
Build,
|
||||
BuildWeapon,
|
||||
GearType,
|
||||
UserWithPlusTier,
|
||||
} from "~/db/types";
|
||||
import { modesShort, type ModeShort } from "~/modules/in-game-lists";
|
||||
import type { BuildAbilitiesTuple } from "~/modules/in-game-lists/types";
|
||||
|
||||
import countByUserIdSql from "./countByUserId.sql";
|
||||
import createBuildSql from "./createBuild.sql";
|
||||
import createBuildAbilitySql from "./createBuildAbility.sql";
|
||||
import createBuildWeaponSql from "./createBuildWeapon.sql";
|
||||
import deleteByIdSql from "./deleteById.sql";
|
||||
|
||||
const createBuildStm = sql.prepare(createBuildSql);
|
||||
const createBuildWeaponStm = sql.prepare(createBuildWeaponSql);
|
||||
const createBuildAbilityStm = sql.prepare(createBuildAbilitySql);
|
||||
const countByUserIdStm = sql.prepare(countByUserIdSql);
|
||||
const deleteByIdStm = sql.prepare(deleteByIdSql);
|
||||
|
||||
interface CreateArgs {
|
||||
ownerId: Build["ownerId"];
|
||||
title: Build["title"];
|
||||
description: Build["description"];
|
||||
modes: Array<ModeShort> | null;
|
||||
headGearSplId: Build["headGearSplId"];
|
||||
clothesGearSplId: Build["clothesGearSplId"];
|
||||
shoesGearSplId: Build["shoesGearSplId"];
|
||||
weaponSplIds: Array<BuildWeapon["weaponSplId"]>;
|
||||
abilities: BuildAbilitiesTuple;
|
||||
private: Build["private"];
|
||||
}
|
||||
export const create = sql.transaction((build: CreateArgs) => {
|
||||
const createdBuild = createBuildStm.get({
|
||||
ownerId: build.ownerId,
|
||||
title: build.title,
|
||||
description: build.description,
|
||||
modes:
|
||||
build.modes && build.modes.length > 0
|
||||
? JSON.stringify(
|
||||
build.modes
|
||||
.slice()
|
||||
.sort((a, b) => modesShort.indexOf(a) - modesShort.indexOf(b)),
|
||||
)
|
||||
: null,
|
||||
headGearSplId: build.headGearSplId,
|
||||
clothesGearSplId: build.clothesGearSplId,
|
||||
shoesGearSplId: build.shoesGearSplId,
|
||||
private: build.private,
|
||||
}) as Build;
|
||||
|
||||
for (const weaponSplId of build.weaponSplIds) {
|
||||
createBuildWeaponStm.run({
|
||||
buildId: createdBuild.id,
|
||||
weaponSplId,
|
||||
});
|
||||
}
|
||||
|
||||
for (const [rowI, row] of build.abilities.entries()) {
|
||||
const gearType: GearType =
|
||||
rowI === 0 ? "HEAD" : rowI === 1 ? "CLOTHES" : "SHOES";
|
||||
|
||||
for (const [abilityI, ability] of row.entries()) {
|
||||
createBuildAbilityStm.run({
|
||||
buildId: createdBuild.id,
|
||||
gearType,
|
||||
ability,
|
||||
slotIndex: abilityI,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const updateByReplacing = sql.transaction(
|
||||
(build: CreateArgs & { id: Build["id"] }) => {
|
||||
deleteByIdStm.run({ id: build.id });
|
||||
create(build);
|
||||
},
|
||||
);
|
||||
|
||||
export function countByUserId({
|
||||
userId,
|
||||
loggedInUserId,
|
||||
}: {
|
||||
userId: Build["ownerId"];
|
||||
loggedInUserId?: UserWithPlusTier["id"];
|
||||
}) {
|
||||
return ((countByUserIdStm.get({ userId, loggedInUserId }) as any)?.count ??
|
||||
0) as number;
|
||||
}
|
||||
|
||||
export function deleteById(id: Build["id"]) {
|
||||
deleteByIdStm.run({ id });
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
insert into
|
||||
"CalendarEvent" (
|
||||
"name",
|
||||
"authorId",
|
||||
"tags",
|
||||
"description",
|
||||
"discordInviteCode",
|
||||
"bracketUrl",
|
||||
"tournamentId"
|
||||
)
|
||||
values
|
||||
(
|
||||
@name,
|
||||
@authorId,
|
||||
@tags,
|
||||
@description,
|
||||
@discordInviteCode,
|
||||
@bracketUrl,
|
||||
@tournamentId
|
||||
) returning *
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"CalendarEventBadge" ("eventId", "badgeId")
|
||||
values
|
||||
(@eventId, @badgeId)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"CalendarEventDate" ("eventId", "startTime")
|
||||
values
|
||||
(@eventId, @startTime)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"MapPoolMap" ("calendarEventId", "stageId", "mode")
|
||||
values
|
||||
(@calendarEventId, @stageId, @mode)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"MapPoolMap" ("tieBreakerCalendarEventId", "stageId", "mode")
|
||||
values
|
||||
(@calendarEventId, @stageId, @mode)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"Tournament" ("mapPickingStyle", "format")
|
||||
values
|
||||
(@mapPickingStyle, @format) returning *
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"CalendarEventBadge"
|
||||
where
|
||||
"eventId" = @eventId
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"CalendarEvent"
|
||||
where
|
||||
"id" = @id
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"CalendarEventDate"
|
||||
where
|
||||
"eventId" = @eventId
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
delete from
|
||||
"MapPoolMap"
|
||||
where
|
||||
"calendarEventId" = @calendarEventId
|
||||
or "tieBreakerCalendarEventId" = @calendarEventId
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"CalendarEventResultTeam"
|
||||
where
|
||||
"eventId" = @eventId
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"Tournament"
|
||||
where
|
||||
id = @id
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
select
|
||||
"CalendarEvent"."id",
|
||||
"CalendarEvent"."name",
|
||||
(
|
||||
select
|
||||
max("startTime")
|
||||
from
|
||||
"CalendarEventDate"
|
||||
where
|
||||
"eventId" = "CalendarEvent"."id"
|
||||
) as "startTime"
|
||||
from
|
||||
"CalendarEvent"
|
||||
where
|
||||
"CalendarEvent"."authorId" = @authorId
|
||||
and "startTime" > @lowerLimitTime
|
||||
and "startTime" < @upperLimitTime
|
||||
and "CalendarEvent"."participantCount" is null
|
||||
and "CalendarEvent"."tournamentId" is null
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
select
|
||||
"CalendarEvent"."name",
|
||||
"CalendarEvent"."discordUrl",
|
||||
"CalendarEvent"."bracketUrl",
|
||||
"CalendarEvent"."tags",
|
||||
"CalendarEvent"."tournamentId",
|
||||
"CalendarEventDate"."id" as "eventDateId",
|
||||
"CalendarEventDate"."eventId",
|
||||
"CalendarEventDate"."startTime",
|
||||
"User"."discordName",
|
||||
"User"."discordDiscriminator",
|
||||
"CalendarEventRanks"."nthAppearance",
|
||||
exists (
|
||||
select
|
||||
1
|
||||
from
|
||||
"CalendarEventBadge"
|
||||
where
|
||||
"CalendarEventBadge"."eventId" = "CalendarEventDate"."eventId"
|
||||
) as "hasBadge"
|
||||
from
|
||||
"CalendarEvent"
|
||||
join "CalendarEventDate" on "CalendarEvent"."id" = "CalendarEventDate"."eventId"
|
||||
join "User" on "CalendarEvent"."authorId" = "User"."id"
|
||||
join (
|
||||
select
|
||||
"id",
|
||||
"eventId",
|
||||
"startTime",
|
||||
rank() over(
|
||||
partition by "eventId"
|
||||
order by
|
||||
"startTime" asc
|
||||
) "nthAppearance"
|
||||
from
|
||||
"CalendarEventDate"
|
||||
) "CalendarEventRanks" on "CalendarEventDate"."id" = "CalendarEventRanks"."id"
|
||||
where
|
||||
"CalendarEventDate"."startTime" between @startTime
|
||||
and @endTime
|
||||
order by
|
||||
"CalendarEventDate"."startTime" asc
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
select
|
||||
"CalendarEvent"."id",
|
||||
"CalendarEvent"."name",
|
||||
json_group_array(
|
||||
json_object(
|
||||
'stageId',
|
||||
"MapPoolMap"."stageId",
|
||||
'mode',
|
||||
"MapPoolMap"."mode"
|
||||
)
|
||||
) as "mapPool"
|
||||
from
|
||||
"CalendarEvent"
|
||||
join "MapPoolMap" on "CalendarEvent"."id" = "MapPoolMap"."calendarEventId"
|
||||
group by
|
||||
"CalendarEvent"."id"
|
||||
order by
|
||||
"CalendarEvent"."id" desc
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
select
|
||||
"Badge"."id",
|
||||
"Badge"."code",
|
||||
"Badge"."hue",
|
||||
"Badge"."displayName"
|
||||
from
|
||||
"CalendarEventBadge"
|
||||
join "Badge" on "CalendarEventBadge"."badgeId" = "Badge"."id"
|
||||
where
|
||||
"CalendarEventBadge"."eventId" = @eventId
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
select
|
||||
"CalendarEvent"."name",
|
||||
"CalendarEvent"."description",
|
||||
"CalendarEvent"."discordInviteCode",
|
||||
"CalendarEvent"."discordUrl",
|
||||
"CalendarEvent"."bracketUrl",
|
||||
"CalendarEvent"."tags",
|
||||
"CalendarEvent"."tournamentId",
|
||||
"CalendarEvent"."participantCount",
|
||||
"Tournament"."mapPickingStyle",
|
||||
"User"."id" as "authorId",
|
||||
exists (
|
||||
select
|
||||
1
|
||||
from
|
||||
"CalendarEventBadge"
|
||||
where
|
||||
"CalendarEventBadge"."eventId" = "CalendarEventDate"."eventId"
|
||||
) as "hasBadge",
|
||||
"CalendarEventDate"."startTime",
|
||||
"CalendarEventDate"."eventId",
|
||||
"User"."discordName",
|
||||
"User"."discordDiscriminator",
|
||||
"User"."discordId",
|
||||
"User"."discordAvatar"
|
||||
from
|
||||
"CalendarEvent"
|
||||
join "CalendarEventDate" on "CalendarEvent"."id" = "CalendarEventDate"."eventId"
|
||||
join "User" on "CalendarEvent"."authorId" = "User"."id"
|
||||
left join "Tournament" on "CalendarEvent"."tournamentId" = "Tournament"."id"
|
||||
where
|
||||
"CalendarEvent"."id" = @id
|
||||
order by
|
||||
"CalendarEventDate"."startTime" asc
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
select
|
||||
"stageId",
|
||||
"mode"
|
||||
from
|
||||
"MapPoolMap"
|
||||
where
|
||||
"calendarEventId" = @calendarEventId
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
select
|
||||
"CalendarEventResultPlayer"."name",
|
||||
"User"."id",
|
||||
"User"."discordName" as "discordName",
|
||||
"User"."discordDiscriminator" as "discordDiscriminator",
|
||||
"User"."discordId" as "discordId",
|
||||
"User"."discordAvatar" as "discordAvatar"
|
||||
from
|
||||
"CalendarEventResultPlayer"
|
||||
left join "User" on "User"."id" = "CalendarEventResultPlayer"."userId"
|
||||
where
|
||||
"teamId" = @teamId
|
||||
and (
|
||||
"CalendarEventResultPlayer"."userId" is null
|
||||
or "CalendarEventResultPlayer"."userId" != @userId
|
||||
)
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
select
|
||||
"User"."id",
|
||||
"User"."discordName",
|
||||
"User"."discordDiscriminator",
|
||||
"User"."discordId",
|
||||
"User"."discordAvatar"
|
||||
from
|
||||
"TournamentTeamMember"
|
||||
left join "User" on "User"."id" = "TournamentTeamMember"."userId"
|
||||
where
|
||||
"TournamentTeamMember"."tournamentTeamId" = @teamId
|
||||
and "TournamentTeamMember"."userId" != @userId
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
select
|
||||
"CalendarEvent"."id",
|
||||
"CalendarEvent"."name",
|
||||
json_group_array(
|
||||
json_object(
|
||||
'stageId',
|
||||
"MapPoolMap"."stageId",
|
||||
'mode',
|
||||
"MapPoolMap"."mode"
|
||||
)
|
||||
) as "mapPool"
|
||||
from
|
||||
"CalendarEvent"
|
||||
join "MapPoolMap" on "CalendarEvent"."id" = "MapPoolMap"."calendarEventId"
|
||||
where
|
||||
"CalendarEvent"."authorId" = @authorId
|
||||
group by
|
||||
"CalendarEvent"."id"
|
||||
order by
|
||||
"CalendarEvent"."id" desc
|
||||
limit 5
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
select
|
||||
"CalendarEvent"."id" as "eventId",
|
||||
null as "tournamentId",
|
||||
"CalendarEventResultTeam"."placement",
|
||||
"CalendarEvent"."participantCount",
|
||||
"CalendarEvent"."name" as "eventName",
|
||||
"CalendarEventResultTeam"."id" as "teamId",
|
||||
"CalendarEventResultTeam"."name" as "teamName",
|
||||
(
|
||||
select
|
||||
max("startTime")
|
||||
from
|
||||
"CalendarEventDate"
|
||||
where
|
||||
"eventId" = "CalendarEvent"."id"
|
||||
) as "startTime",
|
||||
exists (
|
||||
select
|
||||
1
|
||||
from
|
||||
"UserResultHighlight"
|
||||
where
|
||||
"userId" = @userId
|
||||
and "teamId" = "CalendarEventResultTeam"."id"
|
||||
) as "isHighlight"
|
||||
from
|
||||
"CalendarEventResultPlayer"
|
||||
join "CalendarEventResultTeam" on "CalendarEventResultTeam"."id" = "CalendarEventResultPlayer"."teamId"
|
||||
join "CalendarEvent" on "CalendarEvent"."id" = "CalendarEventResultTeam"."eventId"
|
||||
where
|
||||
"CalendarEventResultPlayer"."userId" = @userId
|
||||
union
|
||||
all
|
||||
select
|
||||
null as "eventId",
|
||||
"TournamentResult"."tournamentId",
|
||||
"TournamentResult"."placement",
|
||||
"TournamentResult"."participantCount",
|
||||
"CalendarEvent"."name" as "eventName",
|
||||
"TournamentTeam"."id" as "teamId",
|
||||
"TournamentTeam"."name" as "teamName",
|
||||
(
|
||||
select
|
||||
max("startTime")
|
||||
from
|
||||
"CalendarEventDate"
|
||||
where
|
||||
"eventId" = "CalendarEvent"."id"
|
||||
) as "startTime",
|
||||
"TournamentResult"."isHighlight"
|
||||
from
|
||||
"TournamentResult"
|
||||
left join "TournamentTeam" on "TournamentTeam"."id" = "TournamentResult"."tournamentTeamId"
|
||||
left join "CalendarEvent" on "CalendarEvent"."tournamentId" = "TournamentResult"."tournamentId"
|
||||
where
|
||||
"TournamentResult"."userId" = @userId
|
||||
order by
|
||||
"startTime" desc
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
select
|
||||
"stageId",
|
||||
"mode"
|
||||
from
|
||||
"MapPoolMap"
|
||||
where
|
||||
"tieBreakerCalendarEventId" = @calendarEventId
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
select
|
||||
count(*) as "memberCount"
|
||||
from
|
||||
"TournamentTeam"
|
||||
left join "TournamentTeamMember" on "TournamentTeamMember"."tournamentTeamId" = "TournamentTeam"."id"
|
||||
where
|
||||
"TournamentTeam"."tournamentId" = @tournamentId
|
||||
group by
|
||||
"TournamentTeam"."id";
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
select
|
||||
"CalendarEventResultTeam"."id",
|
||||
"CalendarEventResultTeam"."name" as "teamName",
|
||||
"CalendarEventResultTeam"."placement",
|
||||
"CalendarEventResultPlayer"."userId" as "playerId",
|
||||
"CalendarEventResultPlayer"."name" as "playerName",
|
||||
"User"."discordName" as "playerDiscordName",
|
||||
"User"."discordDiscriminator" as "playerDiscordDiscriminator",
|
||||
"User"."discordId" as "playerDiscordId",
|
||||
"User"."discordAvatar" as "playerDiscordAvatar"
|
||||
from
|
||||
"CalendarEventResultTeam"
|
||||
left join "CalendarEventResultPlayer" on "CalendarEventResultPlayer"."teamId" = "CalendarEventResultTeam"."id"
|
||||
left join "User" on "User"."id" = "CalendarEventResultPlayer"."userId"
|
||||
where
|
||||
"CalendarEventResultTeam"."eventId" = @eventId
|
||||
order by
|
||||
"CalendarEventResultTeam"."placement" asc
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"CalendarEventResultPlayer" ("teamId", "userId", "name")
|
||||
values
|
||||
(@teamId, @userId, @name)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"CalendarEventResultTeam" ("eventId", "name", "placement")
|
||||
values
|
||||
(@eventId, @name, @placement) returning *
|
||||
|
|
@ -1,564 +0,0 @@
|
|||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
import { sql } from "../../sql";
|
||||
import type {
|
||||
CalendarEvent,
|
||||
CalendarEventDate,
|
||||
User,
|
||||
Badge,
|
||||
CalendarEventTag,
|
||||
CalendarEventBadge,
|
||||
CalendarEventResultTeam,
|
||||
CalendarEventResultPlayer,
|
||||
MapPoolMap,
|
||||
Tournament,
|
||||
} from "../../types";
|
||||
import { MapPool } from "~/modules/map-pool-serializer";
|
||||
|
||||
import createSql from "./create.sql";
|
||||
import updateSql from "./update.sql";
|
||||
import createDateSql from "./createDate.sql";
|
||||
import deleteDatesByEventIdSql from "./deleteDatesByEventId.sql";
|
||||
import createBadgeSql from "./createBadge.sql";
|
||||
import deleteBadgesByEventIdSql from "./deleteBadgesByEventId.sql";
|
||||
import updateParticipantsCountSql from "./updateParticipantsCount.sql";
|
||||
import deleteResultTeamsByEventIdSql from "./deleteResultTeamsByEventId.sql";
|
||||
import insertResultTeamSql from "./insertResultTeam.sql";
|
||||
import insertResultPlayerSql from "./insertResultPlayer.sql";
|
||||
import findWinnersByEventIdSql from "./findWinnersByEventId.sql";
|
||||
import findResultsByUserIdSql from "./findResultsByUserId.sql";
|
||||
import findMatesByTournamentTeamIdSql from "./findMatesByTournamentTeamId.sql";
|
||||
import findMatesByResultTeamIdSql from "./findMatesByResultTeamId.sql";
|
||||
import findAllBetweenTwoTimestampsSql from "./findAllBetweenTwoTimestamps.sql";
|
||||
import findByIdSql from "./findById.sql";
|
||||
import startTimesOfRangeSql from "./startTimesOfRange.sql";
|
||||
import findBadgesByEventIdSql from "./findBadgesByEventId.sql";
|
||||
import eventsToReportSql from "./eventsToReport.sql";
|
||||
import createMapPoolMapSql from "./createMapPoolMap.sql";
|
||||
import deleteMapPoolMapsSql from "./deleteMapPoolMaps.sql";
|
||||
import createTieBreakerMapPoolMapSql from "./createTieBreakerMapPoolMap.sql";
|
||||
import findMapPoolByEventIdSql from "./findMapPoolByEventId.sql";
|
||||
import findRecentMapPoolsByAuthorIdSql from "./findRecentMapPoolsByAuthorId.sql";
|
||||
import findAllEventsWithMapPoolsSql from "./findAllEventsWithMapPools.sql";
|
||||
import findTieBreakerMapPoolByEventIdSql from "./findTieBreakerMapPoolByEventId.sql";
|
||||
import deleteByIdSql from "./deleteById.sql";
|
||||
import createTournamentSql from "./createTournament.sql";
|
||||
import deleteTournamentByIdSql from "./deleteTournamentById.sql";
|
||||
import findTournamentTeamMemberCountsByEventIdSql from "./findTournamentTeamMemberCountsByEventId.sql";
|
||||
import { sumArray } from "~/utils/number";
|
||||
|
||||
const createStm = sql.prepare(createSql);
|
||||
const updateStm = sql.prepare(updateSql);
|
||||
const createDateStm = sql.prepare(createDateSql);
|
||||
const deleteDatesByEventIdStm = sql.prepare(deleteDatesByEventIdSql);
|
||||
const createBadgeStm = sql.prepare(createBadgeSql);
|
||||
const deleteBadgesByEventIdStm = sql.prepare(deleteBadgesByEventIdSql);
|
||||
const createMapPoolMapStm = sql.prepare(createMapPoolMapSql);
|
||||
const deleteMapPoolMapsStm = sql.prepare(deleteMapPoolMapsSql);
|
||||
const createTieBreakerMapPoolMapStm = sql.prepare(
|
||||
createTieBreakerMapPoolMapSql,
|
||||
);
|
||||
const findMapPoolByEventIdStm = sql.prepare(findMapPoolByEventIdSql);
|
||||
const findTieBreakerMapPoolByEventIdtm = sql.prepare(
|
||||
findTieBreakerMapPoolByEventIdSql,
|
||||
);
|
||||
const deleteByIdStm = sql.prepare(deleteByIdSql);
|
||||
const deleteTournamentByIdStm = sql.prepare(deleteTournamentByIdSql);
|
||||
const createTournamentStm = sql.prepare(createTournamentSql);
|
||||
|
||||
const createTournament = (
|
||||
args: Omit<Tournament, "id" | "showMapListGenerator">,
|
||||
) => {
|
||||
return createTournamentStm.get(args) as Tournament;
|
||||
};
|
||||
|
||||
export type CreateArgs = Pick<
|
||||
CalendarEvent,
|
||||
| "name"
|
||||
| "authorId"
|
||||
| "tags"
|
||||
| "description"
|
||||
| "discordInviteCode"
|
||||
| "bracketUrl"
|
||||
> & {
|
||||
startTimes: Array<CalendarEventDate["startTime"]>;
|
||||
badges: Array<CalendarEventBadge["badgeId"]>;
|
||||
mapPoolMaps?: Array<Pick<MapPoolMap, "mode" | "stageId">>;
|
||||
createTournament: boolean;
|
||||
mapPickingStyle: Tournament["mapPickingStyle"];
|
||||
};
|
||||
export const create = sql.transaction(
|
||||
({
|
||||
startTimes,
|
||||
badges,
|
||||
mapPoolMaps = [],
|
||||
...calendarEventArgs
|
||||
}: CreateArgs) => {
|
||||
let tournamentId;
|
||||
if (calendarEventArgs.createTournament) {
|
||||
tournamentId = createTournament({
|
||||
// TODO: format picking
|
||||
format: "DE",
|
||||
mapPickingStyle: calendarEventArgs.mapPickingStyle,
|
||||
}).id;
|
||||
}
|
||||
const createdEvent = createStm.get({
|
||||
...calendarEventArgs,
|
||||
tournamentId,
|
||||
}) as CalendarEvent;
|
||||
|
||||
for (const startTime of startTimes) {
|
||||
createDateStm.run({
|
||||
eventId: createdEvent.id,
|
||||
startTime,
|
||||
});
|
||||
}
|
||||
|
||||
for (const badgeId of badges) {
|
||||
createBadgeStm.run({
|
||||
eventId: createdEvent.id,
|
||||
badgeId,
|
||||
});
|
||||
}
|
||||
|
||||
upsertMapPool({
|
||||
eventId: createdEvent.id,
|
||||
mapPoolMaps,
|
||||
isFullTournament: calendarEventArgs.createTournament,
|
||||
});
|
||||
|
||||
return createdEvent.id;
|
||||
},
|
||||
);
|
||||
|
||||
export type Update = Omit<
|
||||
CreateArgs,
|
||||
"authorId" | "createTournament" | "mapPickingStyle"
|
||||
> & {
|
||||
eventId: CalendarEvent["id"];
|
||||
};
|
||||
export const update = sql.transaction(
|
||||
({
|
||||
startTimes,
|
||||
badges,
|
||||
mapPoolMaps = [],
|
||||
eventId,
|
||||
...calendarEventArgs
|
||||
}: Update) => {
|
||||
const event = updateStm.get({
|
||||
...calendarEventArgs,
|
||||
eventId,
|
||||
}) as CalendarEvent;
|
||||
|
||||
deleteDatesByEventIdStm.run({ eventId });
|
||||
for (const startTime of startTimes) {
|
||||
createDateStm.run({
|
||||
eventId,
|
||||
startTime,
|
||||
});
|
||||
}
|
||||
|
||||
deleteBadgesByEventIdStm.run({ eventId });
|
||||
for (const badgeId of badges) {
|
||||
createBadgeStm.run({
|
||||
eventId,
|
||||
badgeId,
|
||||
});
|
||||
}
|
||||
|
||||
// can't edit tournament specific info after creation
|
||||
if (!event.tournamentId) {
|
||||
upsertMapPool({
|
||||
eventId,
|
||||
mapPoolMaps,
|
||||
isFullTournament: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function upsertMapPool({
|
||||
eventId,
|
||||
mapPoolMaps,
|
||||
isFullTournament,
|
||||
}: {
|
||||
eventId: Update["eventId"];
|
||||
mapPoolMaps: NonNullable<Update["mapPoolMaps"]>;
|
||||
isFullTournament: boolean;
|
||||
}) {
|
||||
deleteMapPoolMapsStm.run({ calendarEventId: eventId });
|
||||
if (isFullTournament) {
|
||||
for (const mapPoolArgs of mapPoolMaps) {
|
||||
createTieBreakerMapPoolMapStm.run({
|
||||
calendarEventId: eventId,
|
||||
...mapPoolArgs,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (const mapPoolArgs of mapPoolMaps) {
|
||||
createMapPoolMapStm.run({
|
||||
calendarEventId: eventId,
|
||||
...mapPoolArgs,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const updateParticipantsCountStm = sql.prepare(updateParticipantsCountSql);
|
||||
const deleteResultTeamsByEventIdStm = sql.prepare(
|
||||
deleteResultTeamsByEventIdSql,
|
||||
);
|
||||
const insertResultTeamStm = sql.prepare(insertResultTeamSql);
|
||||
const insertResultPlayerStm = sql.prepare(insertResultPlayerSql);
|
||||
|
||||
export const upsertReportedScores = sql.transaction(
|
||||
({
|
||||
eventId,
|
||||
participantCount,
|
||||
results,
|
||||
}: {
|
||||
eventId: CalendarEvent["id"];
|
||||
participantCount: CalendarEvent["participantCount"];
|
||||
results: Array<{
|
||||
teamName: CalendarEventResultTeam["name"];
|
||||
placement: CalendarEventResultTeam["placement"];
|
||||
players: Array<{
|
||||
userId: CalendarEventResultPlayer["userId"];
|
||||
name: CalendarEventResultPlayer["name"];
|
||||
}>;
|
||||
}>;
|
||||
}) => {
|
||||
updateParticipantsCountStm.run({ eventId, participantCount });
|
||||
deleteResultTeamsByEventIdStm.run({ eventId });
|
||||
|
||||
for (const { players, ...teamArgs } of results) {
|
||||
const teamInDb = insertResultTeamStm.get({
|
||||
eventId,
|
||||
name: teamArgs.teamName,
|
||||
placement: teamArgs.placement,
|
||||
}) as CalendarEventResultTeam;
|
||||
|
||||
for (const playerArgs of players) {
|
||||
insertResultPlayerStm.run({
|
||||
teamId: teamInDb.id,
|
||||
userId: playerArgs.userId,
|
||||
name: playerArgs.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const findWinnersByEventIdStm = sql.prepare(findWinnersByEventIdSql);
|
||||
|
||||
export function findResultsByEventId(eventId: CalendarEvent["id"]) {
|
||||
const rows = findWinnersByEventIdStm.all({ eventId }) as Array<{
|
||||
id: CalendarEventResultTeam["id"];
|
||||
teamName: CalendarEventResultTeam["name"];
|
||||
placement: CalendarEventResultTeam["placement"];
|
||||
playerId: CalendarEventResultPlayer["userId"];
|
||||
playerName: CalendarEventResultPlayer["name"] | null;
|
||||
playerDiscordName: User["discordName"] | null;
|
||||
playerDiscordDiscriminator: User["discordDiscriminator"] | null;
|
||||
playerDiscordId: User["discordId"] | null;
|
||||
playerDiscordAvatar: User["discordAvatar"];
|
||||
}>;
|
||||
|
||||
const result: Array<{
|
||||
teamName: CalendarEventResultTeam["name"];
|
||||
placement: CalendarEventResultTeam["placement"];
|
||||
players: Array<
|
||||
| string
|
||||
| Pick<
|
||||
User,
|
||||
| "id"
|
||||
| "discordId"
|
||||
| "discordName"
|
||||
| "discordDiscriminator"
|
||||
| "discordAvatar"
|
||||
>
|
||||
>;
|
||||
}> = [];
|
||||
|
||||
for (const row of rows) {
|
||||
const team = result.find((team) => team.teamName === row.teamName);
|
||||
const player = row.playerName ?? {
|
||||
// player name and user id are mutually exclusive
|
||||
// also if user id exists we know a joined user also has to exist
|
||||
id: row.playerId!,
|
||||
discordId: row.playerDiscordId!,
|
||||
discordName: row.playerDiscordName!,
|
||||
discordDiscriminator: row.playerDiscordDiscriminator!,
|
||||
discordAvatar: row.playerDiscordAvatar,
|
||||
};
|
||||
|
||||
if (team) {
|
||||
team.players.push(player);
|
||||
} else {
|
||||
result.push({
|
||||
teamName: row.teamName,
|
||||
placement: row.placement,
|
||||
players: [player],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const findResultsByUserIdStm = sql.prepare(findResultsByUserIdSql);
|
||||
const findMatesByResultTeamIdStm = sql.prepare(findMatesByResultTeamIdSql);
|
||||
const findMatesByTournamentTeamIdStm = sql.prepare(
|
||||
findMatesByTournamentTeamIdSql,
|
||||
);
|
||||
export function findResultsByUserId(userId: User["id"]) {
|
||||
return (
|
||||
findResultsByUserIdStm.all({ userId }) as Array<{
|
||||
eventId: CalendarEvent["id"] | null;
|
||||
tournamentId: CalendarEvent["tournamentId"] | null;
|
||||
teamId: CalendarEventResultTeam["id"];
|
||||
eventName: CalendarEvent["name"];
|
||||
teamName: CalendarEventResultTeam["name"];
|
||||
placement: CalendarEventResultTeam["placement"];
|
||||
participantCount: CalendarEvent["participantCount"];
|
||||
startTime: CalendarEventDate["startTime"];
|
||||
isHighlight: number;
|
||||
}>
|
||||
).map((row) => ({
|
||||
...row,
|
||||
isHighlight: Boolean(row.isHighlight),
|
||||
mates: (
|
||||
(row.tournamentId
|
||||
? findMatesByTournamentTeamIdStm
|
||||
: findMatesByResultTeamIdStm
|
||||
).all({
|
||||
teamId: row.teamId,
|
||||
userId,
|
||||
}) as Array<{
|
||||
name: CalendarEventResultPlayer["name"];
|
||||
id: User["id"];
|
||||
discordName: User["discordName"];
|
||||
discordDiscriminator: User["discordDiscriminator"];
|
||||
discordId: User["discordId"];
|
||||
discordAvatar: User["discordAvatar"];
|
||||
}>
|
||||
).map(({ name, ...mate }) => name ?? mate),
|
||||
}));
|
||||
}
|
||||
|
||||
const findAllBetweenTwoTimestampsStm = sql.prepare(
|
||||
findAllBetweenTwoTimestampsSql,
|
||||
);
|
||||
|
||||
function addTagArray<
|
||||
T extends {
|
||||
hasBadge: number;
|
||||
tags?: CalendarEvent["tags"];
|
||||
tournamentId: CalendarEvent["tournamentId"];
|
||||
},
|
||||
>(arg: T) {
|
||||
const { hasBadge, ...row } = arg;
|
||||
const tags = (row.tags ? row.tags.split(",") : []) as Array<CalendarEventTag>;
|
||||
|
||||
if (hasBadge) tags.unshift("BADGE");
|
||||
if (row.tournamentId) tags.unshift("FULL_TOURNAMENT");
|
||||
|
||||
return { ...row, tags };
|
||||
}
|
||||
|
||||
const findTournamentTeamMemberCountsByEventIdStm = sql.prepare(
|
||||
findTournamentTeamMemberCountsByEventIdSql,
|
||||
);
|
||||
|
||||
function addParticipantsCounts<
|
||||
T extends { tournamentId: CalendarEvent["tournamentId"] },
|
||||
>(arg: T) {
|
||||
if (!arg.tournamentId) return arg;
|
||||
|
||||
const counts = findTournamentTeamMemberCountsByEventIdStm.all({
|
||||
tournamentId: arg.tournamentId,
|
||||
}) as Array<{
|
||||
memberCount: number;
|
||||
}>;
|
||||
|
||||
return {
|
||||
...arg,
|
||||
participantCounts: {
|
||||
teams: counts.length,
|
||||
players: sumArray(counts.map((c) => c.memberCount)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function findAllBetweenTwoTimestamps({
|
||||
startTime,
|
||||
endTime,
|
||||
}: {
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
}) {
|
||||
const rows = findAllBetweenTwoTimestampsStm.all({
|
||||
startTime: dateToDatabaseTimestamp(startTime),
|
||||
endTime: dateToDatabaseTimestamp(endTime),
|
||||
}) as Array<
|
||||
Pick<
|
||||
CalendarEvent,
|
||||
"name" | "discordUrl" | "bracketUrl" | "tags" | "tournamentId"
|
||||
> &
|
||||
Pick<CalendarEventDate, "eventId" | "startTime"> & {
|
||||
eventDateId: CalendarEventDate["id"];
|
||||
} & Pick<User, "discordName" | "discordDiscriminator"> & {
|
||||
nthAppearance: number;
|
||||
} & { hasBadge: number } & {
|
||||
participantCounts?: { teams: number; players: number };
|
||||
}
|
||||
>;
|
||||
|
||||
return rows.map(addTagArray).map(addBadges).map(addParticipantsCounts);
|
||||
}
|
||||
|
||||
const findByIdStm = sql.prepare(findByIdSql);
|
||||
export function findById(id: CalendarEvent["id"]) {
|
||||
const [firstRow, ...rest] = findByIdStm.all({ id }) as Array<
|
||||
Pick<
|
||||
CalendarEvent,
|
||||
| "name"
|
||||
| "description"
|
||||
| "discordUrl"
|
||||
| "discordInviteCode"
|
||||
| "bracketUrl"
|
||||
| "tags"
|
||||
| "authorId"
|
||||
| "participantCount"
|
||||
| "tournamentId"
|
||||
> &
|
||||
Pick<Tournament, "mapPickingStyle"> &
|
||||
Pick<CalendarEventDate, "startTime" | "eventId"> &
|
||||
Pick<
|
||||
User,
|
||||
"discordName" | "discordDiscriminator" | "discordId" | "discordAvatar"
|
||||
> & { hasBadge: number }
|
||||
>;
|
||||
|
||||
if (!firstRow) return null;
|
||||
|
||||
return addTagArray({
|
||||
...firstRow,
|
||||
startTimes: [firstRow, ...rest].map((row) => row.startTime),
|
||||
startTime: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
function addBadges<
|
||||
T extends { eventId: CalendarEvent["id"]; tags?: CalendarEvent["tags"] },
|
||||
>(arg: T) {
|
||||
return {
|
||||
...arg,
|
||||
badgePrizes: arg.tags?.includes("BADGE")
|
||||
? findBadgesByEventId(arg.eventId)
|
||||
: [],
|
||||
};
|
||||
}
|
||||
|
||||
const startTimesOfRangeStm = sql.prepare(startTimesOfRangeSql);
|
||||
export function startTimesOfRange({
|
||||
startTime,
|
||||
endTime,
|
||||
}: {
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
}) {
|
||||
return (
|
||||
startTimesOfRangeStm.all({
|
||||
startTime: dateToDatabaseTimestamp(startTime),
|
||||
endTime: dateToDatabaseTimestamp(endTime),
|
||||
}) as Array<Pick<CalendarEventDate, "startTime">>
|
||||
).map(({ startTime }) => startTime);
|
||||
}
|
||||
|
||||
const findBadgesByEventIdStm = sql.prepare(findBadgesByEventIdSql);
|
||||
export function findBadgesByEventId(eventId: CalendarEvent["id"]) {
|
||||
return findBadgesByEventIdStm.all({ eventId }) as Array<
|
||||
Pick<Badge, "id" | "code" | "hue" | "displayName">
|
||||
>;
|
||||
}
|
||||
|
||||
export function findMapPoolByEventId(calendarEventId: CalendarEvent["id"]) {
|
||||
const rows = findMapPoolByEventIdStm.all({ calendarEventId }) as Array<
|
||||
Pick<MapPoolMap, "stageId" | "mode">
|
||||
>;
|
||||
|
||||
if (rows.length === 0) return;
|
||||
|
||||
return MapPool.parse(rows);
|
||||
}
|
||||
|
||||
const eventsToReportStm = sql.prepare(eventsToReportSql);
|
||||
export function eventsToReport(authorId?: CalendarEvent["authorId"]) {
|
||||
if (!authorId) return [];
|
||||
|
||||
const oneMonthAgo = new Date();
|
||||
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
|
||||
|
||||
return (
|
||||
eventsToReportStm.all({
|
||||
authorId,
|
||||
upperLimitTime: dateToDatabaseTimestamp(new Date()),
|
||||
lowerLimitTime: dateToDatabaseTimestamp(oneMonthAgo),
|
||||
}) as Array<Pick<CalendarEvent, "id" | "name">>
|
||||
).map((row) => ({ id: row.id, name: row.name }));
|
||||
}
|
||||
|
||||
const findRecentMapPoolsByAuthorIdStm = sql.prepare(
|
||||
findRecentMapPoolsByAuthorIdSql,
|
||||
);
|
||||
export function findRecentMapPoolsByAuthorId(
|
||||
authorId: CalendarEvent["authorId"],
|
||||
) {
|
||||
return (
|
||||
findRecentMapPoolsByAuthorIdStm.all({ authorId }) as Array<
|
||||
Pick<CalendarEvent, "id" | "name"> & {
|
||||
mapPool: string;
|
||||
}
|
||||
>
|
||||
).map((row) => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
serializedMapPool: MapPool.serialize(JSON.parse(row.mapPool)),
|
||||
}));
|
||||
}
|
||||
|
||||
const findAllEventsWithMapPoolsStm = sql.prepare(findAllEventsWithMapPoolsSql);
|
||||
export function findAllEventsWithMapPools() {
|
||||
return (
|
||||
findAllEventsWithMapPoolsStm.all() as Array<
|
||||
Pick<CalendarEvent, "id" | "name"> & {
|
||||
mapPool: string;
|
||||
}
|
||||
>
|
||||
).map((row) => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
serializedMapPool: MapPool.serialize(JSON.parse(row.mapPool)),
|
||||
}));
|
||||
}
|
||||
|
||||
export function findTieBreakerMapPoolByEventId(
|
||||
calendarEventId: string | number,
|
||||
) {
|
||||
return findTieBreakerMapPoolByEventIdtm.all({ calendarEventId }) as Array<
|
||||
Pick<MapPoolMap, "mode" | "stageId">
|
||||
>;
|
||||
}
|
||||
|
||||
export const deleteById = sql.transaction(
|
||||
({
|
||||
eventId,
|
||||
tournamentId,
|
||||
}: {
|
||||
eventId: number;
|
||||
tournamentId: number | null;
|
||||
}) => {
|
||||
deleteByIdStm.run({ id: eventId });
|
||||
if (tournamentId) deleteTournamentByIdStm.run({ id: tournamentId });
|
||||
},
|
||||
);
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
select
|
||||
"CalendarEventDate"."startTime"
|
||||
from
|
||||
"CalendarEventDate"
|
||||
where
|
||||
"CalendarEventDate"."startTime" between @startTime
|
||||
and @endTime
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
update
|
||||
"CalendarEvent"
|
||||
set
|
||||
"name" = @name,
|
||||
"tags" = @tags,
|
||||
"description" = @description,
|
||||
"discordInviteCode" = @discordInviteCode,
|
||||
"bracketUrl" = @bracketUrl
|
||||
where
|
||||
"id" = @eventId returning *;
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
update
|
||||
"CalendarEvent"
|
||||
set
|
||||
"participantCount" = @participantCount
|
||||
where
|
||||
"id" = @eventId
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
insert into
|
||||
"PlusSuggestion" (
|
||||
"text",
|
||||
"authorId",
|
||||
"suggestedId",
|
||||
"month",
|
||||
"year",
|
||||
"tier"
|
||||
)
|
||||
values
|
||||
(
|
||||
@text,
|
||||
@authorId,
|
||||
@suggestedId,
|
||||
@month,
|
||||
@year,
|
||||
@tier
|
||||
)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"PlusSuggestion"
|
||||
where
|
||||
"id" = @id
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
delete from
|
||||
"PlusSuggestion"
|
||||
where
|
||||
"suggestedId" = @suggestedId
|
||||
and "tier" = @tier
|
||||
and "month" = @month
|
||||
and "year" = @year
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
delete from
|
||||
"PlusSuggestion"
|
||||
where
|
||||
"month" = @month
|
||||
and "year" = @year
|
||||
and "suggestedId" = @suggestedId
|
||||
and "tier" = @tier
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
select
|
||||
suggestion."id",
|
||||
suggestion."createdAt",
|
||||
suggestion."text",
|
||||
suggestion."tier",
|
||||
author."id" as "authorId",
|
||||
author."discordId" as "authorDiscordId",
|
||||
author."discordName" as "authorDiscordName",
|
||||
author."discordDiscriminator" as "authorDiscordDiscriminator",
|
||||
suggested."id" as "suggestedId",
|
||||
suggested."discordId" as "suggestedDiscordId",
|
||||
suggested."discordName" as "suggestedDiscordName",
|
||||
suggested."discordDiscriminator" as "suggestedDiscordDiscriminator",
|
||||
suggested."discordAvatar" as "suggestedDiscordAvatar",
|
||||
suggested."bio" as "suggestedBio"
|
||||
from
|
||||
"PlusSuggestion" as suggestion
|
||||
join "User" as author on suggestion."authorId" = author."id"
|
||||
join "User" as suggested on suggestion."suggestedId" = suggested."id"
|
||||
where
|
||||
"month" = @month
|
||||
and "year" = @year
|
||||
and "tier" >= @plusTier
|
||||
order by
|
||||
suggestion."id" asc
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
import { formatDistance } from "date-fns";
|
||||
import type { MonthYear } from "~/modules/plus-server";
|
||||
import { nextNonCompletedVoting } from "~/modules/plus-server";
|
||||
import { atOrError } from "~/utils/arrays";
|
||||
import { databaseTimestampToDate } from "~/utils/dates";
|
||||
import { sql } from "../../sql";
|
||||
import type { PlusSuggestion, User, UserWithPlusTier } from "../../types";
|
||||
|
||||
import createSql from "./create.sql";
|
||||
import findVisibleForUserSql from "./findVisibleForUser.sql";
|
||||
import tiersSuggestedForSql from "./tiersSuggestedFor.sql";
|
||||
import deleteSql from "./delete.sql";
|
||||
import deleteAllSql from "./deleteAll.sql";
|
||||
import deleteSuggestionWithCommentsSql from "./deleteSuggestionWithComments.sql";
|
||||
|
||||
const createStm = sql.prepare(createSql);
|
||||
export function create(
|
||||
args: Pick<
|
||||
PlusSuggestion,
|
||||
"text" | "authorId" | "suggestedId" | "month" | "year" | "tier"
|
||||
>,
|
||||
) {
|
||||
createStm.run(args);
|
||||
}
|
||||
|
||||
const findVisibleForUserStm = sql.prepare(findVisibleForUserSql);
|
||||
|
||||
export interface FindVisibleForUserSuggestedUserInfo {
|
||||
suggestedUser: Pick<
|
||||
User,
|
||||
| "id"
|
||||
| "discordId"
|
||||
| "discordName"
|
||||
| "discordDiscriminator"
|
||||
| "discordAvatar"
|
||||
| "bio"
|
||||
>;
|
||||
suggestions: (Pick<PlusSuggestion, "id" | "text" | "createdAt"> & {
|
||||
createdAtRelative: string;
|
||||
author: Pick<
|
||||
User,
|
||||
"id" | "discordId" | "discordName" | "discordDiscriminator"
|
||||
>;
|
||||
})[];
|
||||
}
|
||||
export interface FindVisibleForUser {
|
||||
[tier: string]: FindVisibleForUserSuggestedUserInfo[];
|
||||
}
|
||||
|
||||
export function findVisibleForUser(
|
||||
args: MonthYear &
|
||||
Pick<UserWithPlusTier, "plusTier"> & { includeBio?: boolean },
|
||||
): FindVisibleForUser | undefined {
|
||||
if (typeof args.plusTier !== "number") return;
|
||||
return sortNewestPlayersToBeSuggestedFirst(
|
||||
mapFindVisibleForUserRowsToResult(
|
||||
findVisibleForUserStm.all(args),
|
||||
args.includeBio,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function findAll(args: MonthYear & { includeBio?: boolean }) {
|
||||
// plusTier 0 is a bit hacky way to get all suggestions
|
||||
// while reusing the query
|
||||
return findVisibleForUser({ ...args, plusTier: 0 })!;
|
||||
}
|
||||
|
||||
function mapFindVisibleForUserRowsToResult(
|
||||
rows: any[],
|
||||
includeBio?: boolean,
|
||||
): FindVisibleForUser {
|
||||
return rows.reduce((result: FindVisibleForUser, row) => {
|
||||
const usersOfTier = result[row.tier] ?? [];
|
||||
result[row.tier] = usersOfTier;
|
||||
|
||||
const suggestionInfo = {
|
||||
id: row.id,
|
||||
createdAt: row.createdAt,
|
||||
createdAtRelative: formatDistance(
|
||||
databaseTimestampToDate(row.createdAt),
|
||||
new Date(),
|
||||
{ addSuffix: true },
|
||||
),
|
||||
text: row.text,
|
||||
author: {
|
||||
id: row.authorId,
|
||||
discordId: row.authorDiscordId,
|
||||
discordName: row.authorDiscordName,
|
||||
discordDiscriminator: row.authorDiscordDiscriminator,
|
||||
},
|
||||
};
|
||||
|
||||
const existingSuggestion = usersOfTier.find(
|
||||
(suggestion) => suggestion.suggestedUser.id === row.suggestedId,
|
||||
);
|
||||
|
||||
if (existingSuggestion) {
|
||||
existingSuggestion.suggestions.push(suggestionInfo);
|
||||
} else {
|
||||
usersOfTier.push({
|
||||
suggestedUser: {
|
||||
id: row.suggestedId,
|
||||
discordId: row.suggestedDiscordId,
|
||||
discordName: row.suggestedDiscordName,
|
||||
discordDiscriminator: row.suggestedDiscordDiscriminator,
|
||||
discordAvatar: row.suggestedDiscordAvatar,
|
||||
bio: includeBio ? row.suggestedBio : null,
|
||||
},
|
||||
suggestions: [suggestionInfo],
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function sortNewestPlayersToBeSuggestedFirst(
|
||||
suggestions: FindVisibleForUser,
|
||||
): FindVisibleForUser {
|
||||
return Object.fromEntries(
|
||||
Object.entries(suggestions).map(([tier, suggestions]) => [
|
||||
tier,
|
||||
suggestions.sort(
|
||||
(a, b) =>
|
||||
atOrError(b.suggestions, 0).createdAt -
|
||||
atOrError(a.suggestions, 0).createdAt,
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
const tiersSuggestedForStm = sql.prepare(tiersSuggestedForSql);
|
||||
export function tiersSuggestedFor(args: MonthYear & { userId: User["id"] }) {
|
||||
return JSON.parse(
|
||||
tiersSuggestedForStm.pluck().get(args) as any,
|
||||
) as User["id"][];
|
||||
}
|
||||
|
||||
const deleteStm = sql.prepare(deleteSql);
|
||||
|
||||
export function del(id: PlusSuggestion["id"]) {
|
||||
deleteStm.run({ id });
|
||||
}
|
||||
|
||||
const deleteAllStm = sql.prepare(deleteAllSql);
|
||||
export function deleteAll(args: Pick<PlusSuggestion, "suggestedId" | "tier">) {
|
||||
deleteAllStm.run({ ...args, ...nextNonCompletedVoting(new Date()) });
|
||||
}
|
||||
|
||||
const deleteSuggestionWithCommentsStm = sql.prepare(
|
||||
deleteSuggestionWithCommentsSql,
|
||||
);
|
||||
export function deleteSuggestionWithComments(
|
||||
args: Pick<PlusSuggestion, "suggestedId" | "tier" | "month" | "year">,
|
||||
) {
|
||||
deleteSuggestionWithCommentsStm.run(args);
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
select
|
||||
json_group_array("tier")
|
||||
from
|
||||
(
|
||||
select
|
||||
distinct "tier"
|
||||
from
|
||||
"PlusSuggestion"
|
||||
where
|
||||
"month" = @month
|
||||
and "year" = @year
|
||||
and "suggestedId" = @userId
|
||||
order by
|
||||
"tier" asc
|
||||
)
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
insert into
|
||||
"PlusVote" (
|
||||
"month",
|
||||
"year",
|
||||
"tier",
|
||||
"authorId",
|
||||
"votedId",
|
||||
"score",
|
||||
"validAfter"
|
||||
)
|
||||
values
|
||||
(
|
||||
@month,
|
||||
@year,
|
||||
@tier,
|
||||
@authorId,
|
||||
@votedId,
|
||||
@score,
|
||||
@validAfter
|
||||
)
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
delete from
|
||||
"PlusVote"
|
||||
where
|
||||
"authorId" = @authorId
|
||||
and "month" = @month
|
||||
and "year" = @year
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
select
|
||||
1
|
||||
from
|
||||
"PlusVote"
|
||||
where
|
||||
"authorId" = @userId
|
||||
and "month" = @month
|
||||
and "year" = @year
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
select
|
||||
"User"."id",
|
||||
"User"."discordId",
|
||||
"User"."discordName",
|
||||
"User"."discordDiscriminator",
|
||||
"User"."discordAvatar",
|
||||
"User"."bio"
|
||||
from
|
||||
"User"
|
||||
join "PlusTier" on "User"."id" = "PlusTier"."userId"
|
||||
where
|
||||
"PlusTier"."tier" = @plusTier
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
import shuffle from "just-shuffle";
|
||||
import invariant from "tiny-invariant";
|
||||
import type { MonthYear } from "~/modules/plus-server";
|
||||
import {
|
||||
nextNonCompletedVoting,
|
||||
rangeToMonthYear,
|
||||
} from "~/modules/plus-server";
|
||||
import { atOrError } from "~/utils/arrays";
|
||||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
import type { Unpacked } from "~/utils/types";
|
||||
import { db } from "../..";
|
||||
import { sql } from "../../sql";
|
||||
import type {
|
||||
PlusVote,
|
||||
PlusVotingResult,
|
||||
User,
|
||||
UserWithPlusTier,
|
||||
} from "../../types";
|
||||
import type { FindVisibleForUserSuggestedUserInfo } from "../plusSuggestions/queries.server";
|
||||
|
||||
import createSql from "./create.sql";
|
||||
import deleteManySql from "./deleteMany.sql";
|
||||
import resultsByMonthYearSql from "./resultsByMonthYear.sql";
|
||||
import plusServerMembersSql from "./plusServerMembers.sql";
|
||||
import hasVotedSql from "./hasVoted.sql";
|
||||
|
||||
const createStm = sql.prepare(createSql);
|
||||
const deleteManyStm = sql.prepare(deleteManySql);
|
||||
|
||||
export type UpsertManyPlusVotesArgs = (Pick<
|
||||
PlusVote,
|
||||
"month" | "year" | "tier" | "authorId" | "votedId" | "score"
|
||||
> & { validAfter: Date })[];
|
||||
export const upsertMany = sql.transaction((votes: UpsertManyPlusVotesArgs) => {
|
||||
const firstVote = atOrError(votes, 0);
|
||||
deleteManyStm.run({
|
||||
authorId: firstVote.authorId,
|
||||
month: firstVote.month,
|
||||
year: firstVote.year,
|
||||
});
|
||||
|
||||
for (const vote of votes) {
|
||||
const { validAfter, ...rest } = vote;
|
||||
createStm.run({
|
||||
...rest,
|
||||
validAfter: dateToDatabaseTimestamp(validAfter),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
type PlusVotingResultsByMonthYearDatabaseResult = (PlusVotingResultUser &
|
||||
Pick<PlusVotingResult, "score" | "wasSuggested" | "passedVoting" | "tier">)[];
|
||||
|
||||
const resultsByMonthYearStm = sql.prepare(resultsByMonthYearSql);
|
||||
|
||||
type PlusVotingResultUser = Pick<
|
||||
User,
|
||||
"id" | "discordAvatar" | "discordDiscriminator" | "discordName" | "discordId"
|
||||
> &
|
||||
Pick<PlusVotingResult, "wasSuggested">;
|
||||
export interface PlusVotingResultByMonthYear {
|
||||
results: {
|
||||
tier: number;
|
||||
passed: PlusVotingResultUser[];
|
||||
failed: PlusVotingResultUser[];
|
||||
}[];
|
||||
scores: (Pick<
|
||||
PlusVotingResult,
|
||||
"score" | "tier" | "wasSuggested" | "passedVoting"
|
||||
> & { userId: User["id"] })[];
|
||||
}
|
||||
|
||||
export function resultsByMontYear(
|
||||
args: MonthYear,
|
||||
): PlusVotingResultByMonthYear {
|
||||
const results = resultsByMonthYearStm.all(
|
||||
args,
|
||||
) as PlusVotingResultsByMonthYearDatabaseResult;
|
||||
|
||||
return {
|
||||
results: groupPlusVotingResults(results),
|
||||
scores: scoresFromPlusVotingResults(results),
|
||||
};
|
||||
}
|
||||
|
||||
function groupPlusVotingResults(
|
||||
rows: PlusVotingResultsByMonthYearDatabaseResult,
|
||||
): PlusVotingResultByMonthYear["results"] {
|
||||
const grouped: Record<
|
||||
number,
|
||||
{ passed: PlusVotingResultUser[]; failed: PlusVotingResultUser[] }
|
||||
> = {};
|
||||
|
||||
for (const row of rows) {
|
||||
const playersOfTier = grouped[row.tier] ?? {
|
||||
passed: [],
|
||||
failed: [],
|
||||
};
|
||||
grouped[row.tier] = playersOfTier;
|
||||
|
||||
playersOfTier[row.passedVoting ? "passed" : "failed"].push({
|
||||
id: row.id,
|
||||
discordAvatar: row.discordAvatar,
|
||||
discordDiscriminator: row.discordDiscriminator,
|
||||
discordName: row.discordName,
|
||||
discordId: row.discordId,
|
||||
wasSuggested: row.wasSuggested,
|
||||
});
|
||||
}
|
||||
|
||||
return Object.entries(grouped)
|
||||
.map(([tier, { passed, failed }]) => ({
|
||||
tier: Number(tier),
|
||||
passed,
|
||||
failed,
|
||||
}))
|
||||
.sort((a, b) => a.tier - b.tier);
|
||||
}
|
||||
|
||||
function scoresFromPlusVotingResults(
|
||||
rows: PlusVotingResultsByMonthYearDatabaseResult,
|
||||
) {
|
||||
return rows
|
||||
.map((row) => ({
|
||||
userId: row.id,
|
||||
tier: row.tier,
|
||||
score: row.score,
|
||||
wasSuggested: row.wasSuggested,
|
||||
passedVoting: row.passedVoting,
|
||||
}))
|
||||
.sort((a, b) => a.tier - b.tier);
|
||||
}
|
||||
|
||||
const plusServerMembersStm = sql.prepare(plusServerMembersSql);
|
||||
|
||||
export type UsersForVoting = {
|
||||
user: Pick<
|
||||
User,
|
||||
| "id"
|
||||
| "discordId"
|
||||
| "discordName"
|
||||
| "discordDiscriminator"
|
||||
| "discordAvatar"
|
||||
| "bio"
|
||||
>;
|
||||
suggestions?: FindVisibleForUserSuggestedUserInfo["suggestions"];
|
||||
}[];
|
||||
|
||||
export function usersForVoting(
|
||||
loggedInUser?: Pick<UserWithPlusTier, "id" | "plusTier">,
|
||||
) {
|
||||
if (!loggedInUser || !loggedInUser.plusTier) return;
|
||||
|
||||
const { month, year } = rangeToMonthYear(nextNonCompletedVoting(new Date()));
|
||||
const members = plusServerMembersStm.all({
|
||||
plusTier: loggedInUser.plusTier,
|
||||
}) as Unpacked<UsersForVoting>["user"][];
|
||||
|
||||
const allSuggestedTiers = db.plusSuggestions.findVisibleForUser({
|
||||
plusTier: loggedInUser.plusTier,
|
||||
month,
|
||||
year,
|
||||
includeBio: true,
|
||||
});
|
||||
invariant(allSuggestedTiers);
|
||||
const suggestedUsers = allSuggestedTiers[loggedInUser.plusTier] ?? [];
|
||||
|
||||
const result: UsersForVoting = [];
|
||||
|
||||
for (const member of members) {
|
||||
result.push({
|
||||
user: {
|
||||
id: member.id,
|
||||
discordId: member.discordId,
|
||||
discordName: member.discordName,
|
||||
discordDiscriminator: member.discordDiscriminator,
|
||||
discordAvatar: member.discordAvatar,
|
||||
bio: member.bio,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (const { suggestedUser, suggestions } of suggestedUsers) {
|
||||
result.push({
|
||||
user: {
|
||||
id: suggestedUser.id,
|
||||
discordId: suggestedUser.discordId,
|
||||
discordName: suggestedUser.discordName,
|
||||
discordDiscriminator: suggestedUser.discordDiscriminator,
|
||||
discordAvatar: suggestedUser.discordAvatar,
|
||||
bio: suggestedUser.bio,
|
||||
},
|
||||
suggestions,
|
||||
});
|
||||
}
|
||||
|
||||
return shuffle(result.filter(({ user }) => user.id !== loggedInUser.id));
|
||||
}
|
||||
|
||||
const hasVotedStm = sql.prepare(hasVotedSql);
|
||||
|
||||
export function hasVoted({
|
||||
month,
|
||||
year,
|
||||
user,
|
||||
}: MonthYear & { user?: Pick<User, "id"> }) {
|
||||
if (!user) return false;
|
||||
return Boolean(
|
||||
hasVotedStm.get({
|
||||
userId: user.id,
|
||||
month,
|
||||
year,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
select
|
||||
"PlusVotingResult"."wasSuggested",
|
||||
"PlusVotingResult"."passedVoting",
|
||||
"PlusVotingResult"."tier",
|
||||
"PlusVotingResult"."score",
|
||||
"User"."id",
|
||||
"User"."discordAvatar",
|
||||
"User"."discordDiscriminator",
|
||||
"User"."discordName",
|
||||
"User"."discordId"
|
||||
from
|
||||
"PlusVotingResult"
|
||||
join "User" on "PlusVotingResult"."votedId" = "User".id
|
||||
where
|
||||
"PlusVotingResult"."month" = @month
|
||||
and "PlusVotingResult"."year" = @year
|
||||
order by
|
||||
"User"."discordName" collate nocase asc
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
update
|
||||
"User"
|
||||
set
|
||||
"patronTier" = @patronTier,
|
||||
"patronSince" = @patronSince,
|
||||
"patronTill" = null
|
||||
where
|
||||
"discordId" = @discordId
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
insert into
|
||||
"UserResultHighlight" (
|
||||
"userId",
|
||||
"teamId"
|
||||
)
|
||||
values
|
||||
(
|
||||
@userId,
|
||||
@teamId
|
||||
)
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
update
|
||||
"TournamentResult"
|
||||
set
|
||||
"isHighlight" = 1
|
||||
where
|
||||
"userId" = @userId
|
||||
and "tournamentTeamId" = @tournamentTeamId
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
insert into
|
||||
"UserWeapon" ("userId", "weaponSplId", "order", "isFavorite")
|
||||
values
|
||||
(@userId, @weaponSplId, @order, @isFavorite);
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
update
|
||||
"User"
|
||||
set
|
||||
"patronTier" = null,
|
||||
"patronSince" = null,
|
||||
"patronTill" = null
|
||||
where
|
||||
"patronTill" < @now;
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"UserResultHighlight"
|
||||
where
|
||||
"userId" = @userId
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
update
|
||||
"TournamentResult"
|
||||
set
|
||||
"isHighlight" = 0
|
||||
where
|
||||
"userId" = @userId
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"User"
|
||||
where
|
||||
id = @id returning *
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
delete from
|
||||
"UserWeapon"
|
||||
where
|
||||
"userId" = @userId;
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
insert into
|
||||
"PlusTier" ("userId", "tier")
|
||||
select
|
||||
"userId",
|
||||
"tier"
|
||||
from
|
||||
"FreshPlusTier"
|
||||
where
|
||||
"tier" is not null
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
select
|
||||
"User"."id",
|
||||
"User"."discordId",
|
||||
"User"."discordName",
|
||||
"User"."discordDiscriminator",
|
||||
"PlusTier"."tier" as "plusTier"
|
||||
from
|
||||
"User"
|
||||
left join "PlusTier" on "PlusTier"."userId" = "User"."id"
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
select
|
||||
"id",
|
||||
"discordId",
|
||||
"discordName",
|
||||
"discordDiscriminator",
|
||||
"patronTier"
|
||||
from
|
||||
"User"
|
||||
where
|
||||
"patronTier" is not null
|
||||
order by
|
||||
"patronTier" desc,
|
||||
"patronSince" asc
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
select
|
||||
"User"."discordId",
|
||||
"PlusTier"."tier" as "plusTier"
|
||||
from
|
||||
"User"
|
||||
left join "PlusTier" on "PlusTier"."userId" = "User"."id"
|
||||
where
|
||||
"PlusTier"."tier" is not null
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
select
|
||||
"User".*,
|
||||
"Team"."name" as "teamName",
|
||||
"Team"."customUrl" as "teamCustomUrl",
|
||||
"Team"."id" as "teamId",
|
||||
"UserSubmittedImage"."url" as "teamAvatarUrl",
|
||||
"PlusTier"."tier" as "plusTier",
|
||||
json_group_array(
|
||||
json_object(
|
||||
'weaponSplId',
|
||||
"UserWeapon"."weaponSplId",
|
||||
'isFavorite',
|
||||
"UserWeapon"."isFavorite"
|
||||
)
|
||||
) as "weapons"
|
||||
from
|
||||
"User"
|
||||
left join "PlusTier" on "PlusTier"."userId" = "User"."id"
|
||||
left join "UserWeapon" on "UserWeapon"."userId" = "User"."id"
|
||||
left join "TeamMember" on "TeamMember"."userId" = "User"."id"
|
||||
left join "Team" on "Team"."id" = "TeamMember"."teamId"
|
||||
left join "UserSubmittedImage" on "Team"."avatarImgId" = "UserSubmittedImage"."id"
|
||||
where
|
||||
"User"."discordId" = @identifier
|
||||
or "User"."id" = @identifier
|
||||
or "User"."customUrl" = @identifier
|
||||
order by
|
||||
"UserWeapon"."order" asc
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
update
|
||||
User
|
||||
set
|
||||
"patronTier" = @patronTier,
|
||||
"patronSince" = @patronSince,
|
||||
"patronTill" = @patronTill
|
||||
where
|
||||
"id" = @id;
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
update
|
||||
"SplatoonPlayer"
|
||||
set
|
||||
"userId" = @userId
|
||||
where
|
||||
"id" = @playerId
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
update
|
||||
"User"
|
||||
set
|
||||
"isVideoAdder" = 1
|
||||
where
|
||||
"id" = @id
|
||||
|
|
@ -1,349 +0,0 @@
|
|||
import { sql } from "../../sql";
|
||||
import type {
|
||||
CalendarEventResultTeam,
|
||||
SplatoonPlayer,
|
||||
TournamentTeam,
|
||||
User,
|
||||
UserWeapon,
|
||||
UserWithPlusTier,
|
||||
} from "../../types";
|
||||
import { parseDBJsonArray } from "~/utils/sql";
|
||||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
|
||||
import addPatronDataSql from "./addPatronData.sql";
|
||||
import addResultHighlightSql from "./addResultHighlight.sql";
|
||||
import addTournamentResultHighlightSql from "./addTournamentResultHighlight.sql";
|
||||
import deleteAllPatronDataSql from "./deleteAllPatronData.sql";
|
||||
import deleteAllResultHighlightsSql from "./deleteAllResultHighlights.sql";
|
||||
import deleteAllTournamentResultHighlightsSql from "./deleteAllTournamentResultHighlights.sql";
|
||||
import deleteByIdSql from "./deleteById.sql";
|
||||
import findAllSql from "./findAll.sql";
|
||||
import findAllPatronsSql from "./findAllPatrons.sql";
|
||||
import findAllPlusMembersSql from "./findAllPlusMembers.sql";
|
||||
import findByIdentifierSql from "./findByIdentifier.sql";
|
||||
import searchSql from "./search.sql";
|
||||
import searchExactSql from "./searchExact.sql";
|
||||
import updateByDiscordIdSql from "./updateByDiscordId.sql";
|
||||
import updateDiscordIdSql from "./updateDiscordId.sql";
|
||||
import updateProfileSql from "./updateProfile.sql";
|
||||
import upsertSql from "./upsert.sql";
|
||||
import upsertLiteSql from "./upsertLite.sql";
|
||||
import addUserWeaponSql from "./addUserWeapon.sql";
|
||||
import deleteUserWeaponsSql from "./deleteUserWeapons.sql";
|
||||
import wipePlusTiersSql from "./wipePlusTiers.sql";
|
||||
import fillPlusTiersSql from "./fillPlusTiers.sql";
|
||||
import forcePatronSql from "./forcePatron.sql";
|
||||
import makeVideoAdderSql from "./makeVideoAdder.sql";
|
||||
import linkPlayerSql from "./linkPlayer.sql";
|
||||
import unlinkPlayerSql from "./unlinkPlayer.sql";
|
||||
import { syncXPBadges } from "~/features/badges";
|
||||
|
||||
const upsertStm = sql.prepare(upsertSql);
|
||||
export function upsert(
|
||||
input: Pick<
|
||||
User,
|
||||
| "discordId"
|
||||
| "discordName"
|
||||
| "discordDiscriminator"
|
||||
| "discordAvatar"
|
||||
| "twitch"
|
||||
| "twitter"
|
||||
| "youtubeId"
|
||||
| "discordUniqueName"
|
||||
>,
|
||||
) {
|
||||
return upsertStm.get(input) as User;
|
||||
}
|
||||
|
||||
const upsertLiteStm = sql.prepare(upsertLiteSql);
|
||||
export function upsertLite(
|
||||
input: Pick<
|
||||
User,
|
||||
| "discordId"
|
||||
| "discordName"
|
||||
| "discordDiscriminator"
|
||||
| "discordAvatar"
|
||||
| "discordUniqueName"
|
||||
>,
|
||||
) {
|
||||
return upsertLiteStm.get(input) as User;
|
||||
}
|
||||
|
||||
const updateProfileStm = sql.prepare(updateProfileSql);
|
||||
const addUserWeaponStm = sql.prepare(addUserWeaponSql);
|
||||
const deleteUserWeaponsStm = sql.prepare(deleteUserWeaponsSql);
|
||||
export const updateProfile = sql.transaction(
|
||||
({
|
||||
weapons,
|
||||
...rest
|
||||
}: Pick<
|
||||
User,
|
||||
| "country"
|
||||
| "id"
|
||||
| "bio"
|
||||
| "customUrl"
|
||||
| "motionSens"
|
||||
| "stickSens"
|
||||
| "inGameName"
|
||||
| "css"
|
||||
| "favoriteBadgeId"
|
||||
| "showDiscordUniqueName"
|
||||
| "commissionText"
|
||||
| "commissionsOpen"
|
||||
> & { weapons: Pick<UserWeapon, "weaponSplId" | "isFavorite">[] }) => {
|
||||
deleteUserWeaponsStm.run({ userId: rest.id });
|
||||
for (const [i, weapon] of weapons.entries()) {
|
||||
addUserWeaponStm.run({
|
||||
userId: rest.id,
|
||||
weaponSplId: weapon.weaponSplId,
|
||||
isFavorite: weapon.isFavorite,
|
||||
order: i + 1,
|
||||
});
|
||||
}
|
||||
|
||||
return updateProfileStm.get(rest) as User;
|
||||
},
|
||||
);
|
||||
|
||||
const updateByDiscordIdStm = sql.prepare(updateByDiscordIdSql);
|
||||
export const updateMany = sql.transaction(
|
||||
(
|
||||
argsArr: Array<
|
||||
Pick<
|
||||
User,
|
||||
"discordAvatar" | "discordName" | "discordUniqueName" | "discordId"
|
||||
>
|
||||
>,
|
||||
) => {
|
||||
for (const updateArgs of argsArr) {
|
||||
updateByDiscordIdStm.run(updateArgs);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const deleteAllPatronDataStm = sql.prepare(deleteAllPatronDataSql);
|
||||
const addPatronDataStm = sql.prepare(addPatronDataSql);
|
||||
export type UpdatePatronDataArgs = Array<
|
||||
Pick<User, "discordId" | "patronTier" | "patronSince">
|
||||
>;
|
||||
export const updatePatronData = sql.transaction(
|
||||
(argsArr: UpdatePatronDataArgs) => {
|
||||
deleteAllPatronDataStm.run({ now: dateToDatabaseTimestamp(new Date()) });
|
||||
|
||||
for (const args of argsArr) {
|
||||
addPatronDataStm.run(args);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const deleteByIdStm = sql.prepare(deleteByIdSql);
|
||||
const updateDiscordIdStm = sql.prepare(updateDiscordIdSql);
|
||||
export const migrate = sql.transaction(
|
||||
(args: { newUserId: User["id"]; oldUserId: User["id"] }) => {
|
||||
const deletedUser = deleteByIdStm.get({ id: args.newUserId }) as User;
|
||||
|
||||
updateDiscordIdStm.run({
|
||||
id: args.oldUserId,
|
||||
discordId: deletedUser.discordId,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
const findByIdentifierStm = sql.prepare(findByIdentifierSql);
|
||||
export function findByIdentifier(identifier: string | number) {
|
||||
const {
|
||||
weapons,
|
||||
teamName,
|
||||
teamCustomUrl,
|
||||
teamAvatarUrl,
|
||||
teamId,
|
||||
css,
|
||||
...row
|
||||
} = findByIdentifierStm.get({ identifier }) as any;
|
||||
|
||||
if (!row.id) return;
|
||||
|
||||
return {
|
||||
...row,
|
||||
css: css ? JSON.parse(css) : undefined,
|
||||
weapons: parseDBJsonArray(weapons),
|
||||
team: teamName
|
||||
? {
|
||||
name: teamName,
|
||||
customUrl: teamCustomUrl,
|
||||
avatarUrl: teamAvatarUrl,
|
||||
id: teamId,
|
||||
}
|
||||
: undefined,
|
||||
} as
|
||||
| (Omit<UserWithPlusTier, "css"> & {
|
||||
css: Record<string, string>;
|
||||
weapons: Pick<UserWeapon, "weaponSplId" | "isFavorite">[];
|
||||
team?: {
|
||||
name: string;
|
||||
customUrl: string;
|
||||
avatarUrl?: string;
|
||||
id: number;
|
||||
};
|
||||
})
|
||||
| undefined;
|
||||
}
|
||||
|
||||
const findAllStm = sql.prepare(findAllSql);
|
||||
|
||||
export function findAll() {
|
||||
return findAllStm.all() as Pick<
|
||||
UserWithPlusTier,
|
||||
"id" | "discordId" | "discordName" | "discordDiscriminator" | "plusTier"
|
||||
>[];
|
||||
}
|
||||
|
||||
const findAllPlusMembersStm = sql.prepare(findAllPlusMembersSql);
|
||||
export function findAllPlusMembers() {
|
||||
return findAllPlusMembersStm.all() as Array<{
|
||||
discordId: User["discordId"];
|
||||
plusTier: NonNullable<UserWithPlusTier["plusTier"]>;
|
||||
}>;
|
||||
}
|
||||
|
||||
const findAllPatronsStm = sql.prepare(findAllPatronsSql);
|
||||
export type FindAllPatrons = Array<
|
||||
Pick<
|
||||
User,
|
||||
"id" | "discordId" | "discordName" | "discordDiscriminator" | "patronTier"
|
||||
>
|
||||
>;
|
||||
export function findAllPatrons() {
|
||||
return findAllPatronsStm.all() as FindAllPatrons;
|
||||
}
|
||||
|
||||
const forcePatronStm = sql.prepare(forcePatronSql);
|
||||
export function forcePatron(
|
||||
user: Pick<User, "id" | "patronSince" | "patronTill" | "patronTier">,
|
||||
) {
|
||||
forcePatronStm.run(user);
|
||||
}
|
||||
|
||||
const deleteAllResultHighlightsStm = sql.prepare(deleteAllResultHighlightsSql);
|
||||
const deleteAllTournamentResultHighlightsStm = sql.prepare(
|
||||
deleteAllTournamentResultHighlightsSql,
|
||||
);
|
||||
const addResultHighlightStm = sql.prepare(addResultHighlightSql);
|
||||
const addTournamentResultHighlightStm = sql.prepare(
|
||||
addTournamentResultHighlightSql,
|
||||
);
|
||||
export type UpdateResultHighlightsArgs = {
|
||||
userId: User["id"];
|
||||
resultTeamIds: Array<CalendarEventResultTeam["id"]>;
|
||||
resultTournamentTeamIds: Array<TournamentTeam["id"]>;
|
||||
};
|
||||
export const updateResultHighlights = sql.transaction(
|
||||
({
|
||||
userId,
|
||||
resultTeamIds,
|
||||
resultTournamentTeamIds,
|
||||
}: UpdateResultHighlightsArgs) => {
|
||||
deleteAllResultHighlightsStm.run({ userId });
|
||||
deleteAllTournamentResultHighlightsStm.run({ userId });
|
||||
for (const teamId of resultTeamIds) {
|
||||
addResultHighlightStm.run({ userId, teamId });
|
||||
}
|
||||
for (const tournamentTeamId of resultTournamentTeamIds) {
|
||||
addTournamentResultHighlightStm.run({ userId, tournamentTeamId });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const searchStm = sql.prepare(searchSql);
|
||||
export function search({ input, limit }: { input: string; limit: number }) {
|
||||
const searchString = `%${input}%`;
|
||||
|
||||
return (
|
||||
searchStm.all({
|
||||
discordName: searchString,
|
||||
inGameName: searchString,
|
||||
discordUniqueName: searchString,
|
||||
twitter: searchString,
|
||||
limit,
|
||||
}) as Array<
|
||||
Pick<
|
||||
UserWithPlusTier,
|
||||
| "id"
|
||||
| "discordId"
|
||||
| "discordAvatar"
|
||||
| "discordName"
|
||||
| "discordDiscriminator"
|
||||
| "customUrl"
|
||||
| "inGameName"
|
||||
| "discordUniqueName"
|
||||
| "showDiscordUniqueName"
|
||||
| "plusTier"
|
||||
>
|
||||
>
|
||||
).map((user) => ({
|
||||
...user,
|
||||
discordUniqueName: user.showDiscordUniqueName
|
||||
? user.discordUniqueName
|
||||
: undefined,
|
||||
}));
|
||||
}
|
||||
|
||||
const searchExactStm = sql.prepare(searchExactSql);
|
||||
export function searchExact(args: {
|
||||
discordId?: User["discordId"];
|
||||
customUrl?: User["customUrl"];
|
||||
id?: User["id"];
|
||||
}) {
|
||||
return (
|
||||
searchExactStm.all({
|
||||
discordId: args.discordId ?? null,
|
||||
customUrl: args.customUrl ?? null,
|
||||
id: args.id ?? null,
|
||||
}) as Array<
|
||||
Pick<
|
||||
UserWithPlusTier,
|
||||
| "id"
|
||||
| "discordId"
|
||||
| "discordAvatar"
|
||||
| "discordName"
|
||||
| "discordDiscriminator"
|
||||
| "customUrl"
|
||||
| "inGameName"
|
||||
| "discordUniqueName"
|
||||
| "showDiscordUniqueName"
|
||||
| "plusTier"
|
||||
>
|
||||
>
|
||||
).map((user) => ({
|
||||
...user,
|
||||
discordUniqueName: user.showDiscordUniqueName
|
||||
? user.discordUniqueName
|
||||
: undefined,
|
||||
}));
|
||||
}
|
||||
|
||||
const wipePlusTiersStm = sql.prepare(wipePlusTiersSql);
|
||||
const fillPlusTiersStm = sql.prepare(fillPlusTiersSql);
|
||||
export const refreshPlusTiers = sql.transaction(() => {
|
||||
wipePlusTiersStm.run();
|
||||
fillPlusTiersStm.run();
|
||||
});
|
||||
|
||||
const makeVideoAdderStm = sql.prepare(makeVideoAdderSql);
|
||||
export function makeVideoAdder(id: User["id"]) {
|
||||
return makeVideoAdderStm.run({ id });
|
||||
}
|
||||
|
||||
const linkPlayerStm = sql.prepare(linkPlayerSql);
|
||||
const unlinkPlayerStm = sql.prepare(unlinkPlayerSql);
|
||||
export function linkPlayer({
|
||||
userId,
|
||||
playerId,
|
||||
}: {
|
||||
userId: User["id"];
|
||||
playerId: SplatoonPlayer["id"];
|
||||
}) {
|
||||
unlinkPlayerStm.run({ userId });
|
||||
linkPlayerStm.run({ userId, playerId });
|
||||
syncXPBadges();
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
select
|
||||
"id",
|
||||
"discordName",
|
||||
"discordId",
|
||||
"discordAvatar",
|
||||
"discordDiscriminator",
|
||||
"discordUniqueName",
|
||||
"showDiscordUniqueName",
|
||||
"customUrl",
|
||||
"inGameName",
|
||||
"PlusTier"."tier" as "plusTier"
|
||||
from
|
||||
"User"
|
||||
left join "PlusTier" on "PlusTier"."userId" = "User"."id"
|
||||
where
|
||||
"discordName" like @discordName
|
||||
or "inGameName" like @inGameName
|
||||
or "discordUniqueName" like @discordUniqueName
|
||||
or "twitter" like @twitter
|
||||
order by
|
||||
case
|
||||
when "PlusTier"."tier" is null then 4
|
||||
else "PlusTier"."tier"
|
||||
end asc
|
||||
limit
|
||||
@limit
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
select
|
||||
"id",
|
||||
"discordName",
|
||||
"discordId",
|
||||
"discordAvatar",
|
||||
"discordDiscriminator",
|
||||
"discordUniqueName",
|
||||
"showDiscordUniqueName",
|
||||
"customUrl",
|
||||
"inGameName",
|
||||
"PlusTier"."tier" as "plusTier"
|
||||
from
|
||||
"User"
|
||||
left join "PlusTier" on "PlusTier"."userId" = "User"."id"
|
||||
where
|
||||
"discordId" = @discordId
|
||||
or "customUrl" = @customUrl
|
||||
or "id" = @id
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
update
|
||||
"SplatoonPlayer"
|
||||
set
|
||||
"userId" = null
|
||||
where
|
||||
"userId" = @userId
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
update
|
||||
"User"
|
||||
set
|
||||
"discordAvatar" = @discordAvatar,
|
||||
"discordName" = coalesce(@discordName, "discordName"),
|
||||
"discordUniqueName" = coalesce(@discordUniqueName, "discordUniqueName")
|
||||
where
|
||||
"discordId" = @discordId
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
update
|
||||
"User"
|
||||
set
|
||||
"discordId" = @discordId
|
||||
where
|
||||
"id" = @id
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
update
|
||||
"User"
|
||||
set
|
||||
"country" = @country,
|
||||
"bio" = @bio,
|
||||
"customUrl" = @customUrl,
|
||||
"stickSens" = @stickSens,
|
||||
"motionSens" = @motionSens,
|
||||
"inGameName" = @inGameName,
|
||||
"css" = @css,
|
||||
"favoriteBadgeId" = @favoriteBadgeId,
|
||||
"showDiscordUniqueName" = @showDiscordUniqueName,
|
||||
"commissionsOpen" = @commissionsOpen,
|
||||
"commissionText" = @commissionText
|
||||
where
|
||||
"id" = @id returning *
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
insert into
|
||||
"User" (
|
||||
"discordId",
|
||||
"discordName",
|
||||
"discordDiscriminator",
|
||||
"discordAvatar",
|
||||
"discordUniqueName",
|
||||
"twitch",
|
||||
"twitter",
|
||||
"youtubeId"
|
||||
)
|
||||
values
|
||||
(
|
||||
@discordId,
|
||||
@discordName,
|
||||
@discordDiscriminator,
|
||||
@discordAvatar,
|
||||
@discordUniqueName,
|
||||
@twitch,
|
||||
@twitter,
|
||||
@youtubeId
|
||||
) on conflict("discordId") do
|
||||
update
|
||||
set
|
||||
"discordName" = excluded."discordName",
|
||||
"discordDiscriminator" = excluded."discordDiscriminator",
|
||||
"discordAvatar" = excluded."discordAvatar",
|
||||
"discordUniqueName" = excluded."discordUniqueName",
|
||||
"twitch" = excluded."twitch",
|
||||
"twitter" = excluded."twitter",
|
||||
"youtubeId" = excluded."youtubeId" returning *
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
insert into
|
||||
"User" (
|
||||
"discordId",
|
||||
"discordName",
|
||||
"discordDiscriminator",
|
||||
"discordAvatar",
|
||||
"discordUniqueName"
|
||||
)
|
||||
values
|
||||
(
|
||||
@discordId,
|
||||
@discordName,
|
||||
@discordDiscriminator,
|
||||
@discordAvatar,
|
||||
@discordUniqueName
|
||||
) on conflict("discordId") do
|
||||
update
|
||||
set
|
||||
"discordName" = excluded."discordName",
|
||||
"discordDiscriminator" = excluded."discordDiscriminator",
|
||||
"discordAvatar" = excluded."discordAvatar",
|
||||
"discordUniqueName" = excluded."discordUniqueName" returning *
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user