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,10 +1,16 @@
|
||||
import { and, asc, eq, inArray } from "drizzle-orm";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { ContentCard, EmptyState } from "@/components/public/ui";
|
||||
import { auth } from "@/lib/auth";
|
||||
import {
|
||||
db,
|
||||
WebsitePoll,
|
||||
WebsitePollQuestion,
|
||||
WebsitePollVote,
|
||||
} from "@/lib/db";
|
||||
import { formatDate } from "@/lib/format-date";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { PollVoteForm } from "./poll-vote-form";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
@@ -22,19 +28,24 @@ export default async function PollDetailPage({
|
||||
const session = await auth();
|
||||
const userId = Number(session?.user?.id);
|
||||
|
||||
const poll = await prisma.websitePoll
|
||||
.findUnique({
|
||||
where: { id: pollId },
|
||||
include: {
|
||||
questions: { orderBy: { sortOrder: "asc" } },
|
||||
},
|
||||
})
|
||||
.catch(() => null);
|
||||
const [poll] = await db
|
||||
.select()
|
||||
.from(WebsitePoll)
|
||||
.where(eq(WebsitePoll.id, pollId))
|
||||
.limit(1)
|
||||
.catch(() => []);
|
||||
|
||||
if (!poll || (poll.status !== "active" && poll.status !== "closed")) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const questions = await db
|
||||
.select()
|
||||
.from(WebsitePollQuestion)
|
||||
.where(eq(WebsitePollQuestion.pollId, poll.id))
|
||||
.orderBy(asc(WebsitePollQuestion.sortOrder))
|
||||
.catch(() => []);
|
||||
|
||||
const now = Date.now();
|
||||
if (
|
||||
poll.startsAt &&
|
||||
@@ -50,24 +61,31 @@ export default async function PollDetailPage({
|
||||
(poll.endsAt != null && poll.endsAt.getTime() < now);
|
||||
const isOpen = poll.status === "active" && !hasEnded;
|
||||
|
||||
const questionIds = poll.questions.map((q) => q.id);
|
||||
const questionIds = questions.map((q) => q.id);
|
||||
const myVotes =
|
||||
Number.isInteger(userId) && userId > 0 && questionIds.length > 0
|
||||
? await prisma.websitePollVote
|
||||
.findMany({
|
||||
where: { userId, questionId: { in: questionIds } },
|
||||
})
|
||||
? await db
|
||||
.select()
|
||||
.from(WebsitePollVote)
|
||||
.where(
|
||||
and(
|
||||
eq(WebsitePollVote.userId, userId),
|
||||
inArray(WebsitePollVote.questionId, questionIds),
|
||||
),
|
||||
)
|
||||
.catch(() => [])
|
||||
: [];
|
||||
const hasVoted = myVotes.length > 0;
|
||||
|
||||
const allVotes =
|
||||
poll.showResults === 1
|
||||
? await prisma.websitePollVote
|
||||
.findMany({
|
||||
where: { questionId: { in: questionIds } },
|
||||
select: { questionId: true, answer: true },
|
||||
poll.showResults === 1 && questionIds.length > 0
|
||||
? await db
|
||||
.select({
|
||||
questionId: WebsitePollVote.questionId,
|
||||
answer: WebsitePollVote.answer,
|
||||
})
|
||||
.from(WebsitePollVote)
|
||||
.where(inArray(WebsitePollVote.questionId, questionIds))
|
||||
.catch(() => [])
|
||||
: [];
|
||||
|
||||
@@ -112,7 +130,7 @@ export default async function PollDetailPage({
|
||||
>
|
||||
<PollVoteForm
|
||||
pollId={poll.id}
|
||||
questions={poll.questions.map((q) => ({
|
||||
questions={questions.map((q) => ({
|
||||
id: q.id,
|
||||
question: q.question,
|
||||
type: q.type,
|
||||
@@ -140,7 +158,7 @@ export default async function PollDetailPage({
|
||||
{poll.showResults === 1 && (hasVoted || hasEnded) ? (
|
||||
<ContentCard icon="📈" title={t("resultsTitle")}>
|
||||
<div style={{ display: "grid", gap: "1.25rem" }}>
|
||||
{poll.questions.map((q) => {
|
||||
{questions.map((q) => {
|
||||
const options = q.options
|
||||
.split("\n")
|
||||
.map((o) => o.trim())
|
||||
@@ -179,9 +197,9 @@ export default async function PollDetailPage({
|
||||
</h3>
|
||||
<div style={{ display: "grid", gap: "0.55rem" }}>
|
||||
{options.map((opt) => {
|
||||
const count = counts.get(opt) ?? 0;
|
||||
const voteCount = counts.get(opt) ?? 0;
|
||||
const pct =
|
||||
total > 0 ? Math.round((count / total) * 100) : 0;
|
||||
total > 0 ? Math.round((voteCount / total) * 100) : 0;
|
||||
return (
|
||||
<div key={opt}>
|
||||
<div
|
||||
@@ -194,7 +212,7 @@ export default async function PollDetailPage({
|
||||
>
|
||||
<span>{opt}</span>
|
||||
<span className="muted">
|
||||
{t("voteCount", { count, pct })}
|
||||
{t("voteCount", { count: voteCount, pct })}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { and, count, desc, inArray, isNull, lte, or } from "drizzle-orm";
|
||||
import Link from "next/link";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { ContentCard, EmptyState } from "@/components/public/ui";
|
||||
import { db, WebsitePoll, WebsitePollQuestion } from "@/lib/db";
|
||||
import { excerpt } from "@/lib/format";
|
||||
import { formatDate } from "@/lib/format-date";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export const revalidate = 60;
|
||||
|
||||
@@ -13,20 +14,41 @@ export default async function PollsPage() {
|
||||
const t = await getTranslations("pages.polls");
|
||||
const now = new Date();
|
||||
|
||||
const polls = await prisma.websitePoll
|
||||
.findMany({
|
||||
where: {
|
||||
status: { in: ["active", "closed"] },
|
||||
OR: [{ startsAt: null }, { startsAt: { lte: now } }],
|
||||
},
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 50,
|
||||
include: {
|
||||
_count: { select: { questions: true } },
|
||||
},
|
||||
})
|
||||
const pollRows = await db
|
||||
.select()
|
||||
.from(WebsitePoll)
|
||||
.where(
|
||||
and(
|
||||
inArray(WebsitePoll.status, ["active", "closed"]),
|
||||
or(isNull(WebsitePoll.startsAt), lte(WebsitePoll.startsAt, now)),
|
||||
),
|
||||
)
|
||||
.orderBy(desc(WebsitePoll.createdAt))
|
||||
.limit(50)
|
||||
.catch(() => []);
|
||||
|
||||
const pollIds = pollRows.map((p) => p.id);
|
||||
const questionCounts =
|
||||
pollIds.length > 0
|
||||
? await db
|
||||
.select({
|
||||
pollId: WebsitePollQuestion.pollId,
|
||||
value: count(),
|
||||
})
|
||||
.from(WebsitePollQuestion)
|
||||
.where(inArray(WebsitePollQuestion.pollId, pollIds))
|
||||
.groupBy(WebsitePollQuestion.pollId)
|
||||
.catch(() => [])
|
||||
: [];
|
||||
const countByPoll = new Map(
|
||||
questionCounts.map((r) => [r.pollId, Number(r.value)]),
|
||||
);
|
||||
|
||||
const polls = pollRows.map((poll) => ({
|
||||
...poll,
|
||||
_count: { questions: countByPoll.get(poll.id) ?? 0 },
|
||||
}));
|
||||
|
||||
return (
|
||||
<main style={{ display: "grid", gap: "1.5rem" }}>
|
||||
<ContentCard icon="📊" title={t("title")} subtitle={t("subtitle")} />
|
||||
|
||||
Reference in new issue
Block a user