refactor(db): migrate app pages and APIs from Prisma facade to Drizzle
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
53b350057d
commit
7c39aef5d9
40 files changed
+1124
-692
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import { and, asc, desc, eq, inArray } from "drizzle-orm";
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
@@ -8,9 +9,15 @@ import { toggleReaction } from "@/actions/article-reactions";
|
||||
import { ContentCard, EmptyState } from "@/components/public/ui";
|
||||
import { SanitizedHtml } from "@/components/shared/sanitized-html";
|
||||
import { auth } from "@/lib/auth";
|
||||
import {
|
||||
db,
|
||||
User,
|
||||
WebsiteArticleComments,
|
||||
WebsiteArticleReactions,
|
||||
WebsiteArticles,
|
||||
} from "@/lib/db";
|
||||
import { excerpt } from "@/lib/format";
|
||||
import { formatDate } from "@/lib/format-date";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { cacheQuery } from "@/lib/prisma-cache";
|
||||
import { sanitize } from "@/lib/sanitize";
|
||||
|
||||
@@ -39,12 +46,11 @@ function feedbackStyle(tone: "success" | "error"): CSSProperties {
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const slugs = await prisma.websiteArticles
|
||||
.findMany({
|
||||
select: { slug: true },
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 20,
|
||||
})
|
||||
const slugs = await db
|
||||
.select({ slug: WebsiteArticles.slug })
|
||||
.from(WebsiteArticles)
|
||||
.orderBy(desc(WebsiteArticles.createdAt))
|
||||
.limit(20)
|
||||
.catch(() => []);
|
||||
return slugs.map((a) => ({ slug: a.slug }));
|
||||
}
|
||||
@@ -56,9 +62,15 @@ export async function generateMetadata({
|
||||
}): Promise<Metadata> {
|
||||
const appUrl = process.env.APP_URL ?? "http://localhost:3000";
|
||||
const { slug } = await params;
|
||||
const article = await prisma.websiteArticles
|
||||
.findUnique({ where: { slug }, select: { title: true, shortStory: true } })
|
||||
.catch(() => null);
|
||||
const [article] = await db
|
||||
.select({
|
||||
title: WebsiteArticles.title,
|
||||
shortStory: WebsiteArticles.shortStory,
|
||||
})
|
||||
.from(WebsiteArticles)
|
||||
.where(eq(WebsiteArticles.slug, slug))
|
||||
.limit(1)
|
||||
.catch(() => []);
|
||||
if (!article) return { title: "Article" };
|
||||
return {
|
||||
title: article.title,
|
||||
@@ -97,22 +109,24 @@ export default async function ArticlePage({
|
||||
"websiteArticles",
|
||||
"findUnique",
|
||||
{ slug },
|
||||
() =>
|
||||
prisma.websiteArticles
|
||||
.findUnique({
|
||||
where: { slug },
|
||||
select: {
|
||||
id: true,
|
||||
slug: true,
|
||||
title: true,
|
||||
shortStory: true,
|
||||
fullStory: true,
|
||||
image: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
},
|
||||
async () => {
|
||||
const [row] = await db
|
||||
.select({
|
||||
id: WebsiteArticles.id,
|
||||
slug: WebsiteArticles.slug,
|
||||
title: WebsiteArticles.title,
|
||||
shortStory: WebsiteArticles.shortStory,
|
||||
fullStory: WebsiteArticles.fullStory,
|
||||
image: WebsiteArticles.image,
|
||||
createdAt: WebsiteArticles.createdAt,
|
||||
updatedAt: WebsiteArticles.updatedAt,
|
||||
})
|
||||
.catch(() => null),
|
||||
.from(WebsiteArticles)
|
||||
.where(eq(WebsiteArticles.slug, slug))
|
||||
.limit(1)
|
||||
.catch(() => []);
|
||||
return row ?? null;
|
||||
},
|
||||
);
|
||||
if (!article) notFound();
|
||||
|
||||
@@ -127,10 +141,18 @@ export default async function ArticlePage({
|
||||
let reactionCounts = new Map<string, number>();
|
||||
let myReaction: string | null = null;
|
||||
try {
|
||||
const rows = await prisma.websiteArticleReactions.findMany({
|
||||
where: { articleId, active: true },
|
||||
select: { reaction: true, userId: true },
|
||||
});
|
||||
const rows = await db
|
||||
.select({
|
||||
reaction: WebsiteArticleReactions.reaction,
|
||||
userId: WebsiteArticleReactions.userId,
|
||||
})
|
||||
.from(WebsiteArticleReactions)
|
||||
.where(
|
||||
and(
|
||||
eq(WebsiteArticleReactions.articleId, articleId),
|
||||
eq(WebsiteArticleReactions.active, true),
|
||||
),
|
||||
);
|
||||
for (const r of rows) {
|
||||
reactionCounts.set(r.reaction, (reactionCounts.get(r.reaction) ?? 0) + 1);
|
||||
if (sessionUserId !== null && r.userId === sessionUserId)
|
||||
@@ -142,15 +164,14 @@ export default async function ArticlePage({
|
||||
}
|
||||
|
||||
// Comments for this article (oldest first).
|
||||
let comments: Awaited<
|
||||
ReturnType<typeof prisma.websiteArticleComments.findMany>
|
||||
> = [];
|
||||
let comments: (typeof WebsiteArticleComments.$inferSelect)[] = [];
|
||||
try {
|
||||
comments = await prisma.websiteArticleComments.findMany({
|
||||
where: { articleId },
|
||||
orderBy: { createdAt: "asc" },
|
||||
take: 200,
|
||||
});
|
||||
comments = await db
|
||||
.select()
|
||||
.from(WebsiteArticleComments)
|
||||
.where(eq(WebsiteArticleComments.articleId, articleId))
|
||||
.orderBy(asc(WebsiteArticleComments.createdAt))
|
||||
.limit(200);
|
||||
} catch {
|
||||
comments = [];
|
||||
}
|
||||
@@ -160,10 +181,10 @@ export default async function ArticlePage({
|
||||
let usernameById = new Map<number, string>();
|
||||
if (commenterIds.length > 0) {
|
||||
try {
|
||||
const users = await prisma.user.findMany({
|
||||
where: { id: { in: commenterIds } },
|
||||
select: { id: true, username: true },
|
||||
});
|
||||
const users = await db
|
||||
.select({ id: User.id, username: User.username })
|
||||
.from(User)
|
||||
.where(inArray(User.id, commenterIds));
|
||||
usernameById = new Map(users.map((u) => [u.id, u.username]));
|
||||
} catch {
|
||||
usernameById = new Map();
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { desc } from "drizzle-orm";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { ContentCard, EmptyState } from "@/components/public/ui";
|
||||
import { db, WebsiteArticles } from "@/lib/db";
|
||||
import { excerpt } from "@/lib/format";
|
||||
import { formatDate } from "@/lib/format-date";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export const revalidate = 300;
|
||||
|
||||
@@ -13,13 +14,13 @@ export const metadata = { title: "News" };
|
||||
export default async function NewsPage() {
|
||||
const t = await getTranslations("pages.news");
|
||||
|
||||
let articles: Awaited<ReturnType<typeof prisma.websiteArticles.findMany>> =
|
||||
[];
|
||||
let articles: (typeof WebsiteArticles.$inferSelect)[] = [];
|
||||
try {
|
||||
articles = await prisma.websiteArticles.findMany({
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 30,
|
||||
});
|
||||
articles = await db
|
||||
.select()
|
||||
.from(WebsiteArticles)
|
||||
.orderBy(desc(WebsiteArticles.createdAt))
|
||||
.limit(30);
|
||||
} catch {
|
||||
// DB unavailable — render the empty state rather than a 500.
|
||||
articles = [];
|
||||
|
||||
Reference in new issue
Block a user