Skip to content

Commit b0505dd

Browse files
authored
Merge pull request 100xdevs-cohort-2#881 from tarunclub/master
week-11 solution
2 parents 7d540ae + 2bbdd5d commit b0505dd

File tree

18 files changed

+720
-0
lines changed

18 files changed

+720
-0
lines changed

week-11/solution/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
DATABASE_URL=""
2+
DIRECT_URL=""

week-11/solution/.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
node_modules
2+
dist
3+
.wrangler
4+
.dev.vars
5+
6+
# Change them to your taste:
7+
package-lock.json
8+
yarn.lock
9+
pnpm-lock.yaml
10+
bun.lockb

week-11/solution/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
```
2+
npm install
3+
npm run dev
4+
```
5+
6+
```
7+
npm run deploy
8+
```

week-11/solution/package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"scripts": {
3+
"dev": "wrangler dev src/index.ts",
4+
"deploy": "wrangler deploy --minify src/index.ts"
5+
},
6+
"dependencies": {
7+
"@prisma/client": "^5.9.1",
8+
"@prisma/extension-accelerate": "^0.6.3",
9+
"hono": "^4.0.3",
10+
"jsonwebtoken": "^9.0.2"
11+
},
12+
"devDependencies": {
13+
"@cloudflare/workers-types": "^4.20240208.0",
14+
"@types/jsonwebtoken": "^9.0.5",
15+
"prisma": "^5.9.1",
16+
"wrangler": "^3.25.0"
17+
}
18+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
-- CreateTable
2+
CREATE TABLE "User" (
3+
"id" SERIAL NOT NULL,
4+
"username" TEXT NOT NULL,
5+
"email" TEXT NOT NULL,
6+
"password" TEXT NOT NULL,
7+
8+
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
9+
);
10+
11+
-- CreateTable
12+
CREATE TABLE "Posts" (
13+
"id" SERIAL NOT NULL,
14+
"title" TEXT NOT NULL,
15+
"body" TEXT NOT NULL,
16+
"userId" INTEGER NOT NULL,
17+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
18+
19+
CONSTRAINT "Posts_pkey" PRIMARY KEY ("id")
20+
);
21+
22+
-- CreateTable
23+
CREATE TABLE "Tags" (
24+
"id" SERIAL NOT NULL,
25+
"tag" TEXT NOT NULL,
26+
27+
CONSTRAINT "Tags_pkey" PRIMARY KEY ("id")
28+
);
29+
30+
-- CreateTable
31+
CREATE TABLE "_PostsToTags" (
32+
"A" INTEGER NOT NULL,
33+
"B" INTEGER NOT NULL
34+
);
35+
36+
-- CreateIndex
37+
CREATE UNIQUE INDEX "Tags_tag_key" ON "Tags"("tag");
38+
39+
-- CreateIndex
40+
CREATE UNIQUE INDEX "_PostsToTags_AB_unique" ON "_PostsToTags"("A", "B");
41+
42+
-- CreateIndex
43+
CREATE INDEX "_PostsToTags_B_index" ON "_PostsToTags"("B");
44+
45+
-- AddForeignKey
46+
ALTER TABLE "Posts" ADD CONSTRAINT "Posts_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
47+
48+
-- AddForeignKey
49+
ALTER TABLE "_PostsToTags" ADD CONSTRAINT "_PostsToTags_A_fkey" FOREIGN KEY ("A") REFERENCES "Posts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
50+
51+
-- AddForeignKey
52+
ALTER TABLE "_PostsToTags" ADD CONSTRAINT "_PostsToTags_B_fkey" FOREIGN KEY ("B") REFERENCES "Tags"("id") ON DELETE CASCADE ON UPDATE CASCADE;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Please do not edit this file manually
2+
# It should be added in your version-control system (i.e. Git)
3+
provider = "postgresql"

