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

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-08-01 14:15:39 +02:00
1 parent 9aa4f331bf
commit 30b54e99e7
40 files changed
+1183 -784

No files matched your search

+7 -5
View File
@@ -1,5 +1,6 @@
import { eq } from "drizzle-orm";
import { apiJson } from "@/lib/api";
import { prisma } from "@/lib/prisma";
import { db, User } from "@/lib/db";
import { siteSettings } from "@/lib/services/site-settings";
// Current on-air DJ. The DJ is set manually via the radio_current_dj_id setting
@@ -17,10 +18,11 @@ export async function GET(_req: Request) {
return apiJson({ dj: null });
}
const user = await prisma.user.findUnique({
where: { id },
select: { username: true, look: true },
});
const [user] = await db
.select({ username: User.username, look: User.look })
.from(User)
.where(eq(User.id, id))
.limit(1);
if (!user) {
return apiJson({ dj: null });
+17 -10
View File
@@ -1,5 +1,6 @@
import { inArray, sum } from "drizzle-orm";
import { apiJson } from "@/lib/api";
import { prisma } from "@/lib/prisma";
import { db, RadioListenerPoints, User } from "@/lib/db";
// Radio listener-points leaderboard: the top 20 users by total points, summed
// across radio_listener_points and joined to users for username/look. Public
@@ -10,13 +11,19 @@ export async function GET(_req: Request) {
try {
// Sum points per user. Sort/slice in JS so we stay adapter-agnostic about
// aggregate ordering, then resolve the top 20 to usernames/looks.
const grouped = await prisma.radioListenerPoints.groupBy({
by: ["userId"],
_sum: { points: true },
});
const grouped = await db
.select({
userId: RadioListenerPoints.userId,
points: sum(RadioListenerPoints.points),
})
.from(RadioListenerPoints)
.groupBy(RadioListenerPoints.userId);
const ranked = grouped
.map((g) => ({ userId: g.userId, points: g._sum.points ?? 0 }))
.map((g) => ({
userId: Number(g.userId),
points: Number(g.points ?? 0),
}))
.sort((a, b) => b.points - a.points)
.slice(0, 20);
@@ -25,10 +32,10 @@ export async function GET(_req: Request) {
}
const userIds = ranked.map((r) => r.userId);
const users = await prisma.user.findMany({
where: { id: { in: userIds } },
select: { id: true, username: true, look: true },
});
const users = await db
.select({ id: User.id, username: User.username, look: User.look })
.from(User)
.where(inArray(User.id, userIds));
const userById = new Map(users.map((u) => [u.id, u]));
const data = ranked.map((r) => {
+7 -6
View File
@@ -1,6 +1,7 @@
import { eq, sum } from "drizzle-orm";
import { apiError, apiJson } from "@/lib/api";
import { bearerUserId } from "@/lib/api-auth";
import { prisma } from "@/lib/prisma";
import { db, RadioListenerPoints } from "@/lib/db";
// The Bearer-authed user's total radio listener points: the sum of all
// radio_listener_points.points rows for that user_id.
@@ -11,12 +12,12 @@ export async function GET(req: Request) {
if (!uid) return apiError("Unauthorized", 401);
try {
const agg = await prisma.radioListenerPoints.aggregate({
where: { userId: uid },
_sum: { points: true },
});
const [agg] = await db
.select({ points: sum(RadioListenerPoints.points) })
.from(RadioListenerPoints)
.where(eq(RadioListenerPoints.userId, BigInt(uid)));
return apiJson({ points: agg._sum.points ?? 0 });
return apiJson({ points: Number(agg?.points ?? 0) });
} catch {
// DB unavailable — report zero rather than a 500.
return apiJson({ points: 0 }, { status: 200 });
+16 -17
View File
@@ -1,6 +1,7 @@
import { desc, inArray } from "drizzle-orm";
import { apiError, apiJson } from "@/lib/api";
import { bearerUserId } from "@/lib/api-auth";
import { prisma } from "@/lib/prisma";
import { db, RadioShouts, User } from "@/lib/db";
// Latest 50 radio shouts with their author's username/look resolved. Mirrors the
// query behind the public /radio/shouts page (radio_shouts ordered by created_at
@@ -12,19 +13,20 @@ const MAX_MESSAGE_LENGTH = 255;
export async function GET(_req: Request) {
try {
const shouts = await prisma.radioShouts.findMany({
orderBy: { createdAt: "desc" },
take: 50,
});
const shouts = await db
.select()
.from(RadioShouts)
.orderBy(desc(RadioShouts.createdAt))
.limit(50);
// Resolve author usernames/looks. radio_shouts.user_id is an UnsignedBigInt
// while users.id is an Int, so narrow to Number for the lookup.
const authorIds = Array.from(new Set(shouts.map((s) => Number(s.userId))));
const authors = authorIds.length
? await prisma.user.findMany({
where: { id: { in: authorIds } },
select: { id: true, username: true, look: true },
})
? await db
.select({ id: User.id, username: User.username, look: User.look })
.from(User)
.where(inArray(User.id, authorIds))
: [];
const authorById = new Map(authors.map((a) => [a.id, a]));
@@ -67,14 +69,11 @@ export async function POST(req: Request) {
try {
const now = new Date();
await prisma.radioShouts.create({
data: {
userId: BigInt(uid),
message,
createdAt: now,
updatedAt: now,
},
select: { id: true },
await db.insert(RadioShouts).values({
userId: BigInt(uid),
message,
createdAt: now,
updatedAt: now,
});
return apiJson({ ok: true });