Skip to content

Commit

Permalink
Merge pull request #2 from bercivarga/feature/db-setup
Browse files Browse the repository at this point in the history
Add Prisma, db utils, and sign-up database sync
  • Loading branch information
bercivarga authored Mar 9, 2024
2 parents fd7c7b6 + 63e4370 commit 7cd6bde
Show file tree
Hide file tree
Showing 11 changed files with 306 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ yarn-error.log*

# local env files
.env*.local
.env

# vercel
.vercel
Expand Down
2 changes: 1 addition & 1 deletion app/(auth)/sign-up/[[...sign-up]]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SignUp } from "@clerk/nextjs";

export default function SignUpPage() {
return <SignUp />;
return <SignUp afterSignUpUrl={"/api/sign-up"} />;
}
47 changes: 47 additions & 0 deletions app/api/sign-up/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { currentUser } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import { NextResponse } from "next/server";

import { prisma } from "@/lib/db";

// Handles the sign-up process once the user is made and redirected by Clerk
export async function GET() {
// Get the userId from auth() -- if null, the user is not signed in
const currentUserData = await currentUser();

if (!currentUserData) {
return new NextResponse("Unauthorized", { status: 401 });
}

const { id: userId, emailAddresses, username } = currentUserData;

try {
// Check if the user already exists in the database
const user = await prisma.user.findUnique({
where: { clerkId: currentUserData.id },
});

if (user) {
return new NextResponse("User already exists", { status: 400 });
}
} catch (error) {
return new NextResponse("Error retrieving user from the database", {
status: 500,
});
}

try {
// Create the user in the database using the Clerk user's data
await prisma.user.create({
data: {
clerkId: userId,
email: emailAddresses[0].emailAddress,
name: username,
},
});
} catch (error) {
return new NextResponse("Error creating user", { status: 500 });
}

redirect("/dashboard");
}
4 changes: 2 additions & 2 deletions app/dashboard/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<div className="flex h-screen">
<aside className="flex h-full w-64 flex-col justify-between bg-indigo-100 p-6">
<div className="flex h-screen divide-x">
<aside className="flex h-full w-64 flex-col justify-between bg-indigo-50 p-6">
<div>
<span>TODO: Add sidebar menu</span>
</div>
Expand Down
10 changes: 10 additions & 0 deletions lib/db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient };

export const prisma = globalForPrisma.prisma ?? new PrismaClient();

// Prevents making multiple connections to the database in development mode
if (process.env.NODE_ENV === "development") {
globalForPrisma.prisma = prisma;
}
4 changes: 3 additions & 1 deletion middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { authMiddleware } from "@clerk/nextjs";
export default authMiddleware({
// Routes that can be accessed while signed out
publicRoutes: [
/^(?!\/dashboard).*/, // Match routes that don't start with "/dashboard"
// 👇 Leaving this here so that later I can adjust the middleware logic according to the project's needs
// /^(?!\/dashboard).*/, // Match routes that don't start with "/dashboard"
"/", // Match the root route
],
// Routes that can always be accessed, and have
// no authentication information
Expand Down
80 changes: 80 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
},
"dependencies": {
"@clerk/nextjs": "^4.29.9",
"@prisma/client": "^5.10.2",
"@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
Expand Down Expand Up @@ -42,6 +43,7 @@
"postcss": "^8",
"prettier": "3.2.5",
"prettier-plugin-tailwindcss": "^0.5.12",
"prisma": "^5.10.2",
"tailwindcss": "^3.3.0",
"typescript": "^5",
"typescript-eslint": "^7.1.1",
Expand Down
91 changes: 91 additions & 0 deletions prisma/migrations/20240309095543_init/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"email" TEXT NOT NULL,
"name" TEXT,
"clerkId" TEXT NOT NULL,

CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Tag" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,

CONSTRAINT "Tag_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "SentimentAnalysis" (
"id" TEXT NOT NULL,
"noteId" TEXT NOT NULL,
"sentiment" TEXT NOT NULL,
"score" DOUBLE PRECISION NOT NULL,

CONSTRAINT "SentimentAnalysis_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Note" (
"id" TEXT NOT NULL,
"title" TEXT NOT NULL,
"content" TEXT NOT NULL,
"authorId" TEXT NOT NULL,

CONSTRAINT "Note_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "_NoteToTag" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL
);

-- CreateTable
CREATE TABLE "_RelatedNotes" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL
);

-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");

-- CreateIndex
CREATE UNIQUE INDEX "User_clerkId_key" ON "User"("clerkId");

-- CreateIndex
CREATE UNIQUE INDEX "SentimentAnalysis_noteId_key" ON "SentimentAnalysis"("noteId");

-- CreateIndex
CREATE UNIQUE INDEX "Note_authorId_key" ON "Note"("authorId");

-- CreateIndex
CREATE UNIQUE INDEX "_NoteToTag_AB_unique" ON "_NoteToTag"("A", "B");

-- CreateIndex
CREATE INDEX "_NoteToTag_B_index" ON "_NoteToTag"("B");

-- CreateIndex
CREATE UNIQUE INDEX "_RelatedNotes_AB_unique" ON "_RelatedNotes"("A", "B");

-- CreateIndex
CREATE INDEX "_RelatedNotes_B_index" ON "_RelatedNotes"("B");

-- AddForeignKey
ALTER TABLE "SentimentAnalysis" ADD CONSTRAINT "SentimentAnalysis_noteId_fkey" FOREIGN KEY ("noteId") REFERENCES "Note"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Note" ADD CONSTRAINT "Note_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_NoteToTag" ADD CONSTRAINT "_NoteToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Note"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_NoteToTag" ADD CONSTRAINT "_NoteToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_RelatedNotes" ADD CONSTRAINT "_RelatedNotes_A_fkey" FOREIGN KEY ("A") REFERENCES "Note"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_RelatedNotes" ADD CONSTRAINT "_RelatedNotes_B_fkey" FOREIGN KEY ("B") REFERENCES "Note"("id") ON DELETE CASCADE ON UPDATE CASCADE;
3 changes: 3 additions & 0 deletions prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"
66 changes: 66 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model User {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
email String @unique
name String?
clerkId String @unique
notes Note[]
canMakeChanges Boolean @default(true) // Used only to guard against abuse on the test account
}

model Tag {
id String @id @default(uuid())
name String
notes Note[] // One-to-many relationship: one tag can be associated with multiple notes
}

enum Sentiment {
VERY_POSITIVE
POSITIVE
NEUTRAL
NEGATIVE
VERY_NEGATIVE
}

model SentimentAnalysis {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
note Note @relation(fields: [noteId], references: [id])
noteId String @unique
sentiment Sentiment @default(NEUTRAL)
score Float
summary String
}

model Note {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
content String @db.Text
author User @relation(fields: [authorId], references: [id])
authorId String @unique
tags Tag[] // Many-to-many relationship: one note can have multiple tags
sentimentAnalysis SentimentAnalysis? // One-to-one relationship: one note can have one sentiment analysis
relatedNotes Note[] @relation("RelatedNotes") // Many-to-many relationship: a note can be related to multiple other notes
relatedTo Note[] @relation("RelatedNotes") // Reverse relation for related notes
@@index([authorId], name: "author_index")
}

0 comments on commit 7cd6bde

Please sign in to comment.