opt(tierlist): parallelize ssr queries

This commit is contained in:
2026-04-09 17:02:29 +07:00 Unverified
parent 37b31c782c
commit e376dd77bf
8 changed files with 79 additions and 48 deletions
+1 -1
View File
@@ -4,9 +4,9 @@ import Link from "next/link";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import Avatar from "@/components/avatar"; import Avatar from "@/components/avatar";
import SearchBox, { type Filters, type ParsedQuery } from "@/components/search"; import SearchBox, { type Filters, type ParsedQuery } from "@/components/search";
import { SimpleTooltip } from "@/components/tooltip";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { type characters, element } from "@/lib/db/schema"; import { type characters, element } from "@/lib/db/schema";
import { SimpleTooltip } from "@/components/tooltip";
/** Filters and their value providers */ /** Filters and their value providers */
const filters: Filters = { const filters: Filters = {
+1 -1
View File
@@ -24,6 +24,7 @@ import {
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Kbd } from "@/components/ui/kbd";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import { Tooltip, TooltipContent } from "@/components/ui/tooltip"; import { Tooltip, TooltipContent } from "@/components/ui/tooltip";
@@ -34,7 +35,6 @@ import { CharacterChooser, ClearCookie, Disclaimer } from "./client";
import { ArtifactFormWrapper } from "./form"; import { ArtifactFormWrapper } from "./form";
import { LiveButton } from "./live"; import { LiveButton } from "./live";
import { RulesDialog } from "./rules"; import { RulesDialog } from "./rules";
import { Kbd } from "@/components/ui/kbd";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "เสือกไอดีชาวบ้าน", title: "เสือกไอดีชาวบ้าน",
+1 -1
View File
@@ -3,9 +3,9 @@ import Link from "next/link";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import Banner from "#/banner_t.webp"; import Banner from "#/banner_t.webp";
import ArtifactLogo from "#/logos/artifact.webp"; import ArtifactLogo from "#/logos/artifact.webp";
import GuideLogo from "#/logos/guide.webp";
import RubgramLogo from "#/logos/rubgram.webp"; import RubgramLogo from "#/logos/rubgram.webp";
import TierlistLogo from "#/logos/tierlist.webp"; import TierlistLogo from "#/logos/tierlist.webp";
import GuideLogo from "#/logos/guide.webp";
import Image from "@/components/image"; import Image from "@/components/image";
import { SimpleTooltip } from "@/components/tooltip"; import { SimpleTooltip } from "@/components/tooltip";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
+1 -1
View File
@@ -36,9 +36,9 @@ import {
TooltipTrigger, TooltipTrigger,
} from "@/components/ui/tooltip"; } from "@/components/ui/tooltip";
import { shared } from "@/lib/comms"; import { shared } from "@/lib/comms";
import { sse } from "@/lib/db/sse-endpoints";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { setFree, setLimit, toggleCheck, toggleLock } from "../api"; import { setFree, setLimit, toggleCheck, toggleLock } from "../api";
import { sse } from "@/lib/db/sse-endpoints";
export function SidebarLink({ export function SidebarLink({
submission, submission,
+14 -15
View File
@@ -84,21 +84,20 @@ export default async function TierlistPage({
: ([] as (typeof characters.$inferSelect)[]); : ([] as (typeof characters.$inferSelect)[]);
// fetch rows, columns, badges data... // fetch rows, columns, badges data...
const tiers = await tx const [tiers, columns, badgesList] = await Promise.all([
.select() tx.select().from(tierlistTiers).orderBy(tierlistTiers.order),
.from(tierlistTiers) tx.select().from(tierlistColumns).orderBy(tierlistColumns.order),
.orderBy(tierlistTiers.order); tx
const columns = await tx .select()
.select() .from(tierlistBadges)
.from(tierlistColumns) .orderBy(tierlistBadges.order)
.orderBy(tierlistColumns.order); .where(
const badgesList = await tx or(
.select() isNull(tierlistBadges.type),
.from(tierlistBadges) eq(tierlistBadges.type, version.type),
.orderBy(tierlistBadges.order) ),
.where( ),
or(isNull(tierlistBadges.type), eq(tierlistBadges.type, version.type)), ]);
);
const badges = badgesList.map((b) => ({ const badges = badgesList.map((b) => ({
...b, ...b,
tier: tiers.filter((t) => t.badges?.includes(b.id)).map((t) => t.id), tier: tiers.filter((t) => t.badges?.includes(b.id)).map((t) => t.id),
+3 -3
View File
@@ -15,11 +15,11 @@ import {
CopyPlus, CopyPlus,
FileQuestionMark, FileQuestionMark,
Home, Home,
TriangleAlert,
Pencil, Pencil,
Settings, Settings,
Settings2, Settings2,
Trash2, Trash2,
TriangleAlert,
X, X,
} from "lucide-react"; } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
@@ -64,6 +64,7 @@ import {
TooltipTrigger, TooltipTrigger,
} from "@/components/ui/tooltip"; } from "@/components/ui/tooltip";
import { tlPlacements, tlState } from "@/lib/api"; import { tlPlacements, tlState } from "@/lib/api";
import { authClient } from "@/lib/auth-client";
import { shared } from "@/lib/comms"; import { shared } from "@/lib/comms";
import type { import type {
characters, characters,
@@ -74,12 +75,11 @@ import type {
tierlistTypes, tierlistTypes,
tierlistVersions, tierlistVersions,
} from "@/lib/db/schema"; } from "@/lib/db/schema";
import { authClient } from "@/lib/auth-client"; import { tlSse } from "@/lib/db/sse-endpoints";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { TierListCell } from "./cell"; import { TierListCell } from "./cell";
import { Draggable } from "./character"; import { Draggable } from "./character";
import { TierListContext } from "./context"; import { TierListContext } from "./context";
import { tlSse } from "@/lib/db/sse-endpoints";
function Untiered({ function Untiered({
children, children,
+28 -13
View File
@@ -1,10 +1,10 @@
import { desc, eq, not } from "drizzle-orm"; import { and, eq, getTableColumns, not, sql } from "drizzle-orm";
import { ArrowLeft } from "lucide-react";
import type { Metadata } from "next"; import type { Metadata } from "next";
import Link from "next/link"; import Link from "next/link";
import Image from "@/components/image"; import Image from "@/components/image";
import { db } from "@/lib/db"; import { db } from "@/lib/db";
import { tierlistTypes, tierlistVersions } from "@/lib/db/schema"; import { tierlistTypes, tierlistVersions } from "@/lib/db/schema";
import { ArrowLeft } from "lucide-react";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "จัดเทียร์ลิสต์", title: "จัดเทียร์ลิสต์",
@@ -17,19 +17,34 @@ export default async function TierlistSelectionPage({
params: Promise<{ type: string }>; params: Promise<{ type: string }>;
}) { }) {
const { type: typeId } = await params; const { type: typeId } = await params;
const types = await db const vers = await db
.select() .select({
...getTableColumns(tierlistTypes),
versions: sql<(typeof tierlistVersions.$inferSelect)[]>`
COALESCE(
json_agg(
json_build_object(
'id', ${tierlistVersions.id},
'name', ${tierlistVersions.name},
'image', ${tierlistVersions.image}
) ORDER BY ${tierlistVersions.order} DESC)
FILTER (WHERE ${tierlistVersions.id} IS NOT NULL),
'[]'
)
`.as("versions"),
})
.from(tierlistTypes) .from(tierlistTypes)
.leftJoin(
tierlistVersions,
and(
eq(tierlistVersions.type, tierlistTypes.id),
not(tierlistVersions.hidden),
),
)
.groupBy(tierlistTypes.id)
.orderBy(tierlistTypes.id)
.where(eq(tierlistTypes.id, typeId)); .where(eq(tierlistTypes.id, typeId));
const versionsList = await db
.select()
.from(tierlistVersions)
.orderBy(desc(tierlistVersions.order))
.where(not(tierlistVersions.hidden));
const vers = types.map((t) => ({
...t,
versions: versionsList.filter((v) => v.type === t.id),
}));
return ( return (
<div className="max-w-7xl min-h-full flex flex-col gap-6 mx-auto py-8 px-4"> <div className="max-w-7xl min-h-full flex flex-col gap-6 mx-auto py-8 px-4">
{vers.map((t) => ( {vers.map((t) => (
+30 -13
View File
@@ -1,14 +1,14 @@
import { desc, not } from "drizzle-orm"; import { and, eq, getTableColumns, not, sql } from "drizzle-orm";
import { ArrowRight } from "lucide-react";
import type { Metadata } from "next"; import type { Metadata } from "next";
import Link from "next/link"; import Link from "next/link";
import TierlistLogo from "#/logos/tierlist.webp"; import TierlistLogo from "#/logos/tierlist.webp";
import { HorizontalDiv } from "@/components/horizontal"; import { HorizontalDiv } from "@/components/horizontal";
import { SimpleTooltip } from "@/components/tooltip";
import Image from "@/components/image"; import Image from "@/components/image";
import { SimpleTooltip } from "@/components/tooltip";
import { ScrollBar } from "@/components/ui/scroll-area"; import { ScrollBar } from "@/components/ui/scroll-area";
import { db } from "@/lib/db"; import { db } from "@/lib/db";
import { tierlistTypes, tierlistVersions } from "@/lib/db/schema"; import { tierlistTypes, tierlistVersions } from "@/lib/db/schema";
import { ArrowRight } from "lucide-react";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "จัดเทียร์ลิสต์", title: "จัดเทียร์ลิสต์",
@@ -16,16 +16,33 @@ export const metadata: Metadata = {
}; };
export default async function TierlistSelectionPage() { export default async function TierlistSelectionPage() {
const types = await db.select().from(tierlistTypes).orderBy(tierlistTypes.id); const vers = await db
const versionsList = await db .select({
.select() ...getTableColumns(tierlistTypes),
.from(tierlistVersions) versions: sql<(typeof tierlistVersions.$inferSelect)[]>`
.orderBy(desc(tierlistVersions.order)) COALESCE(
.where(not(tierlistVersions.hidden)); json_agg(
const vers = types.map((t) => ({ json_build_object(
...t, 'id', ${tierlistVersions.id},
versions: versionsList.filter((v) => v.type === t.id), 'name', ${tierlistVersions.name},
})); 'image', ${tierlistVersions.image}
) ORDER BY ${tierlistVersions.order} DESC)
FILTER (WHERE ${tierlistVersions.id} IS NOT NULL),
'[]'
)
`.as("versions"),
})
.from(tierlistTypes)
.leftJoin(
tierlistVersions,
and(
eq(tierlistVersions.type, tierlistTypes.id),
not(tierlistVersions.hidden),
),
)
.groupBy(tierlistTypes.id)
.orderBy(tierlistTypes.id);
return ( return (
<div className="max-w-full min-h-full flex flex-col justify-center gap-2 mx-2"> <div className="max-w-full min-h-full flex flex-col justify-center gap-2 mx-2">
<center className="mb-2"> <center className="mb-2">