From 5307da48aebddeec26d018b2a81dae4f73618ffa Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Tue, 20 Jan 2026 18:00:07 +0200 Subject: [PATCH] Build by weapon loader refactoring --- app/features/builds/BuildRepository.server.ts | 12 +++---- .../builds/loaders/builds.$slug.server.ts | 33 ++++++++++--------- app/utils/unslugify.server.ts | 19 ++++++----- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/app/features/builds/BuildRepository.server.ts b/app/features/builds/BuildRepository.server.ts index 1e5394d37..13ef3b97f 100644 --- a/app/features/builds/BuildRepository.server.ts +++ b/app/features/builds/BuildRepository.server.ts @@ -1,5 +1,5 @@ import type { ExpressionBuilder, Transaction } from "kysely"; -import { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite"; +import { jsonArrayFrom } from "kysely/helpers/sqlite"; import { db } from "~/db/sql"; import type { BuildWeapon, DB, Tables, TablesInsertable } from "~/db/tables"; import { modesShort } from "~/modules/in-game-lists/modes"; @@ -12,7 +12,7 @@ import type { import { weaponIdToArrayWithAlts } from "~/modules/in-game-lists/weapon-ids"; import { LimitReachedError } from "~/utils/errors"; import invariant from "~/utils/invariant"; -import { COMMON_USER_FIELDS } from "~/utils/kysely.server"; +import { commonUserJsonObject } from "~/utils/kysely.server"; import { BUILD } from "./builds-constants"; import { sortAbilities } from "./core/ability-sorting.server"; @@ -349,6 +349,7 @@ function buildsByWeaponIdQuery(weaponSplId: MainWeaponId, limit: number) { return db .selectFrom("BuildWeapon") .innerJoin("Build", "Build.id", "BuildWeapon.buildId") + .innerJoin("User", "User.id", "Build.ownerId") .leftJoin("PlusTier", "PlusTier.userId", "Build.ownerId") .select(({ eb }) => [ "Build.id", @@ -372,12 +373,7 @@ function buildsByWeaponIdQuery(weaponSplId: MainWeaponId, limit: number) { .orderBy("BuildWeaponInner.weaponSplId", "asc") .whereRef("BuildWeaponInner.buildId", "=", "Build.id"), ).as("weapons"), - jsonObjectFrom( - eb - .selectFrom("User") - .select([...COMMON_USER_FIELDS]) - .whereRef("User.id", "=", "Build.ownerId"), - ).as("owner"), + commonUserJsonObject(eb).as("owner"), ]) .where("Build.private", "=", 0) .where("BuildWeapon.weaponSplId", "=", weaponSplId) diff --git a/app/features/builds/loaders/builds.$slug.server.ts b/app/features/builds/loaders/builds.$slug.server.ts index 1d6faa6bb..6e88bd4e6 100644 --- a/app/features/builds/loaders/builds.$slug.server.ts +++ b/app/features/builds/loaders/builds.$slug.server.ts @@ -2,7 +2,6 @@ import type { LoaderFunctionArgs } from "react-router"; import { getUser } from "~/features/auth/core/user.server"; import { i18next } from "~/modules/i18n/i18next.server"; import { weaponIdToType } from "~/modules/in-game-lists/weapon-ids"; -import { logger } from "~/utils/logger"; import { weaponNameSlugToId } from "~/utils/unslugify.server"; import { mySlugify } from "~/utils/urls"; import * as BuildRepository from "../BuildRepository.server"; @@ -35,27 +34,17 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => { const slug = mySlugify(t(`weapons:MAIN_${weaponId}`, { lng: "en" })); - const rawFilters = url.searchParams.get(FILTER_SEARCH_PARAM_KEY); - const filters = buildFiltersSearchParams.safeParse(rawFilters ?? "[]"); - const hasActiveFilters = - filters.success && filters.data && filters.data.length > 0; + const filters = resolveFilters(url.searchParams.get(FILTER_SEARCH_PARAM_KEY)); const builds = await BuildRepository.allByWeaponId(weaponId, { - limit: hasActiveFilters ? BUILDS_PAGE_MAX_BUILDS : limit + 1, + limit: filters ? BUILDS_PAGE_MAX_BUILDS : limit + 1, sortAbilities: !user?.preferences?.disableBuildAbilitySorting, }); - if (!filters.success) { - logger.error( - "Invalid filters", - JSON.stringify(filters.error.issues, null, 2), - ); - } - - const filteredBuilds = hasActiveFilters + const filteredBuilds = filters ? filterBuilds({ builds, - filters: filters.data!, + filters, count: limit + 1, }) : builds; @@ -76,6 +65,18 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => { limit, hasMoreBuilds, slug, - filters: filters.success ? filters.data : [], + filters: filters ?? [], }; }; + +function resolveFilters(rawFilters: string | null) { + if (!rawFilters) return null; + + const filters = buildFiltersSearchParams.safeParse(rawFilters); + const hasActiveFilters = + filters.success && filters.data && filters.data.length > 0; + + if (!hasActiveFilters) return null; + + return filters.data; +} diff --git a/app/utils/unslugify.server.ts b/app/utils/unslugify.server.ts index 30592f3bc..e5aea25ea 100644 --- a/app/utils/unslugify.server.ts +++ b/app/utils/unslugify.server.ts @@ -2,16 +2,17 @@ import type { MainWeaponId } from "~/modules/in-game-lists/types"; import weaponTranslations from "../../locales/en/weapons.json"; import { mySlugify } from "./urls"; +const SLUG_TO_WEAPON_ID = Object.fromEntries( + Object.entries(weaponTranslations) + .filter(([id]) => id.startsWith("MAIN")) + .map(([id, name]) => [ + mySlugify(name), + Number(id.replace("MAIN_", "")) as MainWeaponId, + ]), +) as Record; + export function weaponNameSlugToId(slug?: string) { if (!slug) return null; - for (const [id, name] of Object.entries(weaponTranslations)) { - if (!id.startsWith("MAIN")) continue; - - if (mySlugify(name) === slug.toLowerCase()) { - return Number(id.replace("MAIN_", "")) as MainWeaponId; - } - } - - return null; + return SLUG_TO_WEAPON_ID[slug.toLowerCase()] ?? null; }