From 19c29928242f55f028f6c66d33a757362f2f2647 Mon Sep 17 00:00:00 2001 From: Ishaan Dey Date: Thu, 18 Apr 2024 00:13:40 -0400 Subject: [PATCH] fix db relations + display sandboxes on dash --- .../drizzle/0001_right_omega_sentinel.sql | 7 ++ .../database/drizzle/0002_curvy_darkhawk.sql | 1 + .../drizzle/0003_outgoing_hammerhead.sql | 1 + .../database/drizzle/meta/0001_snapshot.json | 97 ++++++++++++++ .../database/drizzle/meta/0002_snapshot.json | 113 +++++++++++++++++ .../database/drizzle/meta/0003_snapshot.json | 118 ++++++++++++++++++ backend/database/drizzle/meta/_journal.json | 21 ++++ backend/database/src/index.ts | 63 ++++++---- backend/database/src/schema.ts | 19 ++- frontend/app/(app)/dashboard/page.tsx | 10 +- frontend/app/(app)/layout.tsx | 2 + frontend/components/dashboard/index.tsx | 27 ++-- frontend/lib/types.ts | 15 +++ 13 files changed, 458 insertions(+), 36 deletions(-) create mode 100644 backend/database/drizzle/0001_right_omega_sentinel.sql create mode 100644 backend/database/drizzle/0002_curvy_darkhawk.sql create mode 100644 backend/database/drizzle/0003_outgoing_hammerhead.sql create mode 100644 backend/database/drizzle/meta/0001_snapshot.json create mode 100644 backend/database/drizzle/meta/0002_snapshot.json create mode 100644 backend/database/drizzle/meta/0003_snapshot.json create mode 100644 frontend/lib/types.ts diff --git a/backend/database/drizzle/0001_right_omega_sentinel.sql b/backend/database/drizzle/0001_right_omega_sentinel.sql new file mode 100644 index 0000000..9ef94ce --- /dev/null +++ b/backend/database/drizzle/0001_right_omega_sentinel.sql @@ -0,0 +1,7 @@ +/* + SQLite does not support "Dropping foreign key" out of the box, we do not generate automatic migration for that, so it has to be done manually + Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php + https://www.sqlite.org/lang_altertable.html + + Due to that we don't generate migration automatically and it has to be done manually +*/ \ No newline at end of file diff --git a/backend/database/drizzle/0002_curvy_darkhawk.sql b/backend/database/drizzle/0002_curvy_darkhawk.sql new file mode 100644 index 0000000..0052001 --- /dev/null +++ b/backend/database/drizzle/0002_curvy_darkhawk.sql @@ -0,0 +1 @@ +ALTER TABLE `sandbox` RENAME COLUMN `text` TO `type`; \ No newline at end of file diff --git a/backend/database/drizzle/0003_outgoing_hammerhead.sql b/backend/database/drizzle/0003_outgoing_hammerhead.sql new file mode 100644 index 0000000..703670a --- /dev/null +++ b/backend/database/drizzle/0003_outgoing_hammerhead.sql @@ -0,0 +1 @@ +ALTER TABLE sandbox ADD `bucket` text; \ No newline at end of file diff --git a/backend/database/drizzle/meta/0001_snapshot.json b/backend/database/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..95eda56 --- /dev/null +++ b/backend/database/drizzle/meta/0001_snapshot.json @@ -0,0 +1,97 @@ +{ + "version": "5", + "dialect": "sqlite", + "id": "a6b962d3-cabf-464f-9098-c70ed82e94dc", + "prevId": "af9c2bc3-e4c9-42f6-bf73-bb2399b894c7", + "tables": { + "sandbox": { + "name": "sandbox", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "text": { + "name": "text", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "sandbox_id_unique": { + "name": "sandbox_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_unique": { + "name": "user_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/backend/database/drizzle/meta/0002_snapshot.json b/backend/database/drizzle/meta/0002_snapshot.json new file mode 100644 index 0000000..06785f8 --- /dev/null +++ b/backend/database/drizzle/meta/0002_snapshot.json @@ -0,0 +1,113 @@ +{ + "version": "5", + "dialect": "sqlite", + "id": "dda436cb-b614-4fc2-8764-7c2b80ac9e07", + "prevId": "a6b962d3-cabf-464f-9098-c70ed82e94dc", + "tables": { + "sandbox": { + "name": "sandbox", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "sandbox_id_unique": { + "name": "sandbox_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "sandbox_user_id_user_id_fk": { + "name": "sandbox_user_id_user_id_fk", + "tableFrom": "sandbox", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_unique": { + "name": "user_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": { + "\"sandbox\".\"text\"": "\"sandbox\".\"type\"" + } + } +} \ No newline at end of file diff --git a/backend/database/drizzle/meta/0003_snapshot.json b/backend/database/drizzle/meta/0003_snapshot.json new file mode 100644 index 0000000..ba421ab --- /dev/null +++ b/backend/database/drizzle/meta/0003_snapshot.json @@ -0,0 +1,118 @@ +{ + "version": "5", + "dialect": "sqlite", + "id": "90f199c9-66a1-4c89-9a19-f7fbd5a35236", + "prevId": "dda436cb-b614-4fc2-8764-7c2b80ac9e07", + "tables": { + "sandbox": { + "name": "sandbox", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "sandbox_id_unique": { + "name": "sandbox_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "sandbox_user_id_user_id_fk": { + "name": "sandbox_user_id_user_id_fk", + "tableFrom": "sandbox", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_unique": { + "name": "user_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/backend/database/drizzle/meta/_journal.json b/backend/database/drizzle/meta/_journal.json index aea7057..fb07bbb 100644 --- a/backend/database/drizzle/meta/_journal.json +++ b/backend/database/drizzle/meta/_journal.json @@ -8,6 +8,27 @@ "when": 1713306026634, "tag": "0000_sparkling_morg", "breakpoints": true + }, + { + "idx": 1, + "version": "5", + "when": 1713411309767, + "tag": "0001_right_omega_sentinel", + "breakpoints": true + }, + { + "idx": 2, + "version": "5", + "when": 1713411654625, + "tag": "0002_curvy_darkhawk", + "breakpoints": true + }, + { + "idx": 3, + "version": "5", + "when": 1713412439820, + "tag": "0003_outgoing_hammerhead", + "breakpoints": true } ] } \ No newline at end of file diff --git a/backend/database/src/index.ts b/backend/database/src/index.ts index 3641987..2968f4d 100644 --- a/backend/database/src/index.ts +++ b/backend/database/src/index.ts @@ -7,6 +7,7 @@ import { json } from "itty-router-extras"; import { ZodError, z } from "zod"; import { user, sandbox } from "./schema"; +import * as schema from "./schema"; export interface Env { DB: D1Database; @@ -18,35 +19,53 @@ export default { const path = url.pathname; const method = request.method; - const db = drizzle(env.DB); + const db = drizzle(env.DB, { schema }); - if (path === "/api/user") { - if (method === "GET") { + if (path.startsWith("/api/user")) { + if (path === "/api/user") { + if (method === "GET") { + const params = url.searchParams; + + if (params.has("id")) { + const id = params.get("id") as string; + const res = await db.select().from(user).where(eq(user.id, id)).get(); + console.log(res); + return json(res ?? {}); + } else { + const res = await db.select().from(user).all(); + return json(res ?? {}); + } + } else if (method === "POST") { + const userSchema = z.object({ + id: z.string(), + name: z.string(), + email: z.string().email(), + }); + + const body = await request.json(); + const { id, name, email } = userSchema.parse(body); + + const res = await db.insert(user).values({ id, name, email }).returning().get(); + return json({ res }); + } else { + return new Response("Method Not Allowed", { status: 405 }); + } + } else if (path === "/api/user/sandbox") { const params = url.searchParams; - - if (params.has("id")) { + if (method === "GET" && params.has("id")) { const id = params.get("id") as string; - const res = await db.select().from(user).where(eq(user.id, id)).get(); - console.log(res); + const res = await db.query.user.findFirst({ + where: (user, { eq }) => eq(user.id, id), + with: { + sandbox: true, + }, + }); return json(res ?? {}); } else { - const res = await db.select().from(user).all(); - return json(res ?? {}); + return new Response("Method Not Allowed", { status: 405 }); } - } else if (method === "POST") { - const userSchema = z.object({ - id: z.string(), - name: z.string(), - email: z.string().email(), - }); - - const body = await request.json(); - const { id, name, email } = userSchema.parse(body); - - const res = await db.insert(user).values({ id, name, email }).returning().get(); - return json({ res }); } else { - return new Response("Method Not Allowed", { status: 405 }); + return new Response("Not Found", { status: 404 }); } } else return new Response("Not Found", { status: 404 }); }, diff --git a/backend/database/src/schema.ts b/backend/database/src/schema.ts index 29eea23..bf8e49d 100644 --- a/backend/database/src/schema.ts +++ b/backend/database/src/schema.ts @@ -1,5 +1,6 @@ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; import { createId } from "@paralleldrive/cuid2"; +import { relations } from "drizzle-orm"; export const user = sqliteTable("user", { id: text("id") @@ -10,14 +11,30 @@ export const user = sqliteTable("user", { email: text("email").notNull(), }); +export type User = typeof user.$inferSelect; + +export const userRelations = relations(user, ({ many }) => ({ + sandbox: many(sandbox), +})); + export const sandbox = sqliteTable("sandbox", { id: text("id") .$defaultFn(() => createId()) .primaryKey() .unique(), name: text("name").notNull(), - type: text("text", { enum: ["react", "node"] }).notNull(), + type: text("type", { enum: ["react", "node"] }).notNull(), + bucket: text("bucket"), userId: text("user_id") .notNull() .references(() => user.id), }); + +export type Sandbox = typeof sandbox.$inferSelect; + +export const sandboxRelations = relations(sandbox, ({ one }) => ({ + author: one(user, { + fields: [sandbox.userId], + references: [user.id], + }), +})); diff --git a/frontend/app/(app)/dashboard/page.tsx b/frontend/app/(app)/dashboard/page.tsx index 81ed9d2..5d1d60d 100644 --- a/frontend/app/(app)/dashboard/page.tsx +++ b/frontend/app/(app)/dashboard/page.tsx @@ -2,6 +2,7 @@ import { UserButton, currentUser } from "@clerk/nextjs" import { redirect } from "next/navigation" import Dashboard from "@/components/dashboard" import Navbar from "@/components/dashboard/navbar" +import { Sandbox } from "@/lib/types" export default async function DashboardPage() { const user = await currentUser() @@ -10,10 +11,17 @@ export default async function DashboardPage() { redirect("/") } + const res = await fetch( + `http://localhost:8787/api/user/sandbox?id=${user.id}` + ) + const data = (await res.json()).sandbox as Sandbox[] + + console.log(data) + return (
- +
) } diff --git a/frontend/app/(app)/layout.tsx b/frontend/app/(app)/layout.tsx index 550eea6..a191f40 100644 --- a/frontend/app/(app)/layout.tsx +++ b/frontend/app/(app)/layout.tsx @@ -27,6 +27,8 @@ export default async function AppAuthLayout({ email: user.emailAddresses[0].emailAddress, }), }) + + console.log(res) } else { // user already exists in db } diff --git a/frontend/components/dashboard/index.tsx b/frontend/components/dashboard/index.tsx index 1096f0f..d33fa1b 100644 --- a/frontend/components/dashboard/index.tsx +++ b/frontend/components/dashboard/index.tsx @@ -18,10 +18,11 @@ import { import { useState } from "react" import { Card } from "../ui/card" import ProjectCard from "./projectCard" +import { Sandbox } from "@/lib/types" type TScreen = "projects" | "shared" | "settings" | "search" -export default function Dashboard() { +export default function Dashboard({ sandboxes }: { sandboxes: Sandbox[] }) { const [screen, setScreen] = useState("projects") const activeScreen = (s: TScreen) => { @@ -80,19 +81,21 @@ export default function Dashboard() {
- -
- React Project 1 -
-
-
- Public + {sandboxes.map((sandbox) => ( + +
+ {sandbox.name}
-
- 3d ago +
+
+ Public +
+
+ 3d ago +
-
-
+ + ))}
) diff --git a/frontend/lib/types.ts b/frontend/lib/types.ts new file mode 100644 index 0000000..df47309 --- /dev/null +++ b/frontend/lib/types.ts @@ -0,0 +1,15 @@ +// DB Types + +export type User = { + id: string + name: string + email: string +} + +export type Sandbox = { + id: string + name: string + type: "react" | "node" + bucket: string | null + userId: string +}