refactor(db): migrate app pages and APIs from Prisma facade to Drizzle (3)

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-08-01 14:15:32 +02:00
1 parent 2cd0863cb8
commit 580972c0a0
40 files changed
+1089 -808

No files matched your search

+37 -31
View File
@@ -1,7 +1,8 @@
import { sql } from "drizzle-orm";
import { redirect } from "next/navigation";
import { calcPagination, parseListParams } from "@/lib/admin-helpers";
import { db } from "@/lib/db";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
type ListParamsInput = {
searchParams: Promise<Record<string, string>>;
@@ -25,6 +26,11 @@ function parsePageParams(
return { search: parsed.search.trim(), page: parsed.page, perPage };
}
async function rawRows<T>(query: ReturnType<typeof sql>): Promise<T[]> {
const [rows] = (await db.execute(query)) as unknown as [T[], unknown];
return rows ?? [];
}
export type ChatLogListRow = {
id: number;
username: string;
@@ -51,35 +57,35 @@ export async function loadChatLogList({
username: string | null;
};
const [rawRows, countRows] = search
const [rawRowsResult, countRows] = search
? await Promise.all([
prisma.$queryRaw<RawRow[]>`
rawRows<RawRow>(sql`
SELECT c.room_id AS roomId, c.message, c.timestamp, u.username AS username
FROM chatlogs_room c
LEFT JOIN users u ON u.id = c.user_from_id
WHERE c.message LIKE ${like} OR u.username LIKE ${like}
ORDER BY c.timestamp DESC
LIMIT ${perPage} OFFSET ${offset}`,
prisma.$queryRaw<{ count: bigint }[]>`
LIMIT ${perPage} OFFSET ${offset}`),
rawRows<{ count: bigint }>(sql`
SELECT COUNT(*) AS count
FROM chatlogs_room c
LEFT JOIN users u ON u.id = c.user_from_id
WHERE c.message LIKE ${like} OR u.username LIKE ${like}`,
WHERE c.message LIKE ${like} OR u.username LIKE ${like}`),
])
: await Promise.all([
prisma.$queryRaw<RawRow[]>`
rawRows<RawRow>(sql`
SELECT c.room_id AS roomId, c.message, c.timestamp, u.username AS username
FROM chatlogs_room c
LEFT JOIN users u ON u.id = c.user_from_id
ORDER BY c.timestamp DESC
LIMIT ${perPage} OFFSET ${offset}`,
prisma.$queryRaw<{ count: bigint }[]>`
SELECT COUNT(*) AS count FROM chatlogs_room`,
LIMIT ${perPage} OFFSET ${offset}`),
rawRows<{ count: bigint }>(sql`
SELECT COUNT(*) AS count FROM chatlogs_room`),
]);
const total = Number(countRows[0]?.count ?? 0);
const pagination = calcPagination(total, page, perPage);
const rows: ChatLogListRow[] = rawRows.map((row, index) => ({
const rows: ChatLogListRow[] = rawRowsResult.map((row, index) => ({
id: pagination.offset + index + 1,
username: row.username ?? "-",
message: row.message,
@@ -116,9 +122,9 @@ export async function loadCommandLogList({
username: string | null;
};
const [rawRows, countRows] = search
const [rawRowsResult, countRows] = search
? await Promise.all([
prisma.$queryRaw<RawRow[]>`
rawRows<RawRow>(sql`
SELECT c.command, c.params, c.timestamp, u.username AS username
FROM commandlogs c
LEFT JOIN users u ON u.id = c.user_id
@@ -126,29 +132,29 @@ export async function loadCommandLogList({
OR c.params LIKE ${like}
OR u.username LIKE ${like}
ORDER BY c.timestamp DESC
LIMIT ${perPage} OFFSET ${offset}`,
prisma.$queryRaw<{ count: bigint }[]>`
LIMIT ${perPage} OFFSET ${offset}`),
rawRows<{ count: bigint }>(sql`
SELECT COUNT(*) AS count
FROM commandlogs c
LEFT JOIN users u ON u.id = c.user_id
WHERE c.command LIKE ${like}
OR c.params LIKE ${like}
OR u.username LIKE ${like}`,
OR u.username LIKE ${like}`),
])
: await Promise.all([
prisma.$queryRaw<RawRow[]>`
rawRows<RawRow>(sql`
SELECT c.command, c.params, c.timestamp, u.username AS username
FROM commandlogs c
LEFT JOIN users u ON u.id = c.user_id
ORDER BY c.timestamp DESC
LIMIT ${perPage} OFFSET ${offset}`,
prisma.$queryRaw<{ count: bigint }[]>`
SELECT COUNT(*) AS count FROM commandlogs`,
LIMIT ${perPage} OFFSET ${offset}`),
rawRows<{ count: bigint }>(sql`
SELECT COUNT(*) AS count FROM commandlogs`),
]);
const total = Number(countRows[0]?.count ?? 0);
const pagination = calcPagination(total, page, perPage);
const rows: CommandLogListRow[] = rawRows.map((row, index) => ({
const rows: CommandLogListRow[] = rawRowsResult.map((row, index) => ({
id: pagination.offset + index + 1,
username: row.username ?? "-",
command: row.command,
@@ -185,9 +191,9 @@ export async function loadTradeLogList({
userTwoName: string | null;
};
const [rawRows, countRows] = search
const [rawRowsResult, countRows] = search
? await Promise.all([
prisma.$queryRaw<RawRow[]>`
rawRows<RawRow>(sql`
SELECT t.id, t.timestamp,
u1.username AS userOneName, u2.username AS userTwoName
FROM room_trade_log t
@@ -195,30 +201,30 @@ export async function loadTradeLogList({
LEFT JOIN users u2 ON u2.id = t.user_two_id
WHERE u1.username LIKE ${like} OR u2.username LIKE ${like}
ORDER BY t.timestamp DESC
LIMIT ${perPage} OFFSET ${offset}`,
prisma.$queryRaw<{ count: bigint }[]>`
LIMIT ${perPage} OFFSET ${offset}`),
rawRows<{ count: bigint }>(sql`
SELECT COUNT(*) AS count
FROM room_trade_log t
LEFT JOIN users u1 ON u1.id = t.user_one_id
LEFT JOIN users u2 ON u2.id = t.user_two_id
WHERE u1.username LIKE ${like} OR u2.username LIKE ${like}`,
WHERE u1.username LIKE ${like} OR u2.username LIKE ${like}`),
])
: await Promise.all([
prisma.$queryRaw<RawRow[]>`
rawRows<RawRow>(sql`
SELECT t.id, t.timestamp,
u1.username AS userOneName, u2.username AS userTwoName
FROM room_trade_log t
LEFT JOIN users u1 ON u1.id = t.user_one_id
LEFT JOIN users u2 ON u2.id = t.user_two_id
ORDER BY t.timestamp DESC
LIMIT ${perPage} OFFSET ${offset}`,
prisma.$queryRaw<{ count: bigint }[]>`
SELECT COUNT(*) AS count FROM room_trade_log`,
LIMIT ${perPage} OFFSET ${offset}`),
rawRows<{ count: bigint }>(sql`
SELECT COUNT(*) AS count FROM room_trade_log`),
]);
const total = Number(countRows[0]?.count ?? 0);
const pagination = calcPagination(total, page, perPage);
const rows: TradeLogListRow[] = rawRows.map((row) => ({
const rows: TradeLogListRow[] = rawRowsResult.map((row) => ({
id: row.id,
userOneName: row.userOneName ?? "-",
userTwoName: row.userTwoName ?? "-",
+57 -36
View File
@@ -1,20 +1,29 @@
import {
and,
asc,
count,
desc,
inArray,
like,
type SQL,
sql,
} from "drizzle-orm";
import { ClipboardList } from "lucide-react";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { AdminPageShell } from "@/components/admin/admin-page-shell";
import { StatusCard } from "@/components/admin/dashboard";
import { buildStaffActivityWhere } from "@/lib/admin/log-filters";
import { calcPagination, parseListParams } from "@/lib/admin-helpers";
import { db, StaffActivities, User } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
import { StaffActivitiesTable } from "./staff-activities-table";
const SORT_MAP: Record<string, "createdAt" | "userId" | "action"> = {
when: "createdAt",
staff: "userId",
action: "action",
};
const SORT_MAP = {
when: StaffActivities.createdAt,
staff: StaffActivities.userId,
action: StaffActivities.action,
} as const;
export default async function AdminStaffActivities({
searchParams,
@@ -30,36 +39,49 @@ export default async function AdminStaffActivities({
const raw = await searchParams;
const parsed = parseListParams(new URLSearchParams(raw));
const authorizationOnly = raw.filter_authorization === "1";
const whereClause = buildStaffActivityWhere({
q: parsed.search,
authorizationOnly,
});
const sortField = SORT_MAP[parsed.sort ?? ""] ?? "createdAt";
const conditions: SQL[] = [];
if (parsed.search.trim()) {
const q = parsed.search.trim();
conditions.push(
sql`(${like(StaffActivities.action, `%${q}%`)} OR ${like(StaffActivities.description, `%${q}%`)} OR ${like(StaffActivities.ipAddress, `%${q}%`)})`,
);
}
if (authorizationOnly) {
conditions.push(like(StaffActivities.action, "permission.%"));
}
const where = conditions.length > 0 ? and(...conditions) : undefined;
const total = await prisma.staffActivities
.count({ where: whereClause })
.catch(() => 0);
const sortCol =
SORT_MAP[(parsed.sort ?? "") as keyof typeof SORT_MAP] ??
StaffActivities.createdAt;
const orderBy = parsed.order === "asc" ? asc(sortCol) : desc(sortCol);
const [totalRows] = await db
.select({ total: count() })
.from(StaffActivities)
.where(where)
.catch(() => [{ total: 0 }]);
const total = Number(totalRows?.total ?? 0);
const pagination = calcPagination(total, parsed.page, parsed.perPage);
const activities = await prisma.staffActivities
.findMany({
where: whereClause,
select: {
id: true,
userId: true,
action: true,
description: true,
targetType: true,
targetId: true,
ipAddress: true,
createdAt: true,
},
orderBy: { [sortField]: parsed.order },
skip: pagination.offset,
take: pagination.perPage,
const activities = await db
.select({
id: StaffActivities.id,
userId: StaffActivities.userId,
action: StaffActivities.action,
description: StaffActivities.description,
targetType: StaffActivities.targetType,
targetId: StaffActivities.targetId,
ipAddress: StaffActivities.ipAddress,
createdAt: StaffActivities.createdAt,
})
.from(StaffActivities)
.where(where)
.orderBy(orderBy)
.limit(pagination.perPage)
.offset(pagination.offset)
.catch(() => []);
const staffIds = Array.from(
@@ -67,11 +89,10 @@ export default async function AdminStaffActivities({
).filter((n) => n > 0);
let nameById = new Map<number, string>();
if (staffIds.length) {
const users = await prisma.user
.findMany({
where: { id: { in: staffIds } },
select: { id: true, username: true },
})
const users = await db
.select({ id: User.id, username: User.username })
.from(User)
.where(inArray(User.id, staffIds))
.catch(() => []);
nameById = new Map(users.map((x) => [x.id, x.username]));
}