week-11/solution/prisma/schema.prisma

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// This is your Prisma schema file,
2+
// learn more about it in the docs: https://pris.ly/d/prisma-schema
3+
4+
generator client {
5+
provider = "prisma-client-js"
6+
}
7+
8+
datasource db {
9+
provider = "postgresql"
10+
url = env("DATABASE_URL")
11+
directUrl = env("DIRECT_URL")
12+
}
13+
14+
model User {
15+
id Int @id @default(autoincrement())
16+
username String
17+
email String
18+
password String
19+
posts Posts[]
20+
}
21+
22+
model Posts {
23+
id Int @id @default(autoincrement())
24+
title String
25+
body String
26+
tags Tags[]
27+
User User @relation(fields: [userId], references: [id])
28+
userId Int
29+
createdAt DateTime @default(now())
30+
}
31+
32+
model Tags {
33+
id Int @id @default(autoincrement())
34+
tag String @unique
35+
post Posts[]
36+
}
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
import { PrismaClient } from '@prisma/client/edge';
2+
import { withAccelerate } from '@prisma/extension-accelerate';
3+
4+
import { Context } from 'hono';
5+
6+
enum StatusCode {
7+
BADREQ = 400,
8+
NOTFOUND = 404,
9+
NOTPERMISSIOON = 403,
10+
}
11+
12+
export async function getPosts(c: Context) {
13+
const prisma = new PrismaClient({
14+
datasourceUrl: c.env.DATABASE_URL,
15+
}).$extends(withAccelerate());
16+
17+
try {
18+
const response = await prisma.posts.findMany({
19+
include: {
20+
tags: true,
21+
User: true,
22+
},
23+
});
24+
return c.json({
25+
post: response.map((res) => ({
26+
id: res.id,
27+
username: res.User.username,
28+
userId: res.User.id,
29+
title: res.title,
30+
body: res.body,
31+
tags: res.tags,
32+
createdAt: res.createdAt,
33+
})),
34+
});
35+
} catch (error) {
36+
return c.body(`Internal server error: ${error}`, 500);
37+
}
38+
}
39+
40+
export async function getUserPosts(c: Context) {
41+
const prisma = new PrismaClient({
42+
datasourceUrl: c.env.DATABASE_URL,
43+
}).$extends(withAccelerate());
44+
45+
try {
46+
const resp = await prisma.posts.findMany({
47+
where: {
48+
userId: c.get('userId'),
49+
},
50+
});
51+
return c.json({
52+
post: resp,
53+
});
54+
} catch (error) {
55+
return c.body(`Internal server error: ${error}`, 500);
56+
}
57+
}
58+
59+
export async function createPost(c: Context) {
60+
const prisma = new PrismaClient({
61+
datasourceUrl: c.env.DATABASE_URL,
62+
}).$extends(withAccelerate());
63+
64+
try {
65+
const body: {
66+
title: string;
67+
body: string;
68+
tags: string;
69+
} = await c.req.json();
70+
71+
const tagNames = body.tags.split(',').map((tag) => tag.trim());
72+
73+
if ((body.body && body.title) == null) {
74+
return c.body('Invalid user input', StatusCode.BADREQ);
75+
}
76+
const res = await prisma.posts.create({
77+
data: {
78+
title: body.title,
79+
body: body.body,
80+
userId: c.get('userId'),
81+
tags: {
82+
connectOrCreate: tagNames.map((tag) => ({
83+
where: { tag },
84+
create: { tag },
85+
})),
86+
},
87+
},
88+
include: {
89+
tags: true,
90+
},
91+
});
92+
93+
return c.json({
94+
message: 'Post successfully',
95+
post: {
96+
id: res.id,
97+
title: res.title,
98+
body: res.body,
99+
tags: res.tags.map((tag) => tag.tag),
100+
createdAt: res.createdAt,
101+
},
102+
});
103+
} catch (error) {
104+
return c.body(`Internal server error: ${error}`, 500);
105+
}
106+
}
107+
108+
export async function getPost(c: Context) {
109+
const prisma = new PrismaClient({
110+
datasourceUrl: c.env.DATABASE_URL,
111+
}).$extends(withAccelerate());
112+
113+
try {
114+
const id: number = Number(c.req.param('id'));
115+
116+
const isPostExist = await prisma.posts.findFirst({
117+
where: {
118+
id: id,
119+
userId: c.get('userId'),
120+
},
121+
include: {
122+
tags: true,
123+
},
124+
});
125+
126+
if (isPostExist == null) {
127+
return c.body('Post does not exists', StatusCode.NOTFOUND);
128+
}
129+
return c.json({
130+
data: {
131+
id: isPostExist.id,
132+
title: isPostExist.title,
133+
body: isPostExist.body,
134+
tags: isPostExist.tags,
135+
createdAt: isPostExist.createdAt,
136+
},
137+
});
138+
} catch (error) {
139+
return c.body(`Internal server error: ${error}`, 500);
140+
}
141+
}
142+
143+
// this controller update the specific post
144+
export async function updatePost(c: Context) {
145+
const prisma = new PrismaClient({
146+
datasourceUrl: c.env.DATABASE_URL,
147+
}).$extends(withAccelerate());
148+
149+
try {
150+
const id: number = Number(c.req.param('id'));
151+
152+
const body: {
153+
title: string;
154+
body: string;
155+
tags: string;
156+
} = await c.req.json();
157+
158+
const tagNames = body.tags.split(',').map((tag) => tag.trim());
159+
160+
const isPostExist = await prisma.posts.findFirst({
161+
where: {
162+
id: id,
163+
userId: c.get('userId'),
164+
},
165+
});
166+
167+
if (isPostExist == null) {
168+
return c.body('Post does not exists', StatusCode.NOTFOUND);
169+
}
170+
171+
const res = await prisma.posts.update({
172+
where: {
173+
id: id,
174+
userId: c.get('userId'),
175+
},
176+
data: {
177+
title: body.title,
178+
body: body.body,
179+
tags: {
180+
connectOrCreate: tagNames.map((tag) => ({
181+
where: { tag },
182+
create: { tag },
183+
})),
184+
},
185+
},
186+
include: {
187+
tags: true,
188+
},
189+
});
190+
191+
return c.json({
192+
data: {
193+
id: res.id,
194+
title: res.title,
195+
body: res.body,
196+
tags: res.tags,
197+
createdAt: res.createdAt,
198+
},
199+
});
200+
} catch (error) {
201+
return c.body(`Internal server error: ${error}`, 500);
202+
}
203+
}
204+
205+
export async function deletePost(c: Context) {
206+
const prisma = new PrismaClient({
207+
datasourceUrl: c.env.DATABASE_URL,
208+
}).$extends(withAccelerate());
209+
210+
try {
211+
const id: number = Number(c.req.param('id'));
212+
213+
const isPostExist = await prisma.posts.findFirst({
214+
where: {
215+
id: id,
216+
userId: c.get('userId'),
217+
},
218+
});
219+
220+
if (isPostExist == null) {
221+
return c.body('Post does not exists', StatusCode.NOTFOUND);
222+
}
223+
224+
const res = await prisma.posts.delete({
225+
where: {
226+
id: id,
227+
userId: c.get('userId'),
228+
},
229+
});
230+
return c.json({
231+
message: 'post deleted',
232+
});
233+
} catch (error) {
234+
return c.json({ msg: `Internal server error: ${error}` }, 500);
235+
}
236+
}

0 commit comments

Comments
 (0)