diff --git a/frontend/drizzle/0003_glorious_norrin_radd.sql b/frontend/drizzle/0003_glorious_norrin_radd.sql new file mode 100644 index 0000000..f41d1ba --- /dev/null +++ b/frontend/drizzle/0003_glorious_norrin_radd.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS "project" ( + "id" serial PRIMARY KEY NOT NULL, + "uuid" uuid DEFAULT gen_random_uuid(), + "name" varchar(255) NOT NULL, + "user_id" integer NOT NULL +); +--> statement-breakpoint +ALTER TABLE "shortener" ADD COLUMN "project_id" integer; \ No newline at end of file diff --git a/frontend/drizzle/meta/0003_snapshot.json b/frontend/drizzle/meta/0003_snapshot.json new file mode 100644 index 0000000..0d497f2 --- /dev/null +++ b/frontend/drizzle/meta/0003_snapshot.json @@ -0,0 +1,228 @@ +{ + "id": "9a3733db-b0ef-4744-b0bf-f69e9b03917c", + "prevId": "8f8ae49c-43bf-4e07-a30d-383e2b767524", + "version": "5", + "dialect": "pg", + "tables": { + "project": { + "name": "project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "uuid": { + "name": "uuid", + "type": "uuid", + "primaryKey": false, + "notNull": false, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "schema": "", + "columns": { + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "shortener": { + "name": "shortener", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "link": { + "name": "link", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "uuid": { + "name": "uuid", + "type": "uuid", + "primaryKey": false, + "notNull": false, + "default": "gen_random_uuid()" + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } + }, + "visitor": { + "name": "visitor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "shortener_id": { + "name": "shortener_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "country_code": { + "name": "country_code", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "country": { + "name": "country", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "city": { + "name": "city", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/frontend/drizzle/meta/_journal.json b/frontend/drizzle/meta/_journal.json index 638942c..a5c087d 100644 --- a/frontend/drizzle/meta/_journal.json +++ b/frontend/drizzle/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1700882455122, "tag": "0002_robust_the_executioner", "breakpoints": true + }, + { + "idx": 3, + "version": "5", + "when": 1701590526323, + "tag": "0003_glorious_norrin_radd", + "breakpoints": true } ] } \ No newline at end of file diff --git a/frontend/src/lib/db/schema.ts b/frontend/src/lib/db/schema.ts index f3c4832..2a8a2a3 100644 --- a/frontend/src/lib/db/schema.ts +++ b/frontend/src/lib/db/schema.ts @@ -17,6 +17,7 @@ export const shortener = pgTable('shortener', { .defaultNow() .notNull(), userId: integer('user_id').notNull(), + projectId: integer('project_id'), }) export const shortenerRelations = relations( @@ -26,10 +27,32 @@ export const shortenerRelations = relations( fields: [shortener.userId], references: [user.id], }), + project: one(project, { + fields: [shortener.projectId], + references: [project.id], + }), visitor: many(visitor), }), ) +export const project = pgTable('project', { + id: serial('id').primaryKey().notNull(), + uuid: uuid('uuid').defaultRandom(), + name: varchar('name', { length: 255 }).notNull(), + userId: integer('user_id').notNull(), +}) + +export const projectRelations = relations( + project, + ({ one, many }) => ({ + user: one(user, { + fields: [project.userId], + references: [user.id], + }), + shortener: many(shortener), + }), +) + export const user = pgTable('user', { id: serial('id').primaryKey().notNull(), uuid: uuid('uuid').defaultRandom(), diff --git a/frontend/src/routes/(app)/links/+page.server.ts b/frontend/src/routes/(app)/links/+page.server.ts index ab6c881..c793421 100644 --- a/frontend/src/routes/(app)/links/+page.server.ts +++ b/frontend/src/routes/(app)/links/+page.server.ts @@ -8,7 +8,8 @@ export const load = (async (event) => { with: { visitor: true, }, - where: (shortener, { eq }) => eq(shortener.userId, user.id), + where: (shortener, { eq, and, isNull }) => + and(eq(shortener.userId, user.id), isNull(shortener.projectId)), }) return { shorteners } diff --git a/frontend/src/routes/(app)/projects/+page.server.ts b/frontend/src/routes/(app)/projects/+page.server.ts new file mode 100644 index 0000000..edf2f42 --- /dev/null +++ b/frontend/src/routes/(app)/projects/+page.server.ts @@ -0,0 +1,15 @@ +import { db } from '$lib/db' +import type { PageServerLoad } from './$types' + +export const load = (async (event) => { + const user = event.locals.userObject + + const projects = await db.query.project.findMany({ + with: { + shortener: true, + }, + where: (project, { eq }) => eq(project.userId, user.id), + }) + + return { projects } +}) satisfies PageServerLoad diff --git a/frontend/src/routes/(app)/projects/+page.svelte b/frontend/src/routes/(app)/projects/+page.svelte new file mode 100644 index 0000000..ccc4144 --- /dev/null +++ b/frontend/src/routes/(app)/projects/+page.svelte @@ -0,0 +1,109 @@ + + +