chore(db): finish Prisma cutover to Drizzle Kit tooling
Move CMS SQL to drizzle/migrations, drop prisma packages/schema, wire drizzle-kit scripts, and regenerate schema names from src/db/schema.ts. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
d8199ea1e4
commit
ba82789166
47 files changed
+365
-2787
No files matched your search
@@ -10,7 +10,7 @@ export const revalidate = 300;
|
||||
|
||||
export const metadata = { title: "Leaderboard" };
|
||||
|
||||
// Currency type ids (see prisma/schema.prisma UsersCurrency):
|
||||
// Currency type ids (see UsersCurrency in src/db/schema.ts):
|
||||
// Credits = -1 (lives on users.credits), Duckets = 0, Diamonds = 5.
|
||||
const TABS = [
|
||||
{ key: "credits", label: "Credits", coin: "credits" },
|
||||
|
||||
@@ -35,7 +35,7 @@ export default async function PhotosPage() {
|
||||
}
|
||||
|
||||
// Pre-shape for the client lightbox: translate captions server-side so the
|
||||
// client component stays free of i18n/prisma dependencies.
|
||||
// client component stays free of i18n/db dependencies.
|
||||
const items: LightboxPhoto[] = photos.map((p) => ({
|
||||
id: String(p.id),
|
||||
url: p.url,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useCallback, useEffect, useState } from "react";
|
||||
* toggled by state — closes on backdrop click, on the ✕ button, or with Esc.
|
||||
*
|
||||
* Photos are pre-shaped on the server (caption strings already translated) so
|
||||
* this component carries no prisma/i18n dependency.
|
||||
* this component carries no db/i18n dependency.
|
||||
*/
|
||||
export type LightboxPhoto = {
|
||||
id: string;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useEventSource } from "@/lib/use-event-source";
|
||||
* radio via a hidden <audio> element, with play/pause, a volume slider, the
|
||||
* current DJ / now-playing text, and a live listener count.
|
||||
*
|
||||
* It is a CLIENT component and must NOT import prisma / siteSettings.
|
||||
* It is a CLIENT component and must NOT import db / siteSettings.
|
||||
* Config is fetched once on mount; now-playing + listeners come via SSE
|
||||
* (/api/radio/stream) for real-time updates.
|
||||
*
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// AUTO-GENERATED by scripts/generate-drizzle-schema.mjs — DO NOT EDIT.
|
||||
// TS field names mirror prisma/schema.prisma (camelCase); column names are the
|
||||
// real MySQL columns. Run `pnpm db:schema:generate` after schema changes.
|
||||
// TS field names come from the previous src/db/schema.ts; column types from the
|
||||
// live MySQL DB. Run `pnpm db:schema:generate` after schema/map changes.
|
||||
|
||||
import { sql } from "drizzle-orm";
|
||||
import {
|
||||
|
||||
@@ -19,15 +19,17 @@ const tables = [
|
||||
|
||||
describe("admin content module port", () => {
|
||||
it("owns every required table through schema and migration contracts", () => {
|
||||
const schema = readFileSync(resolve("prisma/schema.prisma"), "utf8");
|
||||
const schema = readFileSync(resolve("src/db/schema.ts"), "utf8");
|
||||
const migration = readFileSync(
|
||||
resolve("prisma/migrations/0013_admin_events_polls_banners_prefixes.sql"),
|
||||
resolve(
|
||||
"drizzle/migrations/0013_admin_events_polls_banners_prefixes.sql",
|
||||
),
|
||||
"utf8",
|
||||
);
|
||||
for (const table of tables) {
|
||||
expect(migration).toContain(`CREATE TABLE IF NOT EXISTS \`${table}\``);
|
||||
if (!table.startsWith("custom_prefix"))
|
||||
expect(schema).toContain(`@@map("${table}")`);
|
||||
expect(schema).toContain(`"${table}"`);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ describe("ACL management contract", () => {
|
||||
|
||||
it("ships an idempotent ACL completion migration", () => {
|
||||
const sql = readFileSync(
|
||||
"prisma/migrations/0014_complete_acl_and_import_permissions.sql",
|
||||
"drizzle/migrations/0014_complete_acl_and_import_permissions.sql",
|
||||
"utf8",
|
||||
);
|
||||
expect(sql).toContain("admin.assets.import");
|
||||
|
||||
@@ -4,7 +4,7 @@ import { describe, expect, it } from "vitest";
|
||||
import { PERMS } from "@/lib/permission-slugs";
|
||||
|
||||
describe("production ACL migration", () => {
|
||||
const migrationsDir = resolve(process.cwd(), "prisma/migrations");
|
||||
const migrationsDir = resolve(process.cwd(), "drizzle/migrations");
|
||||
const allSql = readdirSync(migrationsDir)
|
||||
.filter((name) => name.endsWith(".sql"))
|
||||
.map((name) => readFileSync(resolve(migrationsDir, name), "utf8"))
|
||||
|
||||
@@ -36,6 +36,7 @@ describe("CI workflow", () => {
|
||||
const release = workflow.slice(workflow.indexOf("\n release:"));
|
||||
expect(release).toContain("pnpm db:migrate");
|
||||
expect(release).not.toContain("pnpm prisma:generate");
|
||||
expect(release).toContain("pnpm db:migrate");
|
||||
expect(release).toContain("src/db/schema.ts");
|
||||
const migrateAt = release.indexOf("pnpm db:migrate");
|
||||
const buildAt = release.indexOf("pnpm build");
|
||||
|
||||
@@ -249,14 +249,6 @@ export function handleActionError(error: unknown): ActionFailure {
|
||||
if (error instanceof Error && error.name === "ZodError") {
|
||||
return fail("Validation failed");
|
||||
}
|
||||
if (
|
||||
error instanceof Error &&
|
||||
(error.constructor.name === "PrismaClientKnownRequestError" ||
|
||||
error.name === "PrismaClientKnownRequestError") &&
|
||||
(error as Error & { code?: string }).code === "P2025"
|
||||
) {
|
||||
return fail("Not found");
|
||||
}
|
||||
|
||||
reportError(error, "Action error");
|
||||
return fail("Internal server error");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// ── Permission Slug Constants ───────────────────────────────────────
|
||||
// Extracted to its own file so it can be imported by client components
|
||||
// (modules.ts → sidebar.tsx) without pulling in prisma/server-only deps.
|
||||
// (modules.ts → sidebar.tsx) without pulling in db/server-only deps.
|
||||
|
||||
export const PERMS = {
|
||||
ADMIN_DASHBOARD: "admin.dashboard",
|
||||
|
||||
@@ -9,7 +9,7 @@ describe("proxy authentication boundary", () => {
|
||||
expect(proxy).toContain('from "@/lib/proxy-auth"');
|
||||
expect(proxy).not.toContain('from "@/lib/auth"');
|
||||
expect(proxyAuth).not.toMatch(
|
||||
/from\s+["'][^"']*(prisma|site-settings|credentials)[^"']*["']/i,
|
||||
/from\s+["'][^"']*(db|site-settings|credentials|prisma)[^"']*["']/i,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -38,7 +38,7 @@ export interface UploadParams {
|
||||
|
||||
const MIGRATIONS_DIR = path.resolve(
|
||||
/*turbopackIgnore: true*/ process.cwd(),
|
||||
"prisma/migrations",
|
||||
"drizzle/migrations",
|
||||
);
|
||||
|
||||
let itemsBaseIdAllocChain: Promise<unknown> = Promise.resolve();
|
||||
|
||||
@@ -49,6 +49,21 @@ describe("staff smoke contract", () => {
|
||||
).toContain("UserSanctionTimeline");
|
||||
});
|
||||
|
||||
it("applies CMS SQL from drizzle/migrations (not Prisma)", () => {
|
||||
expect(existsSync("drizzle/migrations")).toBe(true);
|
||||
expect(existsSync("prisma")).toBe(false);
|
||||
expect(readFileSync("scripts/apply-migrations.ts", "utf8")).toContain(
|
||||
"drizzle/migrations",
|
||||
);
|
||||
expect(readFileSync("package.json", "utf8")).not.toContain('"prisma"');
|
||||
expect(readFileSync("package.json", "utf8")).not.toContain(
|
||||
'"@prisma/client"',
|
||||
);
|
||||
expect(readFileSync("drizzle.config.ts", "utf8")).toContain(
|
||||
"./drizzle/drafts",
|
||||
);
|
||||
});
|
||||
|
||||
it("ships shared ops + ticket queue helpers", () => {
|
||||
expect(existsSync("src/lib/admin/ops-health.ts")).toBe(true);
|
||||
const ops = readFileSync("src/lib/admin/ops-health.ts", "utf8");
|
||||
|
||||
Reference in new issue
Block a user