Unify db type files
Some checks failed
Tests and checks on push / run-checks-and-tests (push) Has been cancelled
Updates translation progress / update-translation-progress-issue (push) Has been cancelled

This commit is contained in:
Kalle 2025-03-21 21:47:08 +02:00
parent 3d5de9e44a
commit c0ec15b7de
115 changed files with 602 additions and 1145 deletions

View File

@ -1,6 +1,6 @@
import clsx from "clsx";
import * as React from "react";
import type { User } from "~/db/types";
import type { Tables } from "~/db/tables";
import { BLANK_IMAGE_URL, discordAvatarUrl } from "~/utils/urls";
const dimensions = {
@ -21,7 +21,7 @@ function _Avatar({
alt = "",
...rest
}: {
user?: Pick<User, "discordId" | "discordAvatar">;
user?: Pick<Tables["User"], "discordId" | "discordAvatar">;
url?: string;
className?: string;
alt?: string;

View File

@ -1,12 +1,7 @@
import clsx from "clsx";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import type {
Build,
BuildWeapon,
GearType,
UserWithPlusTier,
} from "~/db/types";
import type { GearType, Tables, UserWithPlusTier } from "~/db/tables";
import { useUser } from "~/features/auth/core/user";
import type { BuildWeaponWithTop500Info } from "~/features/builds/queries/buildsBy.server";
import { useIsMounted } from "~/hooks/useIsMounted";
@ -41,7 +36,7 @@ import { TrashIcon } from "./icons/Trash";
interface BuildProps {
build: Pick<
Build,
Tables["Build"],
| "id"
| "title"
| "description"
@ -55,7 +50,7 @@ interface BuildProps {
unsortedAbilities: BuildAbilitiesTuple;
modes: ModeShort[] | null;
weapons: Array<{
weaponSplId: BuildWeapon["weaponSplId"];
weaponSplId: Tables["BuildWeapon"]["weaponSplId"];
minRank: number | null;
maxPower: number | null;
}>;

View File

@ -3,7 +3,7 @@ import clsx from "clsx";
import Fuse, { type IFuseOptions } from "fuse.js";
import * as React from "react";
import { useTranslation } from "react-i18next";
import type { GearType } from "~/db/types";
import type { GearType } from "~/db/tables";
import type { SerializedMapPoolEvent } from "~/features/calendar/routes/map-pool-events";
import { useAllEventsWithMapPools } from "~/hooks/swr";
import type { MainWeaponId } from "~/modules/in-game-lists";

View File

@ -3,7 +3,7 @@ import * as React from "react";
import { useTranslation } from "react-i18next";
import { Button } from "~/components/Button";
import { Image } from "~/components/Image";
import type { CalendarEvent } from "~/db/types";
import type { Tables } from "~/db/tables";
import type { SerializedMapPoolEvent } from "~/features/calendar/routes/map-pool-events";
import { MapPool } from "~/features/map-list-generator/core/map-pool";
import { BANNED_MAPS } from "~/features/sendouq-settings/banned-maps";
@ -26,11 +26,11 @@ export type MapPoolSelectorProps = {
handleRemoval?: () => void;
handleMapPoolChange: (
mapPool: MapPool,
event?: Pick<CalendarEvent, "id" | "name">,
event?: Pick<Tables["CalendarEvent"], "id" | "name">,
) => void;
className?: string;
recentEvents?: SerializedMapPoolEvent[];
initialEvent?: Pick<CalendarEvent, "id" | "name">;
initialEvent?: Pick<Tables["CalendarEvent"], "id" | "name">;
title?: string;
modesToInclude?: ModeShort[];
info?: React.ReactNode;
@ -376,7 +376,7 @@ function detectTemplate(mapPool: MapPool): MapPoolTemplateValue {
type MapPoolTemplateSelectProps = {
value: MapPoolTemplateValue;
handleChange: (newValue: MapPoolTemplateValue) => void;
recentEvents?: Pick<CalendarEvent, "id" | "name">[];
recentEvents?: Pick<Tables["CalendarEvent"], "id" | "name">[];
};
function MapPoolTemplateSelect({
@ -428,7 +428,7 @@ function MapPoolTemplateSelect({
type TemplateEventSelectionProps = {
handleEventChange: (
mapPool: MapPool,
event?: Pick<CalendarEvent, "id" | "name">,
event?: Pick<Tables["CalendarEvent"], "id" | "name">,
) => void;
initialEvent?: SerializedMapPoolEvent;
};

View File

@ -71,7 +71,6 @@ import { dateToDatabaseTimestamp } from "~/utils/dates";
import invariant from "~/utils/invariant";
import { mySlugify } from "~/utils/urls";
import type { Tables, UserMapModePreferences } from "../tables";
import type { Art, UserSubmittedImage } from "../types";
import {
ADMIN_TEST_AVATAR,
AMOUNT_OF_CALENDAR_EVENTS,
@ -1950,12 +1949,12 @@ function arts() {
validatedAt: dateToDatabaseTimestamp(new Date()),
url: getUrl(),
submitterUserId: userId,
}) as UserSubmittedImage
}) as Tables["UserSubmittedImage"]
).id,
authorId: userId,
isShowcase: i === 0 ? 1 : 0,
description: Math.random() > 0.5 ? faker.lorem.paragraph() : null,
}) as Art;
}) as Tables["Art"];
if (i === 1) {
for (
@ -2204,7 +2203,7 @@ async function playedMatches() {
skills: newSkills,
differences,
groupMatchId: match.id,
oldMatchMemento: { users: {}, groups: {} },
oldMatchMemento: { users: {}, groups: {}, pools: [] },
});
setGroupAsInactive(groupAlpha);
setGroupAsInactive(groupBravo);

View File

@ -6,6 +6,10 @@ import type {
SqlBool,
Updateable,
} from "kysely";
import type {
persistedTags,
tags,
} from "~/features/calendar/calendar-constants";
import type { TieredSkill } from "~/features/mmr/tiered.server";
import type { Notification as NotificationValue } from "~/features/notifications/notifications-types";
import type { TEAM_MEMBER_ROLES } from "~/features/team/team-constants";
@ -17,7 +21,6 @@ import type {
ModeShort,
StageId,
} from "~/modules/in-game-lists";
import type { GroupSkillDifference, UserSkillDifference } from "./types";
export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
? ColumnType<S, I | undefined, U>
@ -103,10 +106,12 @@ export interface Build {
updatedAt: Generated<number>;
}
export type GearType = "HEAD" | "CLOTHES" | "SHOES";
export interface BuildAbility {
ability: Ability;
buildId: number;
gearType: string;
gearType: GearType;
slotIndex: number;
}
@ -121,6 +126,9 @@ export type CalendarEventAvatarMetadata = {
textColor: string;
};
export type PersistedCalendarEventTag = keyof typeof persistedTags;
export type CalendarEventTag = keyof typeof tags;
export interface CalendarEvent {
authorId: number;
bracketUrl: string;
@ -189,6 +197,27 @@ export interface GroupLike {
isRechallenge: number | null;
}
type CalculatingSkill = {
calculated: false;
matchesCount: number;
matchesCountNeeded: number;
/** Freshly calculated skill */
newSp?: number;
};
export type UserSkillDifference =
| {
calculated: true;
spDiff: number;
}
| CalculatingSkill;
export type GroupSkillDifference =
| {
calculated: true;
oldSp: number;
newSp: number;
}
| CalculatingSkill;
export type ParsedMemento = {
users: Record<
number,
@ -359,7 +388,7 @@ export interface PlusVotingResult {
export interface ReportedWeapon {
groupMatchMapId: number | null;
userId: number;
weaponSplId: number;
weaponSplId: MainWeaponId;
}
export interface Skill {
@ -492,6 +521,23 @@ export interface TournamentGroup {
stageId: number;
}
export const TournamentMatchStatus = {
/** The two matches leading to this one are not completed yet. */
Locked: 0,
/** One participant is ready and waiting for the other one. */
Waiting: 1,
/** Both participants are ready to start. */
Ready: 2,
/** The match is running. */
Running: 3,
/** The match is completed. */
Completed: 4,
};
export interface TournamentMatch {
// TODO: remove
bestOf: Generated<3 | 5 | 7>;
@ -503,7 +549,7 @@ export interface TournamentMatch {
opponentTwo: ColumnType<ParticipantResult, string, string>;
roundId: number;
stageId: number;
status: number;
status: (typeof TournamentMatchStatus)[keyof typeof TournamentMatchStatus];
// used only for swiss because it's the only stage type where matches are not created in advance
createdAt: Generated<number>;
}
@ -807,6 +853,11 @@ export interface User {
preferences: ColumnType<UserPreferences | null, string | null, string | null>;
}
/** Represents User joined with PlusTier table */
export type UserWithPlusTier = Tables["User"] & {
plusTier: PlusTier["tier"] | null;
};
export interface UserResultHighlight {
teamId: number;
userId: number;
@ -815,7 +866,7 @@ export interface UserResultHighlight {
export interface UserSubmittedImage {
id: GeneratedAlways<number>;
submitterUserId: number | null;
url: string | null;
url: string;
validatedAt: number | null;
}
@ -837,12 +888,12 @@ export interface UserFriendCode {
export interface Video {
eventId: number | null;
id: GeneratedAlways<number>;
submitterUserId: number | null;
title: string | null;
type: string | null;
submitterUserId: number;
title: string;
type: "SCRIM" | "TOURNAMENT" | "MATCHMAKING" | "CAST" | "SENDOUQ";
validatedAt: number | null;
youtubeDate: number | null;
youtubeId: string | null;
youtubeDate: number;
youtubeId: string;
}
export interface VideoMatch {
@ -872,7 +923,7 @@ export interface XRankPlacement {
playerId: number;
power: number;
rank: number;
region: string;
region: "WEST" | "JPN";
title: string;
weaponSplId: MainWeaponId;
year: number;

View File

@ -1,602 +0,0 @@
import type {
persistedTags,
tags,
} from "~/features/calendar/calendar-constants";
import type { TieredSkill } from "~/features/mmr/tiered.server";
import type { TEAM_MEMBER_ROLES } from "~/features/team/team-constants";
import type {
Ability,
MainWeaponId,
ModeShort,
RankedModeShort,
StageId,
} from "~/modules/in-game-lists";
export interface User {
id: number;
discordId: string;
/** Discord display name aka global name (non-unique) */
discordName: string;
username: string;
discordAvatar: string | null;
/** Discord username (unique) */
discordUniqueName: string | null;
showDiscordUniqueName: number;
twitch: string | null;
youtubeId: string | null;
bio: string | null;
css: string | null;
country: string | null;
customUrl: string | null;
stickSens: number | null;
motionSens: number | null;
inGameName: string | null;
patronTier: number | null;
patronSince: number | null;
/** Used to overwrite normal patron giving process and force give the patron status till this date */
patronTill: number | null;
isVideoAdder: number;
isArtist: number;
favoriteBadgeId: number | null;
commissionsOpen: number;
commissionText: string | null;
banned: number;
vc: "YES" | "NO" | "LISTEN_ONLY";
languages: string | null;
}
/** User table after joined with PlusTier table */
export interface UserWithPlusTier extends User {
plusTier: PlusTier["tier"] | null;
}
export interface UserWeapon {
userId: number;
weaponSplId: MainWeaponId;
createdAt: number;
order: number;
isFavorite: number;
}
export interface LogInLink {
code: string;
expiresAt: number;
userId: number;
}
export interface PlusSuggestion {
id: number;
text: string;
authorId: number;
suggestedId: number;
month: number;
year: number;
tier: number;
createdAt: number;
}
export interface PlusVote {
month: number;
year: number;
tier: number;
authorId: number;
votedId: number;
score: number;
validAfter: number;
}
export interface PlusVotingResult {
votedId: number;
tier: number;
score: number;
month: number;
year: number;
wasSuggested: number;
passedVoting: number;
}
export interface PlusTier {
userId: number;
tier: number;
}
export interface Badge {
id: number;
code: string;
displayName: string;
hue?: number;
}
/** View that is union of TournamentBadgeOwner and Patreon badges */
export interface BadgeOwner {
badgeId: number;
userId: number;
}
export interface TournamentBadgeOwner {
badgeId: number;
userId: number;
}
export interface BadgeManager {
badgeId: number;
userId: number;
}
export interface CalendarEvent {
id: number;
name: string;
authorId: number;
tags: string | null;
description: string | null;
discordInviteCode: string | null;
// generated column
discordUrl: string | null;
bracketUrl: string;
participantCount: number | null;
tournamentId: number | null;
}
export type PersistedCalendarEventTag = keyof typeof persistedTags;
export type CalendarEventTag = keyof typeof tags;
export interface CalendarEventDate {
id: number;
eventId: number;
startTime: number;
}
export interface CalendarEventResultTeam {
id: number;
eventId: number;
name: string;
placement: number;
}
export interface CalendarEventResultPlayer {
teamId: number;
userId: number | null;
name: string | null;
}
export interface UserResultHighlight {
teamId: number;
userId: number;
}
export interface CalendarEventBadge {
eventId: number;
badgeId: number;
}
export interface Build {
id: number;
ownerId: number;
title: string;
/** Private builds are only visible on the user builds page to the owner only */
private: number | null;
description: string | null;
modes: string | null;
headGearSplId: number;
clothesGearSplId: number;
shoesGearSplId: number;
updatedAt: number;
}
export interface BuildWeapon {
buildId: number;
weaponSplId: MainWeaponId;
}
export type GearType = "HEAD" | "CLOTHES" | "SHOES";
export interface BuildAbility {
buildId: number;
gearType: "HEAD" | "CLOTHES" | "SHOES";
ability: Ability;
slotIndex: 0 | 1 | 2 | 3;
abilityPoints: number; // 3 or 10
}
export interface MapPoolMap {
calendarEventId: number | null; // Part of tournament's map pool
tournamentTeamId: number | null; // Part of team's map pool
tieBreakerCalendarEventId: number | null; // Part of the tournament's tiebreaker pool
stageId: StageId;
mode: ModeShort;
}
// AUTO = style where teams pick their map pool ahead of time and the map lists are automatically made for each round
// could also have the traditional style where TO picks the maps later
type TournamentMapPickingStyle =
| "AUTO_ALL"
| "AUTO_SZ"
| "AUTO_TC"
| "AUTO_RM"
| "AUTO_CB";
// TODO: later also e.g. RR_TO_DE where we also need an additional field
// describing how many teams advance
export type TournamentFormat = "SE" | "DE";
export interface Tournament {
id: number;
mapPickingStyle: TournamentMapPickingStyle;
format: TournamentFormat;
}
export interface TournamentTeam {
id: number;
name: string;
createdAt: number;
seed: number | null;
tournamentId: number;
inviteCode: string;
prefersNotToHost: number;
}
export interface TournamentTeamCheckIn {
tournamentTeamId: number;
checkedInAt: number;
}
export interface TournamentTeamMember {
tournamentTeamId: number;
userId: number;
isOwner: number;
createdAt: number;
}
/** A stage is an intermediate phase in a tournament.
* Supported stage types are round-robin, single elimination and double elimination. */
export interface TournamentStage {
id: number;
tournamentId: number;
name: string;
type: "round_robin" | "single_elimination" | "double_elimination";
settings: string; // json
number: number;
createdAt: number | null;
}
/** A group is a logical structure used to group multiple rounds together.
- In round-robin stages, a group is a pool.
- In elimination stages, a group is a bracket.
- A single elimination stage can have one or two groups:
- The unique bracket.
- If enabled, the Consolation Final.
- A double elimination stage can have two or three groups:
- Upper and lower brackets.
- If enabled, the Grand Final. */
export interface TournamentGroup {
id: number;
stageId: number;
/** In double elimination 1 = Winners, 2 = Losers, 3 = Grand Finals+Bracket Reset */
number: number;
}
/**
* A round is a logical structure used to group multiple matches together.
- In round-robin stages, a round can be viewed as a day or just as a list of matches that can be played at the same time.
- In elimination stages, a round is a round of a bracket, e.g. 8th finals, semi-finals, etc.
*/
export interface TournamentRound {
id: number;
stageId: number;
groupId: number;
number: number;
}
export enum Status {
/** The two matches leading to this one are not completed yet. */
Locked = 0,
/** One participant is ready and waiting for the other one. */
Waiting = 1,
/** Both participants are ready to start. */
Ready = 2,
/** The match is running. */
Running = 3,
/** The match is completed. */
Completed = 4,
}
/** A match between two participants (more participants are not allowed).
* Participants can be teams or individuals. */
export interface TournamentMatch {
id: number;
bestOf: 3 | 5 | 7;
roundId: number;
stageId: number;
groupId: number;
number: number;
opponentOne: string; // json
opponentTwo: string; // json
status: Status;
chatCode: string | null;
}
export interface TournamentMatchGameResult {
id: number;
matchId: number;
number: number;
stageId: StageId;
mode: ModeShort;
/** serialized TournamentMaplistSource */
source: string;
winnerTeamId: number;
reporterId: number;
createdAt: number;
}
export interface TournamentMatchGameResultParticipant {
matchGameResultId: number;
userId: number;
}
export interface TournamentSub {
userId: number;
tournamentId: number;
canVc: number;
bestWeapons: string;
okWeapons: string | null;
message: string | null;
visibility: "+1" | "+2" | "+3" | "ALL";
createdAt: number;
}
export interface Skill {
id: number;
mu: number;
sigma: number;
ordinal: number;
userId: number | null;
/** e.g. 12-24-44-1024 for "team skills" */
identifier: string | null;
matchesCount: number;
/** Tournament that caused the skill to change */
tournamentId: number | null;
/** Group match that caused the skill to change */
groupMatchId: number | null;
season: number;
}
export interface SkillTeamUser {
userId: number;
skillId: number;
}
export interface MapResult {
mode: ModeShort;
stageId: StageId;
userId: number;
wins: number;
losses: number;
season: number;
}
export interface PlayerResult {
ownerUserId: number;
otherUserId: number;
mapWins: number;
mapLosses: number;
setWins: number;
setLosses: number;
type: "MATE" | "ENEMY";
season: number;
}
export interface TournamentResult {
tournamentId: number;
userId: number;
placement: number;
participantCount: number;
tournamentTeamId: number;
isHighlight: number;
}
export interface TrustRelationship {
trustGiverUserId: number;
trustReceiverUserId: number;
}
export interface UserSubmittedImage {
id: number;
validatedAt: number | null;
url: string;
submitterUserId: number;
}
export interface Team {
id: number;
name: string;
customUrl: string;
inviteCode: string;
css: string | null;
bio: string | null;
avatarImgId: number | null;
bannerImgId: number | null;
createdAt: number;
deletedAt: number | null;
}
export type MemberRole = (typeof TEAM_MEMBER_ROLES)[number];
export interface TeamMember {
teamId: number;
userId: number;
role: MemberRole | null;
isOwner: number;
createdAt: number;
leftAt: number | null;
}
export interface Video {
id: number;
title: string;
type: "SCRIM" | "TOURNAMENT" | "MATCHMAKING" | "CAST" | "SENDOUQ";
youtubeDate: number;
eventId: number | null;
youtubeId: string;
submitterUserId: number;
validatedAt: number | null;
}
export interface VideoMatch {
id: number;
videoId: number;
startsAt: number;
stageId: StageId;
mode: ModeShort;
}
export interface VideoMatchPlayer {
videoMatchId: number;
playerUserId: number | null;
playerName: string | null;
weaponSplId: MainWeaponId;
player: number;
}
export interface XRankPlacement {
id: number;
weaponSplId: MainWeaponId;
name: string;
nameDiscriminator: string;
power: number;
rank: number;
title: string;
badges: string; // badge id's separated by comma
bannerSplId: number;
playerId: number;
month: number;
year: number;
mode: RankedModeShort;
region: "WEST" | "JPN";
}
export interface SplatoonPlayer {
id: number;
userId: number;
splId: string;
}
export interface Art {
id: number;
imgId: number;
authorId: number;
isShowcase: number;
description: string | null;
createdAt: number;
}
export interface ArtTag {
id: number;
name: string;
authorId: number;
createdAt: number;
}
export interface TaggedArt {
artId: number;
tagId: number;
}
export interface ArtUserMetadata {
artId: number;
userId: number;
}
export interface Group {
id: number;
teamId: number | null;
createdAt: number;
latestActionAt: number;
inviteCode: string;
chatCode: string | null;
status: "PREPARING" | "ACTIVE" | "INACTIVE";
}
export interface GroupMember {
groupId: number;
userId: number;
role: "OWNER" | "MANAGER" | "REGULAR";
note: string | null;
createdAt: number;
}
export interface GroupLike {
likerGroupId: number;
targetGroupId: number;
createdAt: number;
}
type CalculatingSkill = {
calculated: false;
matchesCount: number;
matchesCountNeeded: number;
/** Freshly calculated skill */
newSp?: number;
};
export type UserSkillDifference =
| {
calculated: true;
spDiff: number;
}
| CalculatingSkill;
export type GroupSkillDifference =
| {
calculated: true;
oldSp: number;
newSp: number;
}
| CalculatingSkill;
export type ParsedMemento = {
users: Record<
User["id"],
{
plusTier?: PlusTier["tier"];
skill?: TieredSkill;
skillDifference?: UserSkillDifference;
}
>;
groups: Record<
Group["id"],
{
tier?: TieredSkill["tier"];
skillDifference?: GroupSkillDifference;
}
>;
};
export interface GroupMatch {
id: number;
alphaGroupId: number;
bravoGroupId: number;
createdAt: number;
reportedAt: number | null;
reportedByUserId: number | null;
chatCode: string | null;
memento: string | null;
}
export interface GroupMatchMap {
id: number;
matchId: number;
index: number;
mode: ModeShort;
stageId: StageId;
/** serialized TournamentMaplistSource */
source: string;
winnerGroupId: number | null;
}
export interface ReportedWeapon {
groupMatchMapId: number | null;
weaponSplId: MainWeaponId;
userId: User["id"];
}

View File

@ -1,21 +1,21 @@
import type { Art, User, UserSubmittedImage } from "~/db/types";
import type { Tables } from "~/db/tables";
export interface ListedArt {
id: Art["id"];
createdAt: Art["createdAt"];
url: UserSubmittedImage["url"];
description?: Art["description"];
id: Tables["Art"]["id"];
createdAt: Tables["Art"]["createdAt"];
url: Tables["UserSubmittedImage"]["url"];
description?: Tables["Art"]["description"];
tags?: string[];
linkedUsers?: Array<{
discordId: User["discordId"];
username: User["username"];
customUrl: User["customUrl"];
discordId: Tables["User"]["discordId"];
username: Tables["User"]["username"];
customUrl: Tables["User"]["customUrl"];
}>;
author?: {
discordId: User["discordId"];
username: User["username"];
discordAvatar: User["discordAvatar"];
commissionsOpen?: User["commissionsOpen"];
discordId: Tables["User"]["discordId"];
username: Tables["User"]["username"];
discordAvatar: Tables["User"]["discordAvatar"];
commissionsOpen?: Tables["User"]["commissionsOpen"];
};
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { Art, ArtTag, UserSubmittedImage } from "~/db/types";
import type { Tables } from "~/db/tables";
import invariant from "~/utils/invariant";
const addImgStm = sql.prepare(/* sql */ `
@ -92,9 +92,9 @@ const removeUserMetadataStm = sql.prepare(/* sql */ `
"artId" = @artId
`);
type TagsToAdd = Array<Partial<Pick<ArtTag, "name" | "id">>>;
type AddNewArtArgs = Pick<Art, "authorId" | "description"> &
Pick<UserSubmittedImage, "url" | "validatedAt"> & {
type TagsToAdd = Array<Partial<Pick<Tables["ArtTag"], "name" | "id">>>;
type AddNewArtArgs = Pick<Tables["Art"], "authorId" | "description"> &
Pick<Tables["UserSubmittedImage"], "url" | "validatedAt"> & {
linkedUsers: number[];
tags: TagsToAdd;
};
@ -104,12 +104,12 @@ export const addNewArt = sql.transaction((args: AddNewArtArgs) => {
authorId: args.authorId,
url: args.url,
validatedAt: args.validatedAt,
}) as UserSubmittedImage;
}) as Tables["UserSubmittedImage"];
const art = addArtStm.get({
authorId: args.authorId,
description: args.description,
imgId: img.id,
}) as Art;
}) as Tables["Art"];
for (const userId of args.linkedUsers) {
addArtUserMetadataStm.run({ artId: art.id, userId });
@ -123,7 +123,7 @@ export const addNewArt = sql.transaction((args: AddNewArtArgs) => {
const newTag = addArtTagStm.get({
name: tag.name,
authorId: args.authorId,
}) as ArtTag;
}) as Tables["ArtTag"];
tagId = newTag.id;
}
@ -133,7 +133,10 @@ export const addNewArt = sql.transaction((args: AddNewArtArgs) => {
return art.id;
});
type EditArtArgs = Pick<Art, "authorId" | "description" | "isShowcase"> & {
type EditArtArgs = Pick<
Tables["Art"],
"authorId" | "description" | "isShowcase"
> & {
linkedUsers: number[];
artId: number;
tags: TagsToAdd;
@ -166,7 +169,7 @@ export const editArt = sql.transaction((args: EditArtArgs) => {
const newTag = addArtTagStm.get({
name: tag.name,
authorId: args.authorId,
}) as ArtTag;
}) as Tables["ArtTag"];
tagId = newTag.id;
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { ArtTag } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
select
@ -9,6 +9,6 @@ const stm = sql.prepare(/* sql */ `
"ArtTag"
`);
export function allArtTags(): Array<Pick<ArtTag, "id" | "name">> {
export function allArtTags(): Array<Pick<Tables["ArtTag"], "id" | "name">> {
return stm.all() as any;
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { Art, ArtTag, User, UserSubmittedImage } from "~/db/types";
import type { Tables } from "~/db/tables";
import { parseDBArray } from "~/utils/sql";
const findArtStm = sql.prepare(/* sql */ `
@ -26,12 +26,12 @@ const findTagsStm = sql.prepare(/* sql */ `
`);
interface FindArtById {
isShowcase: Art["isShowcase"];
description: Art["description"];
url: UserSubmittedImage["url"];
authorId: Art["authorId"];
linkedUsers: User["id"][];
tags: Array<Pick<ArtTag, "id" | "name">>;
isShowcase: Tables["Art"]["isShowcase"];
description: Tables["Art"]["description"];
url: Tables["UserSubmittedImage"]["url"];
authorId: Tables["Art"]["authorId"];
linkedUsers: Tables["User"]["id"][];
tags: Array<Pick<Tables["ArtTag"], "id" | "name">>;
}
export function findArtById(artId: number): FindArtById | null {

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { ArtTag } from "~/db/types";
import type { Tables } from "~/db/tables";
import type { ListedArt } from "../art-types";
const showcaseArtsStm = sql.prepare(/* sql */ `
@ -55,7 +55,7 @@ const showcaseArtsByTagStm = sql.prepare(/* sql */ `
`);
export function showcaseArtsByTag(tagId: ArtTag["id"]): ListedArt[] {
export function showcaseArtsByTag(tagId: Tables["ArtTag"]["id"]): ListedArt[] {
const encounteredUserIds = new Set<number>();
return showcaseArtsByTagStm

View File

@ -1,5 +1,5 @@
import { redirect } from "@remix-run/node";
import type { User } from "~/db/types";
import type { Tables } from "~/db/tables";
import { userIsBanned } from "~/features/ban/core/banned.server";
import * as UserRepository from "~/features/user-page/UserRepository.server";
import { SUSPENDED_PAGE } from "~/utils/urls";
@ -9,7 +9,7 @@ import { authSessionStorage } from "./session.server";
export async function getUserId(
request: Request,
redirectIfBanned = true,
): Promise<Pick<User, "id"> | undefined> {
): Promise<Pick<Tables["User"], "id"> | undefined> {
const session = await authSessionStorage.getSession(
request.headers.get("Cookie"),
);

View File

@ -1,6 +1,6 @@
import { nanoid } from "nanoid";
import { sql } from "~/db/sql";
import type { LogInLink } from "~/db/types";
import type { Tables } from "~/db/tables";
import { dateToDatabaseTimestamp } from "~/utils/dates";
const stm = sql.prepare(/* sql */ `
@ -26,5 +26,5 @@ export function createLogInLink(userId: number) {
new Date(Date.now() + LOG_IN_LINK_VALID_FOR),
),
code: nanoid(LOG_IN_LINK_LENGTH),
}) as LogInLink;
}) as Tables["LogInLink"];
}

View File

@ -1,10 +1,10 @@
import type { TFunction } from "i18next";
import { SPLATOON_3_XP_BADGE_VALUES } from "~/constants";
import type { Badge as BadgeDBType } from "~/db/types";
import type { Tables } from "~/db/tables";
export function badgeExplanationText(
t: TFunction<"badges", undefined>,
badge: Pick<BadgeDBType, "displayName" | "code"> & { count?: number },
badge: Pick<Tables["Badge"], "displayName" | "code"> & { count?: number },
) {
if (badge.code === "patreon") return t("patreon");
if (badge.code === "patreon_plus") {

View File

@ -8,7 +8,7 @@ import { Dialog } from "~/components/Dialog";
import { Label } from "~/components/Label";
import { UserSearch } from "~/components/UserSearch";
import { TrashIcon } from "~/components/icons/Trash";
import type { User } from "~/db/types";
import type { Tables } from "~/db/tables";
import { useUser } from "~/features/auth/core/user";
import { requireUserId } from "~/features/auth/core/user.server";
import { notify } from "~/features/notifications/core/notify.server";
@ -321,7 +321,7 @@ function getOwnerDifferences(
oldOwners: BadgeRepository.FindOwnersByBadgeIdItem[],
) {
const result: Array<{
id: User["id"];
id: Tables["User"]["id"];
type: "added" | "removed";
difference: number;
username: string;
@ -353,7 +353,7 @@ function getOwnerDifferences(
}
function countArrayToDuplicatedIdsArray(
owners: Array<{ id: User["id"]; count: number }>,
owners: Array<{ id: Tables["User"]["id"]; count: number }>,
) {
return owners.flatMap((o) => new Array(o.count).fill(null).map(() => o.id));
}

View File

@ -1,10 +1,5 @@
import { sql } from "~/db/sql";
import type {
Build,
BuildAbility,
BuildWeapon,
UserWithPlusTier,
} from "~/db/types";
import type { Tables, UserWithPlusTier } from "~/db/tables";
import { type ModeShort, weaponIdToAltId } from "~/modules/in-game-lists";
import type {
BuildAbilitiesTuple,
@ -120,7 +115,7 @@ export function buildsByWeaponId({
weaponId,
limit,
}: {
weaponId: BuildWeapon["weaponSplId"];
weaponId: Tables["BuildWeapon"]["weaponSplId"];
limit: number;
}) {
const [altWeaponId, altWeaponIdTwo] = (() => {
@ -144,17 +139,17 @@ export function buildsByWeaponId({
}
type BuildsByUserRow = Pick<
Build,
Tables["Build"],
| "id"
| "title"
| "description"
| "modes"
| "headGearSplId"
| "clothesGearSplId"
| "shoesGearSplId"
| "updatedAt"
| "private"
> & {
modes: string;
weapons: string;
abilities: string;
};
@ -170,14 +165,14 @@ function augmentBuild<T>({
modes: rawModes,
abilities: rawAbilities,
...row
}: T & { modes: Build["modes"]; weapons: string; abilities: string }) {
}: T & { modes: string; weapons: string; abilities: string }) {
const modes = rawModes ? (JSON.parse(rawModes) as ModeShort[]) : null;
const weapons = (
JSON.parse(rawWeapons) as Array<BuildWeaponWithTop500Info>
).sort((a, b) => a.weaponSplId - b.weaponSplId);
const abilities = dbAbilitiesToArrayOfArrays(
JSON.parse(rawAbilities) as Array<
Pick<BuildAbility, "ability" | "gearType" | "slotIndex">
Pick<Tables["BuildAbility"], "ability" | "gearType" | "slotIndex">
>,
);
@ -190,9 +185,15 @@ function augmentBuild<T>({
};
}
const gearOrder: Array<BuildAbility["gearType"]> = ["HEAD", "CLOTHES", "SHOES"];
const gearOrder: Array<Tables["BuildAbility"]["gearType"]> = [
"HEAD",
"CLOTHES",
"SHOES",
];
function dbAbilitiesToArrayOfArrays(
abilities: Array<Pick<BuildAbility, "ability" | "gearType" | "slotIndex">>,
abilities: Array<
Pick<Tables["BuildAbility"], "ability" | "gearType" | "slotIndex">
>,
): BuildAbilitiesTuple {
const sorted = abilities
.slice()

View File

@ -2,8 +2,13 @@ import type { Expression, ExpressionBuilder, Transaction } from "kysely";
import { sql } from "kysely";
import { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite";
import { db } from "~/db/sql";
import type { DB, Tables, TournamentSettings } from "~/db/tables";
import type { CalendarEventTag, PersistedCalendarEventTag } from "~/db/types";
import type {
CalendarEventTag,
DB,
PersistedCalendarEventTag,
Tables,
TournamentSettings,
} from "~/db/tables";
import { MapPool } from "~/features/map-list-generator/core/map-pool";
import * as Progression from "~/features/tournament-bracket/core/Progression";
import { databaseTimestampNow, dateToDatabaseTimestamp } from "~/utils/dates";

View File

@ -1,8 +1,11 @@
import type { ActionFunction } from "@remix-run/node";
import { redirect } from "@remix-run/node";
import { z } from "zod";
import { TOURNAMENT_STAGE_TYPES } from "~/db/tables";
import type { CalendarEventTag, PersistedCalendarEventTag } from "~/db/types";
import {
type CalendarEventTag,
type PersistedCalendarEventTag,
TOURNAMENT_STAGE_TYPES,
} from "~/db/tables";
import { requireUser } from "~/features/auth/core/user.server";
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
import * as ShowcaseTournaments from "~/features/front-page/core/ShowcaseTournaments.server";

View File

@ -1,4 +1,4 @@
import type { CalendarEventTag, PersistedCalendarEventTag } from "~/db/types";
import type { CalendarEventTag, PersistedCalendarEventTag } from "~/db/tables";
export const persistedTags = {
SPECIAL: {

View File

@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
import { Badge } from "~/components/Badge";
import { Button } from "~/components/Button";
import { CrossIcon } from "~/components/icons/Cross";
import type { CalendarEventTag } from "~/db/types";
import type { CalendarEventTag } from "~/db/tables";
import type * as CalendarRepository from "../CalendarRepository.server";
import { tags as allTags } from "../calendar-constants";

View File

@ -19,8 +19,7 @@ import { RequiredHiddenInput } from "~/components/RequiredHiddenInput";
import { SubmitButton } from "~/components/SubmitButton";
import { CrossIcon } from "~/components/icons/Cross";
import { TrashIcon } from "~/components/icons/Trash";
import type { Tables } from "~/db/tables";
import type { Badge as BadgeType, CalendarEventTag } from "~/db/types";
import type { CalendarEventTag, Tables } from "~/db/tables";
import { useUser } from "~/features/auth/core/user";
import { MapPool } from "~/features/map-list-generator/core/map-pool";
import * as Progression from "~/features/tournament-bracket/core/Progression";
@ -641,7 +640,7 @@ function BadgesAdder() {
if (managedBadges.length === 0) return input;
const handleBadgeDelete = (badgeId: BadgeType["id"]) => {
const handleBadgeDelete = (badgeId: Tables["Badge"]["id"]) => {
setBadges(badges.filter((badge) => badge.id !== badgeId));
};

View File

@ -43,10 +43,6 @@ import {
} from "~/utils/urls";
import { actualNumber, safeSplit } from "~/utils/zod";
import { Label } from "../../../components/Label";
import type {
CalendarEventTag,
PersistedCalendarEventTag,
} from "../../../db/types";
import { metaTags } from "../../../utils/remix";
import * as CalendarRepository from "../CalendarRepository.server";
import { calendarEventTagSchema } from "../actions/calendar.new.server";
@ -55,6 +51,7 @@ import { closeByWeeks } from "../calendar-utils";
import { Tags } from "../components/Tags";
import "~/styles/calendar.css";
import { SendouSwitch } from "~/components/elements/Switch";
import type { CalendarEventTag, PersistedCalendarEventTag } from "~/db/tables";
export const meta: MetaFunction = (args) => {
const data = args.data as SerializeFrom<typeof loader> | null;

View File

@ -4,7 +4,7 @@ import { nanoid } from "nanoid";
import * as React from "react";
import { useTranslation } from "react-i18next";
import ReconnectingWebSocket from "reconnecting-websocket";
import type { User } from "~/db/types";
import type { Tables } from "~/db/tables";
import { useUser } from "~/features/auth/core/user";
import invariant from "~/utils/invariant";
import { logger } from "~/utils/logger";
@ -17,7 +17,10 @@ import { useChatAutoScroll } from "../chat-hooks";
import type { ChatMessage } from "../chat-types";
import { messageTypeToSound, soundEnabled, soundVolume } from "../chat-utils";
type ChatUser = Pick<User, "username" | "discordId" | "discordAvatar"> & {
type ChatUser = Pick<
Tables["User"],
"username" | "discordId" | "discordAvatar"
> & {
chatNameColor: string | null;
title?: string;
};

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { UserSubmittedImage } from "~/db/types";
import type { Tables } from "~/db/tables";
import type { ImageUploadType } from "../upload-types";
const addImgStm = sql.prepare(/* sql */ `
@ -48,7 +48,7 @@ export const addNewImage = sql.transaction(
submitterUserId,
url,
validatedAt,
}) as UserSubmittedImage;
}) as Tables["UserSubmittedImage"];
if (type === "team-pfp") {
updateTeamAvatarStm.run({ avatarImgId: img.id, teamId: teamId ?? null });

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { UserSubmittedImage } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
select
@ -20,7 +20,7 @@ const stm = sql.prepare(/* sql */ `
`);
type UnvalidatedImage = Pick<
UserSubmittedImage,
Tables["UserSubmittedImage"],
"id" | "url" | "submitterUserId"
>;

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { User, XRankPlacement } from "~/db/types";
import type { Tables } from "~/db/tables";
import type { MainWeaponId } from "~/modules/in-game-lists";
import { DEFAULT_LEADERBOARD_MAX_SIZE } from "../leaderboards-constants";
@ -41,13 +41,13 @@ const weaponStm = getStm(/* sql */ `
export interface XPLeaderboardItem {
entryId: number;
power: number;
id: User["id"];
name: XRankPlacement["name"];
playerId: XRankPlacement["playerId"];
username: User["username"] | null;
discordAvatar: User["discordAvatar"] | null;
discordId: User["discordId"] | null;
customUrl: User["customUrl"] | null;
id: Tables["User"]["id"];
name: Tables["XRankPlacement"]["name"];
playerId: Tables["XRankPlacement"]["playerId"];
username: Tables["User"]["username"] | null;
discordAvatar: Tables["User"]["discordAvatar"] | null;
discordId: Tables["User"]["discordId"] | null;
customUrl: Tables["User"]["customUrl"] | null;
placementRank: number;
weaponSplId: MainWeaponId;
}
@ -57,7 +57,7 @@ export function allXPLeaderboard(): XPLeaderboardItem[] {
}
export function modeXPLeaderboard(
mode: XRankPlacement["mode"],
mode: Tables["XRankPlacement"]["mode"],
): XPLeaderboardItem[] {
return modeStm.all({ mode }) as any[];
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { User } from "~/db/types";
import type { Tables } from "~/db/tables";
import { seasonObject } from "~/features/mmr/season";
import type { MainWeaponId } from "~/modules/in-game-lists";
import { dateToDatabaseTimestamp } from "~/utils/dates";
@ -26,7 +26,10 @@ const stm = sql.prepare(/* sql */ `
group by "q1"."userId"
`);
export type SeasonPopularUsersWeapon = Record<User["id"], MainWeaponId>;
export type SeasonPopularUsersWeapon = Record<
Tables["User"]["id"],
MainWeaponId
>;
export function seasonPopularUsersWeapon(
season: number,
@ -39,7 +42,7 @@ export function seasonPopularUsersWeapon(
ends: dateToDatabaseTimestamp(ends),
}) as Array<{
count: number;
userId: User["id"];
userId: Tables["User"]["id"];
weaponSplId: MainWeaponId;
}>;

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { PlusTier, User } from "~/db/types";
import type { Tables } from "~/db/tables";
import { ordinalToSp } from "~/features/mmr/mmr-utils";
import { MATCHES_COUNT_NEEDED_FOR_LEADERBOARD } from "../leaderboards-constants";
@ -36,14 +36,14 @@ const stm = sql.prepare(/* sql */ `
export interface UserSPLeaderboardItem {
entryId: number;
power: number;
id: User["id"];
username: User["username"];
discordAvatar: User["discordAvatar"];
discordId: User["discordId"];
customUrl: User["customUrl"];
id: Tables["User"]["id"];
username: Tables["User"]["username"];
discordAvatar: Tables["User"]["discordAvatar"];
discordId: Tables["User"]["discordId"];
customUrl: Tables["User"]["customUrl"];
plusSkippedForSeasonNth: number | null;
/** Plus tier player is on track to join */
pendingPlusTier?: PlusTier["tier"];
pendingPlusTier?: Tables["PlusTier"]["tier"];
placementRank: number;
}

View File

@ -1,4 +1,4 @@
import type { MapPoolMap } from "~/db/types";
import type { Tables } from "~/db/tables";
import type { ModeShort } from "../../../../modules/in-game-lists";
import type { MapPool } from "../map-pool";
import type { MapPoolObject } from "../map-pool-serializer/types";
@ -16,7 +16,7 @@ export function mapPoolToNonEmptyModes(mapPool: MapPool) {
}
export function mapPoolListToMapPoolObject(
mapPoolList: Array<Pick<MapPoolMap, "stageId" | "mode">>,
mapPoolList: Array<Pick<Tables["MapPoolMap"], "stageId" | "mode">>,
) {
const result: MapPoolObject = {
TW: [],

View File

@ -1,4 +1,4 @@
import type { MapPoolMap } from "~/db/types";
import type { Tables } from "~/db/tables";
import {
type ModeShort,
type StageId,
@ -14,7 +14,9 @@ import type {
ReadonlyMapPoolObject,
} from "./map-pool-serializer/types";
export type DbMapPoolList = Array<Pick<MapPoolMap, "stageId" | "mode">>;
export type DbMapPoolList = Array<
Pick<Tables["MapPoolMap"], "stageId" | "mode">
>;
export class MapPool {
private source: string | ReadonlyMapPoolObject;

View File

@ -9,7 +9,6 @@ import { Label } from "~/components/Label";
import { Main } from "~/components/Main";
import { MapPoolSelector, MapPoolStages } from "~/components/MapPoolSelector";
import { EditIcon } from "~/components/icons/Edit";
import type { CalendarEvent } from "~/db/types";
import { getUserId } from "~/features/auth/core/user.server";
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
import { type ModeWithStage, stageIds } from "~/modules/in-game-lists";
@ -27,6 +26,7 @@ import { mapPoolToNonEmptyModes } from "../core/map-list-generator/utils";
import { MapPool } from "../core/map-pool";
import "~/styles/maps.css";
import { SendouSwitch } from "~/components/elements/Switch";
import type { Tables } from "~/db/tables";
import { metaTags } from "~/utils/remix";
const AMOUNT_OF_MAPS_IN_MAP_LIST = stageIds.length * 2;
@ -155,7 +155,7 @@ function useSearchParamPersistedMapPool() {
const handleMapPoolChange = (
newMapPool: MapPool,
event?: Pick<CalendarEvent, "id" | "name">,
event?: Pick<Tables["CalendarEvent"], "id" | "name">,
) => {
setMapPool(newMapPool);
setSearchParams(

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { Skill } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
select
@ -26,7 +26,7 @@ export function findCurrentSkillByUserId({
season: number;
}) {
return stm.get({ userId, season }) as Pick<
Skill,
Tables["Skill"],
"mu" | "sigma" | "matchesCount"
> | null;
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { Skill } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
select
@ -26,7 +26,7 @@ export function findCurrentTeamSkillByIdentifier({
season: number;
}) {
return stm.get({ identifier, season }) as Pick<
Skill,
Tables["Skill"],
"mu" | "sigma" | "matchesCount"
> | null;
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { Skill } from "~/db/types";
import type { Tables } from "~/db/tables";
const userStm = sql.prepare(/* sql */ `
select
@ -51,6 +51,6 @@ export function orderedMMRBySeason({
const stm = type === "team" ? teamStm : userStm;
return stm.all({ season }) as Array<
Pick<Skill, "ordinal" | "matchesCount" | "userId" | "identifier">
Pick<Tables["Skill"], "ordinal" | "matchesCount" | "userId" | "identifier">
>;
}

View File

@ -1,4 +1,4 @@
import type { Skill } from "~/db/types";
import type { Tables } from "~/db/tables";
import { cache, syncCached } from "~/utils/cache.server";
import { MATCHES_COUNT_NEEDED_FOR_LEADERBOARD } from "../leaderboards/leaderboards-constants";
import { USER_SKILLS_CACHE_KEY } from "../sendouq/q-constants";
@ -71,7 +71,7 @@ export type SkillTierInterval = ReturnType<
>["intervals"][number];
function skillTierIntervals(
orderedPoints: Array<Pick<Skill, "ordinal" | "matchesCount">>,
orderedPoints: Array<Pick<Tables["Skill"], "ordinal" | "matchesCount">>,
type: "user" | "team",
) {
const LEADERBOARD_MIN_ENTRIES_FOR_LEVIATHAN =

View File

@ -14,7 +14,7 @@ import {
PLUS_TIERS,
PlUS_SUGGESTION_FIRST_COMMENT_MAX_LENGTH,
} from "~/constants";
import type { UserWithPlusTier } from "~/db/types";
import type { UserWithPlusTier } from "~/db/tables";
import { useUser } from "~/features/auth/core/user";
import { requireUser } from "~/features/auth/core/user.server";
import { notify } from "~/features/notifications/core/notify.server";

View File

@ -15,7 +15,7 @@ import { FormWithConfirm } from "~/components/FormWithConfirm";
import { RelativeTime } from "~/components/RelativeTime";
import { TrashIcon } from "~/components/icons/Trash";
import { PLUS_TIERS } from "~/constants";
import type { PlusSuggestion, User } from "~/db/types";
import type { Tables } from "~/db/tables";
import { useUser } from "~/features/auth/core/user";
import { requireUser } from "~/features/auth/core/user.server";
import * as PlusSuggestionRepository from "~/features/plus-suggestions/PlusSuggestionRepository.server";
@ -366,7 +366,7 @@ export function PlusSuggestionComments({
}: {
suggestion: PlusSuggestionRepository.FindAllByMonthItem;
deleteButtonArgs?: {
user?: Pick<User, "id" | "discordId">;
user?: Pick<Tables["User"], "id" | "discordId">;
suggestions: PlusSuggestionRepository.FindAllByMonthItem[];
tier: string;
suggested: PlusSuggestionRepository.FindAllByMonthItem["suggested"];
@ -425,7 +425,7 @@ function CommentDeleteButton({
suggestedUsername,
isFirstSuggestion = false,
}: {
suggestionId: PlusSuggestion["id"];
suggestionId: Tables["PlusSuggestion"]["id"];
tier: string;
suggestedUsername: string;
isFirstSuggestion?: boolean;

View File

@ -1,8 +1,8 @@
import type { PlusVote } from "~/db/types";
import type { Tables } from "~/db/tables";
export interface MonthYear {
month: number;
year: number;
}
export type PlusVoteFromFE = Pick<PlusVote, "votedId" | "score">;
export type PlusVoteFromFE = Pick<Tables["PlusVote"], "votedId" | "score">;

View File

@ -1,6 +1,6 @@
import * as React from "react";
import { PLUS_DOWNVOTE, PLUS_UPVOTE } from "~/constants";
import type { User } from "~/db/types";
import type { Tables } from "~/db/tables";
import type * as PlusVotingRepository from "~/features/plus-voting/PlusVotingRepository.server";
import invariant from "~/utils/invariant";
import type { PlusVoteFromFE } from "./types";
@ -13,7 +13,7 @@ interface VotingLocalStorageData {
year: number;
votes: PlusVoteFromFE[];
/** User id -> order for sorting */
usersForVotingOrder: Record<User["id"], number>;
usersForVotingOrder: Record<Tables["User"]["id"], number>;
}
export function usePlusVoting(

View File

@ -5,7 +5,6 @@ import type {
} from "@remix-run/node";
import { Link, useLoaderData } from "@remix-run/react";
import clsx from "clsx";
import type { UserWithPlusTier } from "~/db/types";
import { getUser } from "~/features/auth/core/user.server";
import * as PlusVotingRepository from "~/features/plus-voting/PlusVotingRepository.server";
import { lastCompletedVoting } from "~/features/plus-voting/core";
@ -15,6 +14,7 @@ import { PLUS_SERVER_DISCORD_URL, userPage } from "~/utils/urls";
import { isAtLeastFiveDollarTierPatreon } from "~/utils/users";
import "~/styles/plus-history.css";
import type { UserWithPlusTier } from "~/db/tables";
import { metaTags } from "~/utils/remix";
export const meta: MetaFunction = (args) => {

View File

@ -1,7 +1,6 @@
import { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite";
import { db } from "~/db/sql";
import type { ParsedMemento, Tables } from "~/db/tables";
import type { UserSkillDifference } from "~/db/types";
import type { ParsedMemento, Tables, UserSkillDifference } from "~/db/tables";
import type { MainWeaponId } from "~/modules/in-game-lists";
import { COMMON_USER_FIELDS, userChatNameColor } from "~/utils/kysely.server";

View File

@ -18,7 +18,7 @@ import { SpeakerXIcon } from "~/components/icons/SpeakerX";
import { StarIcon } from "~/components/icons/Star";
import { StarFilledIcon } from "~/components/icons/StarFilled";
import { TrashIcon } from "~/components/icons/Trash";
import type { GroupMember as GroupMemberType, ParsedMemento } from "~/db/types";
import type { ParsedMemento, Tables } from "~/db/tables";
import { useUser } from "~/features/auth/core/user";
import { MATCHES_COUNT_NEEDED_FOR_LEADERBOARD } from "~/features/leaderboards/leaderboards-constants";
import { ordinalToRoundedSp } from "~/features/mmr/mmr-utils";
@ -55,7 +55,7 @@ export function GroupCard({
}: {
group: Omit<LookingGroup, "createdAt" | "chatCode">;
action?: "LIKE" | "UNLIKE" | "GROUP_UP" | "MATCH_UP" | "MATCH_UP_RECHALLENGE";
ownRole?: GroupMemberType["role"] | "PREVIEWER";
ownRole?: Tables["GroupMember"]["role"] | "PREVIEWER";
ownGroup?: boolean;
isExpired?: boolean;
displayOnly?: boolean;

View File

@ -1,5 +1,4 @@
import type { Tables } from "~/db/tables";
import type { Group } from "~/db/types";
import { TIERS } from "~/features/mmr/mmr-constants";
import { defaultOrdinal } from "~/features/mmr/mmr-utils";
import type {
@ -467,7 +466,7 @@ function resolveGroupSkill({
}
export function groupExpiryStatus(
group?: Pick<Group, "latestActionAt">,
group?: Pick<Tables["Group"], "latestActionAt">,
): null | GroupExpiryStatus {
if (!group) return null;

View File

@ -1,4 +1,4 @@
import type { GroupMember } from "~/db/types";
import type { Tables } from "~/db/tables";
import type { LookingGroup } from "../q-types";
// logic is that team who is bigger decides the settings
@ -31,6 +31,6 @@ export function groupAfterMorph({
return ourGroup;
}
export function hasGroupManagerPerms(role: GroupMember["role"]) {
export function hasGroupManagerPerms(role: Tables["GroupMember"]["role"]) {
return role === "OWNER" || role === "MANAGER";
}

View File

@ -1,13 +1,10 @@
import type { Rating } from "node_modules/openskill/dist/types";
import { ordinal } from "openskill";
import type {
Group,
GroupMatch,
GroupSkillDifference,
Skill,
User,
Tables,
UserSkillDifference,
} from "~/db/types";
} from "~/db/tables";
import { MATCHES_COUNT_NEEDED_FOR_LEADERBOARD } from "~/features/leaderboards/leaderboards-constants";
import {
ordinalToSp,
@ -25,13 +22,13 @@ import { roundToNDecimalPlaces } from "~/utils/number";
export type MementoSkillDifferences = {
users: Record<
User["id"],
Tables["User"]["id"],
{
skillDifference?: UserSkillDifference;
}
>;
groups: Record<
Group["id"],
Tables["Group"]["id"],
{
skillDifference?: GroupSkillDifference;
}
@ -45,15 +42,15 @@ export function calculateMatchSkills({
winnerGroupId,
loserGroupId,
}: {
groupMatchId: GroupMatch["id"];
winner: User["id"][];
loser: User["id"][];
winnerGroupId: Group["id"];
loserGroupId: Group["id"];
groupMatchId: Tables["GroupMatch"]["id"];
winner: Tables["User"]["id"][];
loser: Tables["User"]["id"][];
winnerGroupId: Tables["Group"]["id"];
loserGroupId: Tables["Group"]["id"];
}) {
const newSkills: Array<
Pick<
Skill,
Tables["Skill"],
"groupMatchId" | "identifier" | "mu" | "season" | "sigma" | "userId"
>
> = [];

View File

@ -1,4 +1,4 @@
import type { MapResult, PlayerResult } from "~/db/types";
import type { Tables } from "~/db/tables";
import { currentOrPreviousSeason } from "~/features/mmr/season";
import invariant from "~/utils/invariant";
import { winnersArrayToWinner } from "../q-utils";
@ -16,7 +16,7 @@ export function summarizeMaps({
const season = currentOrPreviousSeason(new Date())?.nth;
invariant(typeof season === "number", "No ranked season for skills");
const result: Array<MapResult> = [];
const result: Array<Tables["MapResult"]> = [];
const playedMaps = match.mapList.slice(0, winners.length);
@ -66,7 +66,7 @@ export function summarizePlayerResults({
const season = currentOrPreviousSeason(new Date())?.nth;
invariant(typeof season === "number", "No ranked season for skills");
const result: Array<PlayerResult> = [];
const result: Array<Tables["PlayerResult"]> = [];
const addMapResult = ({
outcome,

View File

@ -1,18 +1,11 @@
import type { Tables } from "~/db/tables";
import type {
Group,
GroupMember,
ParsedMemento,
PlusTier,
User,
} from "~/db/types";
import type { ParsedMemento, Tables } from "~/db/tables";
import type { MainWeaponId, ModeShort } from "~/modules/in-game-lists";
import type { TieredSkill } from "../mmr/tiered.server";
import type { GroupForMatch } from "../sendouq-match/QMatchRepository.server";
export type LookingGroup = {
id: number;
createdAt: Group["createdAt"];
createdAt: Tables["Group"]["createdAt"];
tier?: TieredSkill["tier"];
tierRange?: {
range?: [TieredSkill["tier"], TieredSkill["tier"]];
@ -23,7 +16,7 @@ export type LookingGroup = {
isLiked?: boolean;
isRechallenge?: boolean;
team?: GroupForMatch["team"];
chatCode?: Group["chatCode"];
chatCode?: Tables["Group"]["chatCode"];
mapModePreferences?: Array<NonNullable<Tables["User"]["mapModePreferences"]>>;
futureMatchModes?: Array<ModeShort>;
rechallengeMatchModes?: Array<ModeShort>;
@ -34,14 +27,14 @@ export type LookingGroup = {
username: string;
discordAvatar: string | null;
noScreen?: number;
customUrl?: User["customUrl"];
plusTier?: PlusTier["tier"];
role: GroupMember["role"];
note?: GroupMember["note"];
customUrl?: Tables["User"]["customUrl"];
plusTier?: Tables["PlusTier"]["tier"];
role: Tables["GroupMember"]["role"];
note?: Tables["GroupMember"]["note"];
weapons?: MainWeaponId[];
skill?: TieredSkill | "CALCULATING";
vc?: User["vc"];
inGameName?: User["inGameName"];
vc?: Tables["User"]["vc"];
inGameName?: Tables["User"]["inGameName"];
languages: string[];
chatNameColor: string | null;
skillDifference?: ParsedMemento["users"][number]["skillDifference"];
@ -54,7 +47,7 @@ export type LookingGroup = {
};
export type LookingGroupWithInviteCode = LookingGroup & {
inviteCode: Group["inviteCode"];
inviteCode: Tables["Group"]["inviteCode"];
members: NonNullable<LookingGroup["members"]>;
};

View File

@ -1,4 +1,4 @@
import type { Group } from "~/db/types";
import type { Tables } from "~/db/tables";
import { stageIds } from "~/modules/in-game-lists";
import { rankedModesShort } from "~/modules/in-game-lists/modes";
import { databaseTimestampToDate } from "~/utils/dates";
@ -13,7 +13,7 @@ import type { MapPool } from "../map-list-generator/core/map-pool";
import { SENDOUQ } from "./q-constants";
function groupRedirectLocation(
group?: Pick<Group, "status"> & { matchId?: number },
group?: Pick<Tables["Group"], "status"> & { matchId?: number },
) {
if (group?.status === "PREPARING") return SENDOUQ_PREPARING_PAGE;
if (group?.matchId) return sendouQMatchPage(group.matchId);
@ -26,7 +26,7 @@ export function groupRedirectLocationByCurrentLocation({
group,
currentLocation,
}: {
group?: Pick<Group, "status"> & { matchId?: number };
group?: Pick<Tables["Group"], "status"> & { matchId?: number };
currentLocation: "default" | "preparing" | "looking" | "match";
}) {
const newLocation = groupRedirectLocation(group);

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { MapResult } from "~/db/types";
import type { Tables } from "~/db/tables";
const addMapResultDeltaStm = sql.prepare(/* sql */ `
insert into "MapResult" (
@ -25,7 +25,7 @@ const addMapResultDeltaStm = sql.prepare(/* sql */ `
export function addMapResults(
results: Array<
Pick<MapResult, "losses" | "wins" | "userId" | "mode" | "stageId">
Pick<Tables["MapResult"], "losses" | "wins" | "userId" | "mode" | "stageId">
>,
) {
for (const result of results) {

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { GroupMember } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
insert into "GroupMember" (
@ -20,7 +20,7 @@ export function addMember({
}: {
groupId: number;
userId: number;
role?: GroupMember["role"];
role?: Tables["GroupMember"]["role"];
}) {
stm.run({ groupId, userId, role });
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { PlayerResult } from "~/db/types";
import type { Tables } from "~/db/tables";
const addPlayerResultDeltaStm = sql.prepare(/* sql */ `
insert into "PlayerResult" (
@ -29,7 +29,7 @@ const addPlayerResultDeltaStm = sql.prepare(/* sql */ `
"setLosses" = "setLosses" + @setLosses
`);
export function addPlayerResults(results: Array<PlayerResult>) {
export function addPlayerResults(results: Array<Tables["PlayerResult"]>) {
for (const result of results) {
addPlayerResultDeltaStm.run({
ownerUserId: result.ownerUserId,

View File

@ -1,6 +1,6 @@
import { ordinal } from "openskill";
import { sql } from "~/db/sql";
import type { ParsedMemento, Skill } from "~/db/types";
import type { ParsedMemento, Tables } from "~/db/tables";
import { identifierToUserIds } from "~/features/mmr/mmr-utils";
import type { MementoSkillDifferences } from "../core/skills.server";
@ -55,7 +55,7 @@ export function addSkills({
}: {
groupMatchId: number;
skills: Pick<
Skill,
Tables["Skill"],
"groupMatchId" | "identifier" | "mu" | "season" | "sigma" | "userId"
>[];
oldMatchMemento: ParsedMemento;
@ -66,7 +66,7 @@ export function addSkills({
const insertedSkill = stm.get({
...skill,
ordinal: ordinal(skill),
}) as Skill;
}) as Tables["Skill"];
if (insertedSkill.identifier) {
for (const userId of identifierToUserIds(insertedSkill.identifier)) {

View File

@ -1,7 +1,6 @@
import { nanoid } from "nanoid";
import { sql } from "~/db/sql";
import type { ParsedMemento } from "~/db/tables";
import type { GroupMatch } from "~/db/types";
import type { ParsedMemento, Tables } from "~/db/tables";
import type { TournamentMapListMap } from "~/modules/tournament-map-list-generator";
import { syncGroupTeamId } from "./syncGroupTeamId.server";
@ -53,7 +52,7 @@ export const createMatch = sql.transaction(
bravoGroupId,
chatCode: nanoid(10),
memento: JSON.stringify(memento),
}) as GroupMatch;
}) as Tables["GroupMatch"];
for (const [i, { mode, source, stageId }] of mapList.entries()) {
createMatchMapStm.run({

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { Group, GroupMember } from "~/db/types";
import type { Tables } from "~/db/tables";
import invariant from "~/utils/invariant";
const stm = sql.prepare(/* sql */ `
@ -21,11 +21,11 @@ const stm = sql.prepare(/* sql */ `
`);
type ActiveGroup = Pick<
Group,
Tables["Group"],
"id" | "status" | "latestActionAt" | "chatCode"
> & {
matchId?: number;
role: GroupMember["role"];
role: Tables["GroupMember"]["role"];
};
export function findCurrentGroupByUserId(

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { Group, GroupMember } from "~/db/types";
import type { Tables } from "~/db/tables";
import { parseDBJsonArray } from "~/utils/sql";
const stm = sql.prepare(/* sql */ `
@ -25,8 +25,12 @@ const stm = sql.prepare(/* sql */ `
export function findGroupByInviteCode(inviteCode: string): {
id: number;
status: Group["status"];
members: { id: number; username: string; role: GroupMember["role"] }[];
status: Tables["Group"]["status"];
members: {
id: number;
username: string;
role: Tables["GroupMember"]["role"];
}[];
} | null {
const row = stm.get({ inviteCode }) as any;
if (!row) return null;

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { GroupMatch, GroupMatchMap, ParsedMemento } from "~/db/types";
import type { ParsedMemento, Tables } from "~/db/tables";
import { parseDBJsonArray } from "~/utils/sql";
const stm = sql.prepare(/* sql */ `
@ -30,17 +30,20 @@ const stm = sql.prepare(/* sql */ `
`);
export interface MatchById {
id: GroupMatch["id"];
alphaGroupId: GroupMatch["alphaGroupId"];
bravoGroupId: GroupMatch["bravoGroupId"];
createdAt: GroupMatch["createdAt"];
reportedAt: GroupMatch["reportedAt"];
reportedByUserId: GroupMatch["reportedByUserId"];
chatCode: GroupMatch["chatCode"];
id: Tables["GroupMatch"]["id"];
alphaGroupId: Tables["GroupMatch"]["alphaGroupId"];
bravoGroupId: Tables["GroupMatch"]["bravoGroupId"];
createdAt: Tables["GroupMatch"]["createdAt"];
reportedAt: Tables["GroupMatch"]["reportedAt"];
reportedByUserId: Tables["GroupMatch"]["reportedByUserId"];
chatCode: Tables["GroupMatch"]["chatCode"];
isLocked: boolean;
memento: ParsedMemento;
mapList: Array<
Pick<GroupMatchMap, "id" | "mode" | "stageId" | "source" | "winnerGroupId">
Pick<
Tables["GroupMatchMap"],
"id" | "mode" | "stageId" | "source" | "winnerGroupId"
>
>;
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { GroupMember } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql*/ `
with "MostRecentGroupMatch" as (
@ -25,7 +25,10 @@ const stm = sql.prepare(/* sql*/ `
"MostRecentGroupMatch"."createdAt" > unixepoch() - 60 * 60 * 2
`);
export type RecentMatchPlayer = Pick<GroupMember, "groupId" | "userId">;
export type RecentMatchPlayer = Pick<
Tables["GroupMember"],
"groupId" | "userId"
>;
export function findRecentMatchPlayersByUserId(userId: number) {
return stm.all({ userId }) as Array<RecentMatchPlayer>;

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { GroupMember } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
select
@ -13,7 +13,7 @@ const stm = sql.prepare(/* sql */ `
export const groupSuccessorOwner = (groupId: number) => {
const rows = stm.all({ groupId }) as Array<
Pick<GroupMember, "role" | "userId">
Pick<Tables["GroupMember"], "role" | "userId">
>;
if (rows.length === 0) {

View File

@ -1,6 +1,6 @@
import { nanoid } from "nanoid";
import { sql } from "~/db/sql";
import type { GroupMember, User } from "~/db/types";
import type { Tables } from "~/db/tables";
import { deleteLikesByGroupId } from "./deleteLikesByGroupId.server";
const findToBeDeletedGroupNonRegularsStm = sql.prepare(/* sql */ `
@ -41,7 +41,7 @@ export const morphGroups = sql.transaction(
}) => {
const toBeDeletedGroupNonRegulars = findToBeDeletedGroupNonRegularsStm
.all({ groupId: otherGroupId })
.map((row: any) => row.userId) as Array<User["id"]>;
.map((row: any) => row.userId) as Array<Tables["User"]["id"]>;
deleteLikesByGroupId(survivingGroupId);
@ -52,11 +52,8 @@ export const morphGroups = sql.transaction(
});
for (const userId of newMembers) {
const role: GroupMember["role"] = toBeDeletedGroupNonRegulars.includes(
userId,
)
? "MANAGER"
: "REGULAR";
const role: Tables["GroupMember"]["role"] =
toBeDeletedGroupNonRegulars.includes(userId) ? "MANAGER" : "REGULAR";
updateGroupMemberStm.run({
newGroupId: survivingGroupId,
oldGroupId: otherGroupId,

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { GroupMatch } from "~/db/types";
import type { Tables } from "~/db/tables";
import { dateToDatabaseTimestamp } from "~/utils/dates";
const updateMatchStm = sql.prepare(/* sql */ `
@ -35,7 +35,7 @@ export const reportScore = ({
reportedAt: dateToDatabaseTimestamp(new Date()),
reportedByUserId,
matchId,
}) as GroupMatch;
}) as Tables["GroupMatch"];
clearMatchMapWinnersStm.run({ matchId });

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { GroupMatchMap, ReportedWeapon } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
select
@ -15,8 +15,8 @@ const stm = sql.prepare(/* sql */ `
export function reportedWeaponsByMatchId(matchId: number) {
const rows = stm.all({ matchId }) as Array<
ReportedWeapon & {
mapIndex: GroupMatchMap["index"];
Tables["ReportedWeapon"] & {
mapIndex: Tables["GroupMatchMap"]["index"];
groupMatchMapId: number;
}
>;

View File

@ -1,7 +1,6 @@
import { add } from "date-fns";
import { sql } from "~/db/sql";
import type { ParsedMemento } from "~/db/tables";
import type { GroupMatch, GroupMatchMap, User } from "~/db/types";
import type { ParsedMemento, Tables } from "~/db/tables";
import { seasonObject } from "~/features/mmr/season";
import { MATCHES_PER_SEASONS_PAGE } from "~/features/user-page/user-page-constants";
import type { MainWeaponId } from "~/modules/in-game-lists";
@ -98,25 +97,25 @@ const weaponsStm = sql.prepare(/* sql */ `
`);
interface SeasonMatchByUserId {
id: GroupMatch["id"];
alphaGroupId: GroupMatch["alphaGroupId"];
bravoGroupId: GroupMatch["bravoGroupId"];
winnerGroupIds: Array<GroupMatchMap["winnerGroupId"]>;
createdAt: GroupMatch["createdAt"];
id: Tables["GroupMatch"]["id"];
alphaGroupId: Tables["GroupMatch"]["alphaGroupId"];
bravoGroupId: Tables["GroupMatch"]["bravoGroupId"];
winnerGroupIds: Array<Tables["GroupMatchMap"]["winnerGroupId"]>;
createdAt: Tables["GroupMatch"]["createdAt"];
isLocked: number;
spDiff: number | null;
groupAlphaMembers: Array<{
id: User["id"];
username: User["username"];
discordId: User["discordId"];
discordAvatar: User["discordAvatar"];
id: Tables["User"]["id"];
username: Tables["User"]["username"];
discordId: Tables["User"]["discordId"];
discordAvatar: Tables["User"]["discordAvatar"];
weaponSplId?: MainWeaponId;
}>;
groupBravoMembers: Array<{
id: User["id"];
username: User["username"];
discordId: User["discordId"];
discordAvatar: User["discordAvatar"];
id: Tables["User"]["id"];
username: Tables["User"]["username"];
discordId: Tables["User"]["discordId"];
discordAvatar: Tables["User"]["discordAvatar"];
weaponSplId?: MainWeaponId;
}>;
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { MapResult } from "~/db/types";
import type { Tables } from "~/db/tables";
import type { ModeShort, StageId } from "~/modules/in-game-lists";
const stm = sql.prepare(/* sql */ `
@ -19,7 +19,7 @@ export function seasonStagesByUserId({
userId: number;
season: number;
}) {
const rows = stm.all({ userId, season }) as Array<MapResult>;
const rows = stm.all({ userId, season }) as Array<Tables["MapResult"]>;
return rows.reduce(
(acc, cur) => {

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { PlayerResult, User } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
select
@ -30,7 +30,7 @@ export function seasonsMatesEnemiesByUserId({
}: {
userId: number;
season: number;
type: PlayerResult["type"];
type: Tables["PlayerResult"]["type"];
}) {
const rows = stm.all({ userId, season, type }) as any[];
@ -43,7 +43,7 @@ export function seasonsMatesEnemiesByUserId({
setWins: number;
setLosses: number;
user: Pick<
User,
Tables["User"],
"id" | "username" | "discordAvatar" | "discordId" | "customUrl"
>;
}>;

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { Group } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
update "Group"
@ -7,6 +7,6 @@ const stm = sql.prepare(/* sql */ `
where "id" = @groupId
`);
export function setGroupAsActive(groupId: Group["id"]) {
export function setGroupAsActive(groupId: Tables["Group"]["id"]) {
stm.run({ groupId });
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { GroupMember } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
update "GroupMember"
@ -8,9 +8,9 @@ const stm = sql.prepare(/* sql */ `
`);
export function updateNote(args: {
note: GroupMember["note"];
groupId: GroupMember["groupId"];
userId: GroupMember["userId"];
note: Tables["GroupMember"]["note"];
groupId: Tables["GroupMember"]["groupId"];
userId: Tables["GroupMember"]["userId"];
}) {
stm.run(args);
}

View File

@ -36,7 +36,6 @@ import { DiscordIcon } from "~/components/icons/Discord";
import { RefreshArrowsIcon } from "~/components/icons/RefreshArrows";
import { ScaleIcon } from "~/components/icons/Scale";
import { sql } from "~/db/sql";
import type { GroupMember, ReportedWeapon } from "~/db/types";
import { useUser } from "~/features/auth/core/user";
import { getUserId, requireUser } from "~/features/auth/core/user.server";
import * as ChatSystemMessage from "~/features/chat/ChatSystemMessage.server";
@ -113,6 +112,7 @@ import { reportedWeaponsByMatchId } from "../queries/reportedWeaponsByMatchId.se
import { setGroupAsInactive } from "../queries/setGroupAsInactive.server";
import "../q.css";
import { SendouSwitch } from "~/components/elements/Switch";
import type { ReportedWeapon, Tables } from "~/db/tables";
import { metaTags } from "~/utils/remix";
export const meta: MetaFunction = (args) => {
@ -751,7 +751,7 @@ function AfterMatchActions({
setShowWeaponsForm,
}: {
ownGroupId: number;
role: GroupMember["role"];
role: Tables["GroupMember"]["role"];
reportedAt: number;
showWeaponsForm: boolean;
setShowWeaponsForm: (show: boolean) => void;

View File

@ -21,7 +21,6 @@ import { SubmitButton } from "~/components/SubmitButton";
import { UserIcon } from "~/components/icons/User";
import { UsersIcon } from "~/components/icons/Users";
import { sql } from "~/db/sql";
import type { GroupMember } from "~/db/types";
import { useUser } from "~/features/auth/core/user";
import { getUserId, requireUser } from "~/features/auth/core/user.server";
import type { RankingSeason } from "~/features/mmr/season";
@ -67,6 +66,7 @@ import { deleteLikesByGroupId } from "../queries/deleteLikesByGroupId.server";
import { findCurrentGroupByUserId } from "../queries/findCurrentGroupByUserId.server";
import { findGroupByInviteCode } from "../queries/findGroupByInviteCode.server";
import "../q.css";
import type { Tables } from "~/db/tables";
import { metaTags } from "~/utils/remix";
export const handle: SendouRouteHandle = {
@ -402,7 +402,7 @@ function JoinTeamDialog({
close: () => void;
members: {
username: string;
role: GroupMember["role"];
role: Tables["GroupMember"]["role"];
}[];
}) {
const { t } = useTranslation(["q"]);

View File

@ -1,5 +1,5 @@
import type { LoaderFunctionArgs } from "@remix-run/node";
import type { UserWithPlusTier } from "~/db/types";
import type { UserWithPlusTier } from "~/db/tables";
import { getUserId } from "~/features/auth/core/user.server";
import { sumArray } from "~/utils/number";
import * as TeamRepository from "../TeamRepository.server";

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { User, XRankPlacement } from "~/db/types";
import type { Tables } from "~/db/tables";
const query = (byPlayer?: boolean) => /* sql */ `
select
@ -48,7 +48,7 @@ const ofMonthStm = sql.prepare(query());
const byPlayerStm = sql.prepare(query(true));
export type FindPlacement = Pick<
XRankPlacement,
Tables["XRankPlacement"],
| "id"
| "weaponSplId"
| "name"
@ -60,15 +60,17 @@ export type FindPlacement = Pick<
| "playerId"
| "mode"
> &
Pick<User, "customUrl" | "discordId">;
Pick<Tables["User"], "customUrl" | "discordId">;
export function findPlacementsOfMonth(
args: Pick<XRankPlacement, "mode" | "region" | "month" | "year">,
args: Pick<Tables["XRankPlacement"], "mode" | "region" | "month" | "year">,
) {
return ofMonthStm.all(args) as Array<FindPlacement>;
}
export function findPlacementsByPlayerId(playerId: XRankPlacement["playerId"]) {
export function findPlacementsByPlayerId(
playerId: Tables["XRankPlacement"]["playerId"],
) {
const results = byPlayerStm.all({ playerId }) as Array<FindPlacement>;
if (!results) return null;

View File

@ -3,7 +3,6 @@ import { useLoaderData, useSearchParams } from "@remix-run/react";
import { nanoid } from "nanoid";
import { useTranslation } from "react-i18next";
import { Main } from "~/components/Main";
import type { XRankPlacement } from "~/db/types";
import type { RankedModeShort } from "~/modules/in-game-lists";
import { rankedModesShort } from "~/modules/in-game-lists/modes";
import invariant from "~/utils/invariant";
@ -16,6 +15,7 @@ import { monthYears } from "../queries/monthYears";
import type { MonthYear } from "../top-search-utils";
import "../top-search.css";
import type { Tables } from "~/db/tables";
export const handle: SendouRouteHandle = {
breadcrumb: () => ({
@ -152,7 +152,7 @@ export default function XSearchPage() {
interface SelectOption {
id: string;
region: XRankPlacement["region"];
region: Tables["XRankPlacement"]["region"];
mode: RankedModeShort;
span: {
from: MonthYear;

View File

@ -2,13 +2,7 @@
import { nanoid } from "nanoid";
import { sql } from "~/db/sql";
import type { TournamentRoundMaps } from "~/db/tables";
import type {
TournamentGroup,
TournamentMatch,
TournamentRound,
TournamentStage,
} from "~/db/types";
import type { Tables, TournamentRoundMaps } from "~/db/tables";
import type {
Group as GroupType,
Match as MatchType,
@ -54,20 +48,20 @@ const stage_updateSettingsStm = sql.prepare(/*sql*/ `
`);
export class Stage {
id?: TournamentStage["id"];
tournamentId: TournamentStage["tournamentId"];
number: TournamentStage["number"];
name: TournamentStage["name"];
id?: Tables["TournamentStage"]["id"];
tournamentId: Tables["TournamentStage"]["tournamentId"];
number: Tables["TournamentStage"]["number"];
name: Tables["TournamentStage"]["name"];
type: StageType["type"];
settings: TournamentStage["settings"];
settings: Tables["TournamentStage"]["settings"];
constructor(
id: TournamentStage["id"] | undefined,
tournamentId: TournamentStage["tournamentId"],
number: TournamentStage["number"],
name: TournamentStage["name"],
id: Tables["TournamentStage"]["id"] | undefined,
tournamentId: Tables["TournamentStage"]["tournamentId"],
number: Tables["TournamentStage"]["number"],
name: Tables["TournamentStage"]["name"],
type: StageType["type"],
settings: TournamentStage["settings"],
settings: Tables["TournamentStage"]["settings"],
) {
this.id = id;
this.tournamentId = tournamentId;
@ -92,7 +86,7 @@ export class Stage {
return true;
}
static #convertStage(rawStage: TournamentStage): StageType {
static #convertStage(rawStage: Tables["TournamentStage"]): StageType {
return {
id: rawStage.id,
name: rawStage.name,
@ -104,7 +98,7 @@ export class Stage {
};
}
static getById(id: TournamentStage["id"]): StageType {
static getById(id: Tables["TournamentStage"]["id"]): StageType {
const stage = stage_getByIdStm.get({ id }) as any;
if (!stage) return stage;
return Stage.#convertStage(stage);
@ -117,8 +111,8 @@ export class Stage {
}
static updateSettings(
id: TournamentStage["id"],
settings: TournamentStage["settings"],
id: Tables["TournamentStage"]["id"],
settings: Tables["TournamentStage"]["settings"],
) {
stage_updateSettingsStm.run({ id, settings });
@ -155,21 +149,21 @@ const group_insertStm = sql.prepare(/*sql*/ `
`);
export class Group {
id?: TournamentGroup["id"];
stageId: TournamentGroup["stageId"];
number: TournamentGroup["number"];
id?: Tables["TournamentGroup"]["id"];
stageId: Tables["TournamentGroup"]["stageId"];
number: Tables["TournamentGroup"]["number"];
constructor(
id: TournamentGroup["id"] | undefined,
stageId: TournamentGroup["stageId"],
number: TournamentGroup["number"],
id: Tables["TournamentGroup"]["id"] | undefined,
stageId: Tables["TournamentGroup"]["stageId"],
number: Tables["TournamentGroup"]["number"],
) {
this.id = id;
this.stageId = stageId;
this.number = number;
}
static #convertGroup(rawGroup: TournamentGroup): GroupType {
static #convertGroup(rawGroup: Tables["TournamentGroup"]): GroupType {
return {
id: rawGroup.id,
number: rawGroup.number,
@ -177,21 +171,21 @@ export class Group {
};
}
static getById(id: TournamentGroup["id"]): GroupType {
static getById(id: Tables["TournamentGroup"]["id"]): GroupType {
const group = group_getByIdStm.get({ id }) as any;
if (!group) return group;
return Group.#convertGroup(group);
}
static getByStageId(stageId: TournamentStage["id"]): GroupType[] {
static getByStageId(stageId: Tables["TournamentStage"]["id"]): GroupType[] {
return (group_getByStageIdStm.all({ stageId }) as any[]).map(
Group.#convertGroup,
);
}
static getByStageAndNumber(
stageId: TournamentStage["id"],
number: TournamentGroup["number"],
stageId: Tables["TournamentStage"]["id"],
number: Tables["TournamentGroup"]["number"],
): GroupType {
const group = group_getByStageAndNumberStm.get({ stageId, number }) as any;
if (!group) return group;
@ -245,17 +239,17 @@ const round_insertStm = sql.prepare(/*sql*/ `
`);
export class Round {
id?: TournamentRound["id"];
stageId: TournamentRound["stageId"];
groupId: TournamentRound["groupId"];
number: TournamentRound["number"];
id?: Tables["TournamentRound"]["id"];
stageId: Tables["TournamentRound"]["stageId"];
groupId: Tables["TournamentRound"]["groupId"];
number: Tables["TournamentRound"]["number"];
maps: Pick<TournamentRoundMaps, "count" | "type">;
constructor(
id: TournamentRound["id"] | undefined,
stageId: TournamentRound["stageId"],
groupId: TournamentRound["groupId"],
number: TournamentRound["number"],
id: Tables["TournamentRound"]["id"] | undefined,
stageId: Tables["TournamentRound"]["stageId"],
groupId: Tables["TournamentRound"]["groupId"],
number: Tables["TournamentRound"]["number"],
maps: Pick<TournamentRoundMaps, "count" | "type">,
) {
this.id = id;
@ -278,7 +272,7 @@ export class Round {
}
static #convertRound(
rawRound: TournamentRound & { maps?: string | null },
rawRound: Tables["TournamentRound"] & { maps?: string | null },
): RoundType {
const parsedMaps = rawRound.maps ? JSON.parse(rawRound.maps) : null;
@ -297,28 +291,28 @@ export class Round {
};
}
static getByStageId(stageId: TournamentStage["id"]): RoundType[] {
static getByStageId(stageId: Tables["TournamentStage"]["id"]): RoundType[] {
return (round_getByStageIdStm.all({ stageId }) as any[]).map(
Round.#convertRound,
);
}
static getByGroupId(groupId: TournamentGroup["id"]): RoundType[] {
static getByGroupId(groupId: Tables["TournamentGroup"]["id"]): RoundType[] {
return (round_getByGroupIdStm.all({ groupId }) as any[]).map(
Round.#convertRound,
);
}
static getByGroupAndNumber(
groupId: TournamentGroup["id"],
number: TournamentRound["number"],
groupId: Tables["TournamentGroup"]["id"],
number: Tables["TournamentRound"]["number"],
): RoundType {
const round = round_getByGroupAndNumberStm.get({ groupId, number }) as any;
if (!round) return round;
return Round.#convertRound(round);
}
static getById(id: TournamentRound["id"]): RoundType {
static getById(id: Tables["TournamentRound"]["id"]): RoundType {
const round = round_getByIdStm.get({ id }) as any;
if (!round) return round;
return Round.#convertRound(round);
@ -380,27 +374,27 @@ const match_updateStm = sql.prepare(/*sql*/ `
`);
export class Match {
id?: TournamentMatch["id"];
roundId: TournamentMatch["roundId"];
stageId: TournamentMatch["stageId"];
groupId: TournamentMatch["groupId"];
number: TournamentMatch["number"];
opponentOne: TournamentMatch["opponentOne"];
opponentTwo: TournamentMatch["opponentTwo"];
status: TournamentMatch["status"];
id?: Tables["TournamentMatch"]["id"];
roundId: Tables["TournamentMatch"]["roundId"];
stageId: Tables["TournamentMatch"]["stageId"];
groupId: Tables["TournamentMatch"]["groupId"];
number: Tables["TournamentMatch"]["number"];
opponentOne: string;
opponentTwo: string;
status: Tables["TournamentMatch"]["status"];
constructor(
id: TournamentMatch["id"] | undefined,
status: TournamentMatch["status"],
stageId: TournamentMatch["stageId"],
groupId: TournamentMatch["groupId"],
roundId: TournamentMatch["roundId"],
number: TournamentMatch["number"],
id: Tables["TournamentMatch"]["id"] | undefined,
status: Tables["TournamentMatch"]["status"],
stageId: Tables["TournamentMatch"]["stageId"],
groupId: Tables["TournamentMatch"]["groupId"],
roundId: Tables["TournamentMatch"]["roundId"],
number: Tables["TournamentMatch"]["number"],
_unknown1: null,
_unknown2: null,
_unknown3: null,
opponentOne: TournamentMatch["opponentOne"],
opponentTwo: TournamentMatch["opponentTwo"],
opponentOne: string,
opponentTwo: string,
) {
this.id = id;
this.roundId = roundId;
@ -413,7 +407,9 @@ export class Match {
}
static #convertMatch(
rawMatch: TournamentMatch & {
rawMatch: Tables["TournamentMatch"] & {
opponentOne: string;
opponentTwo: string;
opponentOnePointsTotal: number | null;
opponentTwoPointsTotal: number | null;
lastGameFinishedAt: number | null;
@ -446,27 +442,27 @@ export class Match {
};
}
static getById(id: TournamentMatch["id"]): MatchType {
static getById(id: Tables["TournamentMatch"]["id"]): MatchType {
const match = match_getByIdStm.get({ id }) as any;
if (!match) return match;
return Match.#convertMatch(match);
}
static getByRoundId(roundId: TournamentRound["id"]): MatchType[] {
static getByRoundId(roundId: Tables["TournamentRound"]["id"]): MatchType[] {
return (match_getByRoundIdStm.all({ roundId }) as any[]).map(
Match.#convertMatch,
);
}
static getByStageId(stageId: TournamentStage["id"]): MatchType[] {
static getByStageId(stageId: Tables["TournamentStage"]["id"]): MatchType[] {
return (match_getByStageIdStm.all({ stageId }) as any[]).map(
Match.#convertMatch,
);
}
static getByRoundAndNumber(
roundId: TournamentRound["id"],
number: TournamentMatch["number"],
roundId: Tables["TournamentRound"]["id"],
number: Tables["TournamentMatch"]["number"],
): MatchType {
const match = match_getByRoundAndNumberStm.get({ roundId, number }) as any;
if (!match) return match;

View File

@ -1,12 +1,6 @@
import shuffle from "just-shuffle";
import type { Rating } from "node_modules/openskill/dist/types";
import { ordinal } from "openskill";
import type {
MapResult,
PlayerResult,
Skill,
TournamentResult,
} from "~/db/types";
import {
identifierToUserIds,
rate,
@ -21,13 +15,16 @@ import type { Standing } from "./Bracket";
export interface TournamentSummary {
skills: Omit<
Skill,
Tables["Skill"],
"tournamentId" | "id" | "ordinal" | "season" | "groupMatchId"
>[];
seedingSkills: Tables["SeedingSkill"][];
mapResultDeltas: Omit<MapResult, "season">[];
playerResultDeltas: Omit<PlayerResult, "season">[];
tournamentResults: Omit<TournamentResult, "tournamentId" | "isHighlight">[];
mapResultDeltas: Omit<Tables["MapResult"], "season">[];
playerResultDeltas: Omit<Tables["PlayerResult"], "season">[];
tournamentResults: Omit<
Tables["TournamentResult"],
"tournamentId" | "isHighlight"
>[];
}
type UserIdToTeamId = Record<number, number>;
@ -294,7 +291,7 @@ function mapResultDeltas(
const result: TournamentSummary["mapResultDeltas"] = [];
const addMapResult = (
mapResult: Pick<MapResult, "stageId" | "mode" | "userId"> & {
mapResult: Pick<Tables["MapResult"], "stageId" | "mode" | "userId"> & {
type: "win" | "loss";
},
) => {

View File

@ -1,6 +1,6 @@
import { ordinal } from "openskill";
import { sql } from "~/db/sql";
import type { Skill } from "~/db/types";
import type { Tables } from "~/db/tables";
import { identifierToUserIds } from "~/features/mmr/mmr-utils";
import type { TournamentSummary } from "../core/summarizer.server";
@ -140,7 +140,7 @@ export const addSummary = sql.transaction(
identifier: skill.identifier ?? null,
matchesCount: skill.matchesCount,
season: season ?? null,
}) as Skill;
}) as Tables["Skill"];
if (insertedSkill.identifier) {
for (const userId of identifierToUserIds(insertedSkill.identifier)) {

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { TournamentMatch, TournamentRound } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
select
@ -13,8 +13,8 @@ const stm = sql.prepare(/* sql */ `
`);
interface BestOfByTournamentId {
roundId: TournamentRound["id"];
bestOf: TournamentMatch["bestOf"];
roundId: Tables["TournamentRound"]["id"];
bestOf: Tables["TournamentMatch"]["bestOf"];
}
export function bestOfsByTournamentId(tournamentId: number) {

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { MapPoolMap } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/*sql*/ `
select
@ -12,5 +12,7 @@ const stm = sql.prepare(/*sql*/ `
`);
export function findMapPoolByTeamId(teamId: number) {
return stm.all({ teamId }) as Array<Pick<MapPoolMap, "stageId" | "mode">>;
return stm.all({ teamId }) as Array<
Pick<Tables["MapPoolMap"], "stageId" | "mode">
>;
}

View File

@ -1,11 +1,5 @@
import { sql } from "~/db/sql";
import type { TournamentRoundMaps } from "~/db/tables";
import type {
Tournament,
TournamentMatch,
TournamentTeamMember,
User,
} from "~/db/types";
import type { Tables, TournamentRoundMaps } from "~/db/tables";
import type { Match } from "~/modules/brackets-model";
import { parseDBArray } from "~/utils/sql";
@ -57,10 +51,12 @@ export type FindMatchById = ReturnType<typeof findMatchById>;
export const findMatchById = (id: number) => {
const row = stm.get({ id }) as
| ((Pick<
TournamentMatch,
"id" | "groupId" | "opponentOne" | "opponentTwo" | "bestOf" | "chatCode"
Tables["TournamentMatch"],
"id" | "groupId" | "bestOf" | "chatCode"
> &
Pick<Tournament, "mapPickingStyle"> & { players: string }) & {
Pick<Tables["Tournament"], "mapPickingStyle"> & { players: string }) & {
opponentOne: string;
opponentTwo: string;
roundId: number;
roundMaps: string | null;
})
@ -81,13 +77,13 @@ export const findMatchById = (id: number) => {
opponentTwo: JSON.parse(row.opponentTwo) as Match["opponent2"],
players: (
parseDBArray(row.players) as Array<{
id: User["id"];
username: User["username"];
tournamentTeamId: TournamentTeamMember["tournamentTeamId"];
inGameName: User["inGameName"];
discordId: User["discordId"];
customUrl: User["customUrl"];
discordAvatar: User["discordAvatar"];
id: Tables["User"]["id"];
username: Tables["User"]["username"];
tournamentTeamId: Tables["TournamentTeamMember"]["tournamentTeamId"];
inGameName: Tables["User"]["inGameName"];
discordId: Tables["User"]["discordId"];
customUrl: Tables["User"]["customUrl"];
discordAvatar: Tables["User"]["discordAvatar"];
chatNameColor: string | null;
}>
).filter((player) => player.id),

View File

@ -1,6 +1,5 @@
import { sql } from "~/db/sql";
import type { Tables } from "~/db/tables";
import type { TournamentMatchGameResult } from "~/db/types";
import { parseDBArray } from "~/utils/sql";
const stm = sql.prepare(/* sql */ `
@ -27,17 +26,17 @@ const stm = sql.prepare(/* sql */ `
`);
interface FindResultsByMatchIdResult {
id: TournamentMatchGameResult["id"];
winnerTeamId: TournamentMatchGameResult["winnerTeamId"];
stageId: TournamentMatchGameResult["stageId"];
mode: TournamentMatchGameResult["mode"];
id: Tables["TournamentMatchGameResult"]["id"];
winnerTeamId: Tables["TournamentMatchGameResult"]["winnerTeamId"];
stageId: Tables["TournamentMatchGameResult"]["stageId"];
mode: Tables["TournamentMatchGameResult"]["mode"];
participants: Array<
Pick<
Tables["TournamentMatchGameResultParticipant"],
"tournamentTeamId" | "userId"
>
>;
createdAt: TournamentMatchGameResult["createdAt"];
createdAt: Tables["TournamentMatchGameResult"]["createdAt"];
opponentOnePoints: Tables["TournamentMatchGameResult"]["opponentOnePoints"];
opponentTwoPoints: Tables["TournamentMatchGameResult"]["opponentTwoPoints"];
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { MapPoolMap } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/*sql*/ `
select
@ -17,6 +17,6 @@ const stm = sql.prepare(/*sql*/ `
export function findTieBreakerMapPoolByTournamentId(tournamentId: number) {
return stm.all({ tournamentId }) as Array<
Pick<MapPoolMap, "stageId" | "mode">
Pick<Tables["MapPoolMap"], "stageId" | "mode">
>;
}

View File

@ -1,6 +1,5 @@
import { sql } from "~/db/sql";
import type { Tables } from "~/db/tables";
import type { TournamentMatchGameResult } from "~/db/types";
const stm = sql.prepare(/* sql */ `
insert into "TournamentMatchGameResult"
@ -13,5 +12,5 @@ const stm = sql.prepare(/* sql */ `
export function insertTournamentMatchGameResult(
args: Omit<Tables["TournamentMatchGameResult"], "id" | "createdAt">,
) {
return stm.get(args) as TournamentMatchGameResult;
return stm.get(args) as Tables["TournamentMatchGameResult"];
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { User } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
select
@ -26,7 +26,7 @@ const stm = sql.prepare(/* sql */ `
`);
export type PlayerThatPlayedByTeamId = Pick<
User,
Tables["User"],
"id" | "username" | "discordAvatar" | "discordId" | "customUrl" | "country"
> & { tournamentTeamId: number };

View File

@ -1,6 +1,5 @@
import type { TFunction } from "i18next";
import type { TournamentRoundMaps } from "~/db/tables";
import type { TournamentMatch } from "~/db/types";
import type { Tables, TournamentRoundMaps } from "~/db/tables";
import type { TournamentManagerDataSet } from "~/modules/brackets-manager/types";
import type { ModeShort, StageId } from "~/modules/in-game-lists";
import type { TournamentMaplistSource } from "~/modules/tournament-map-list-generator";
@ -28,7 +27,7 @@ const NUM_MAP = {
"9": ["9", "6", "8"],
"0": ["0", "8"],
};
export function resolveRoomPass(matchId: TournamentMatch["id"]) {
export function resolveRoomPass(matchId: Tables["TournamentMatch"]["id"]) {
let pass = "5";
for (let i = 0; i < 3; i++) {
const { shuffle } = seededRandom(`${matchId}-${i}`);

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { TournamentSub } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
delete from "TournamentSub"
@ -9,7 +9,7 @@ const stm = sql.prepare(/* sql */ `
`);
export function deleteSub(
args: Pick<TournamentSub, "userId" | "tournamentId">,
args: Pick<Tables["TournamentSub"], "userId" | "tournamentId">,
) {
stm.run(args);
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { TournamentSub, UserWithPlusTier } from "~/db/types";
import type { Tables, UserWithPlusTier } from "~/db/tables";
import type { MainWeaponId } from "~/modules/in-game-lists";
const stm = sql.prepare(/* sql */ `
@ -31,13 +31,13 @@ const stm = sql.prepare(/* sql */ `
`);
export interface SubByTournamentId {
canVc: TournamentSub["canVc"];
canVc: Tables["TournamentSub"]["canVc"];
bestWeapons: MainWeaponId[];
okWeapons: MainWeaponId[] | null;
message: TournamentSub["message"];
visibility: TournamentSub["visibility"];
createdAt: TournamentSub["createdAt"];
userId: TournamentSub["userId"];
message: Tables["TournamentSub"]["message"];
visibility: Tables["TournamentSub"]["visibility"];
createdAt: Tables["TournamentSub"]["createdAt"];
userId: Tables["TournamentSub"]["userId"];
username: UserWithPlusTier["username"];
discordAvatar: UserWithPlusTier["discordAvatar"];
discordId: UserWithPlusTier["discordId"];

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { TournamentSub } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
insert into "TournamentSub" (
@ -30,6 +30,6 @@ const stm = sql.prepare(/* sql */ `
"visibility" = @visibility
`);
export function upsertSub(args: Omit<TournamentSub, "createdAt">) {
export function upsertSub(args: Omit<Tables["TournamentSub"], "createdAt">) {
stm.run(args);
}

View File

@ -2,7 +2,7 @@ import { Link } from "@remix-run/react";
import clsx from "clsx";
import { Avatar } from "~/components/Avatar";
import { ModeImage, StageImage } from "~/components/Image";
import type { MapPoolMap, User } from "~/db/types";
import type { Tables } from "~/db/tables";
import { useUser } from "~/features/auth/core/user";
import type { TournamentDataTeam } from "~/features/tournament-bracket/core/Tournament.server";
import { databaseTimestampToDate } from "~/utils/dates";
@ -18,10 +18,10 @@ export function TeamWithRoster({
activePlayers,
}: {
team: TournamentDataTeam;
mapPool?: Array<Pick<MapPoolMap, "stageId" | "mode">> | null;
mapPool?: Array<Pick<Tables["MapPoolMap"], "stageId" | "mode">> | null;
seed?: number;
teamPageUrl?: string;
activePlayers?: User["id"][];
activePlayers?: Tables["User"]["id"][];
}) {
const user = useUser();
const tournament = useTournament();
@ -136,7 +136,7 @@ function FreshAccountEmoji({ discordId }: { discordId: string }) {
function TeamMapPool({
mapPool,
}: {
mapPool: Array<Pick<MapPoolMap, "stageId" | "mode">>;
mapPool: Array<Pick<Tables["MapPoolMap"], "stageId" | "mode">>;
}) {
return (
<div

View File

@ -1,5 +1,4 @@
import type { Tables } from "~/db/tables";
import type { User } from "~/db/types";
import type { ModeShort, StageId } from "~/modules/in-game-lists";
import type { TournamentMaplistSource } from "~/modules/tournament-map-list-generator";
import { sourceTypes } from "~/modules/tournament-map-list-generator";
@ -31,7 +30,7 @@ export interface PlayedSet {
/** Team's roster that played in this set */
roster: Array<
Pick<
User,
Tables["User"],
"id" | "username" | "discordAvatar" | "discordId" | "customUrl"
>
>;

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { TournamentTeam, User } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/* sql */ `
update TournamentTeamMember
@ -11,9 +11,9 @@ const stm = sql.prepare(/* sql */ `
export const changeTeamOwner = sql.transaction(
(args: {
tournamentTeamId: TournamentTeam["id"];
oldCaptainId: User["id"];
newCaptainId: User["id"];
tournamentTeamId: Tables["TournamentTeam"]["id"];
oldCaptainId: Tables["User"]["id"];
newCaptainId: Tables["User"]["id"];
}) => {
stm.run({
tournamentTeamId: args.tournamentTeamId,

View File

@ -1,11 +1,5 @@
import { sql } from "~/db/sql";
import type { Tables } from "~/db/tables";
import type {
CalendarEvent,
CalendarEventDate,
Tournament,
User,
} from "~/db/types";
const stm = sql.prepare(/*sql*/ `
select
@ -29,13 +23,13 @@ select
`);
type FindByIdentifierRow = (Pick<
CalendarEvent,
Tables["CalendarEvent"],
"bracketUrl" | "name" | "description" | "authorId"
> &
Pick<Tournament, "id" | "mapPickingStyle"> &
Pick<User, "discordId" | "username"> &
Pick<CalendarEventDate, "startTime">) & {
eventId: CalendarEvent["id"];
Pick<Tables["Tournament"], "id" | "mapPickingStyle"> &
Pick<Tables["User"], "discordId" | "username"> &
Pick<Tables["CalendarEventDate"], "startTime">) & {
eventId: Tables["CalendarEvent"]["id"];
} & { settings: string };
export function findByIdentifier(identifier: string | number) {
@ -59,7 +53,7 @@ export function findByIdentifier(identifier: string | number) {
}
function resolveEarliestStartTime(
rows: Pick<CalendarEventDate, "startTime">[],
rows: Pick<Tables["CalendarEventDate"], "startTime">[],
) {
return Math.min(...rows.map((row) => row.startTime));
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { MapPoolMap } from "~/db/types";
import type { Tables } from "~/db/tables";
import { parseDBArray } from "~/utils/sql";
const stm = sql.prepare(/*sql*/ `
@ -20,7 +20,7 @@ const stm = sql.prepare(/*sql*/ `
interface FindMapPoolsByTournamentIdItem {
tournamentTeamId: number;
mapPool: Array<Pick<MapPoolMap, "mode" | "stageId">>;
mapPool: Array<Pick<Tables["MapPoolMap"], "mode" | "stageId">>;
}
export function findMapPoolsByTournamentId(

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { TournamentTeam, TournamentTeamCheckIn } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/*sql*/ `
select
@ -20,8 +20,8 @@ const stm = sql.prepare(/*sql*/ `
`);
type FindOwnTeam =
| (Pick<TournamentTeam, "id" | "name" | "inviteCode"> &
Pick<TournamentTeamCheckIn, "checkedInAt">)
| (Pick<Tables["TournamentTeam"], "id" | "name" | "inviteCode"> &
Pick<Tables["TournamentTeamCheckIn"], "checkedInAt">)
| null;
export function findOwnTournamentTeam({

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { Tournament } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/*sql*/ `
select 1
@ -7,6 +7,8 @@ const stm = sql.prepare(/*sql*/ `
where "TournamentResult"."tournamentId" = @tournamentId
`);
export default function hasTournamentFinalized(tournamentId: Tournament["id"]) {
export default function hasTournamentFinalized(
tournamentId: Tables["Tournament"]["id"],
) {
return Boolean(stm.get({ tournamentId }));
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { Tournament } from "~/db/types";
import type { Tables } from "~/db/tables";
const stm = sql.prepare(/*sql*/ `
select 1
@ -7,6 +7,8 @@ const stm = sql.prepare(/*sql*/ `
where "TournamentStage"."tournamentId" = @tournamentId
`);
export default function hasTournamentStarted(tournamentId: Tournament["id"]) {
export default function hasTournamentStarted(
tournamentId: Tables["Tournament"]["id"],
) {
return Boolean(stm.get({ tournamentId }));
}

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { TournamentMatchGameResult, User } from "~/db/types";
import type { Tables } from "~/db/tables";
import type { ModeShort, StageId } from "~/modules/in-game-lists";
import { removeDuplicatesByProperty } from "~/utils/arrays";
import { parseDBArray } from "~/utils/sql";
@ -89,12 +89,15 @@ export interface SetHistoryByTeamIdItem {
groupNumber: number;
matches: {
stageId: StageId;
source: TournamentMatchGameResult["source"];
source: Tables["TournamentMatchGameResult"]["source"];
mode: ModeShort;
wasWinner: number;
}[];
players: Array<
Pick<User, "id" | "username" | "discordAvatar" | "discordId" | "customUrl">
Pick<
Tables["User"],
"id" | "username" | "discordAvatar" | "discordId" | "customUrl"
>
>;
}
@ -110,7 +113,7 @@ export function setHistoryByTeamId(
// TODO: there is probably a way to do this in SQL
players: removeDuplicatesByProperty(
parseDBArray(row.players),
(u: Pick<User, "id">) => u.id,
(u: Pick<Tables["User"], "id">) => u.id,
),
};
});

View File

@ -1,5 +1,5 @@
import { sql } from "~/db/sql";
import type { TournamentTeam } from "~/db/types";
import type { Tables } from "~/db/tables";
import type { MapPool } from "~/features/map-list-generator/core/map-pool";
const deleteCounterpickMapsByTeamIdStm = sql.prepare(/* sql */ `
@ -21,7 +21,7 @@ export const upsertCounterpickMaps = sql.transaction(
tournamentTeamId,
mapPool,
}: {
tournamentTeamId: TournamentTeam["id"];
tournamentTeamId: Tables["TournamentTeam"]["id"];
mapPool: MapPool;
}) => {
deleteCounterpickMapsByTeamIdStm.run({ tournamentTeamId });

View File

@ -1,5 +1,4 @@
import type { Params } from "@remix-run/react";
import type { Tournament } from "~/db/types";
import type { ModeShort, StageId } from "~/modules/in-game-lists";
import { rankedModesShort } from "~/modules/in-game-lists/modes";
import { weekNumberToDate } from "~/utils/dates";
@ -23,7 +22,7 @@ export function tournamentIdFromParams(params: Params<string>) {
}
export function modesIncluded(
tournament: Pick<Tournament, "mapPickingStyle">,
tournament: Pick<Tables["Tournament"], "mapPickingStyle">,
): ModeShort[] {
switch (tournament.mapPickingStyle) {
case "AUTO_SZ": {
@ -45,7 +44,7 @@ export function modesIncluded(
}
export function isOneModeTournamentOf(
tournament: Pick<Tournament, "mapPickingStyle">,
tournament: Pick<Tables["Tournament"], "mapPickingStyle">,
) {
return modesIncluded(tournament).length === 1
? modesIncluded(tournament)[0]

View File

@ -5,10 +5,10 @@ import { db, sql as dbDirect } from "~/db/sql";
import type {
BuildSort,
DB,
Tables,
TablesInsertable,
UserPreferences,
} from "~/db/tables";
import type { User } from "~/db/types";
import { dateToDatabaseTimestamp } from "~/utils/dates";
import invariant from "~/utils/invariant";
import type { CommonUser } from "~/utils/kysely.server";
@ -744,7 +744,7 @@ export function updateBuildSorting({
}
export type UpdatePatronDataArgs = Array<
Pick<User, "discordId" | "patronTier" | "patronSince">
Pick<Tables["User"], "discordId" | "patronTier" | "patronSince">
>;
export function updatePatronData(users: UpdatePatronDataArgs) {
return db.transaction().execute(async (trx) => {
@ -792,7 +792,7 @@ export const updateMany = dbDirect.transaction(
(
argsArr: Array<
Pick<
User,
Tables["User"],
"discordAvatar" | "discordName" | "discordUniqueName" | "discordId"
>
>,

View File

@ -19,7 +19,6 @@ import { SubmitButton } from "~/components/SubmitButton";
import { CrossIcon } from "~/components/icons/Cross";
import { PlusIcon } from "~/components/icons/Plus";
import { BUILD } from "~/constants";
import type { GearType } from "~/db/types";
import {
validatedBuildFromSearchParams,
validatedWeaponIdFromSearchParams,
@ -35,6 +34,7 @@ import type { SendouRouteHandle } from "~/utils/remix.server";
import { modeImageUrl } from "~/utils/urls";
import type { UserPageLoaderData } from "./u.$identifier";
import type { GearType } from "~/db/tables";
import { action } from "../actions/u.$identifier.builds.new.server";
import { loader } from "../loaders/u.$identifier.builds.new.server";
export { loader, action };

View File

@ -22,7 +22,6 @@ import { StarIcon } from "~/components/icons/Star";
import { StarFilledIcon } from "~/components/icons/StarFilled";
import { TrashIcon } from "~/components/icons/Trash";
import { USER } from "~/constants";
import type { User } from "~/db/types";
import { useUser } from "~/features/auth/core/user";
import { requireUser, requireUserId } from "~/features/auth/core/user.server";
import * as TournamentTeamRepository from "~/features/tournament/TournamentTeamRepository.server";
@ -56,6 +55,7 @@ import { userParamsSchema } from "../user-page-schemas.server";
import type { UserPageLoaderData } from "./u.$identifier";
import "~/styles/u-edit.css";
import { SendouSwitch } from "~/components/elements/Switch";
import type { Tables } from "~/db/tables";
import { clearTournamentDataCache } from "~/features/tournament-bracket/core/Tournament.server";
export const userEditActionSchema = z
@ -555,7 +555,9 @@ function WeaponPoolSelect() {
);
}
function BioTextarea({ initialValue }: { initialValue: User["bio"] }) {
function BioTextarea({
initialValue,
}: { initialValue: Tables["User"]["bio"] }) {
const { t } = useTranslation("user");
const [value, setValue] = React.useState(initialValue ?? "");
@ -664,7 +666,7 @@ function CommissionsOpenToggle({
function CommissionTextArea({
initialValue,
}: {
initialValue: User["commissionText"];
initialValue: Tables["User"]["commissionText"];
}) {
const { t } = useTranslation(["user"]);
const [value, setValue] = React.useState(initialValue ?? "");

Some files were not shown because too many files have changed in this diff Show More