From c7306895877cc2a411dad115edd5d4c2f4cab165 Mon Sep 17 00:00:00 2001 From: Rafi Arrafif Date: Tue, 27 Jan 2026 22:29:21 +0700 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20change=20all?= =?UTF-8?q?=20id=20types=20to=20uuidv7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bun.lock | 3 + package.json | 2 + prisma/dbml/schema.dbml | 4 +- prisma/schema.prisma | 156 +++++++++++------------ src/helpers/databases/uuidv7.ts | 4 + src/utils/databases/prisma/connection.ts | 25 +++- 6 files changed, 113 insertions(+), 81 deletions(-) create mode 100644 src/helpers/databases/uuidv7.ts diff --git a/bun.lock b/bun.lock index fe4af03..77ab458 100644 --- a/bun.lock +++ b/bun.lock @@ -25,6 +25,7 @@ "nock": "^14.0.4", "pg": "^8.17.1", "slugify": "^1.6.6", + "uuidv7": "^1.1.0", "zod": "^4.0.5", }, "devDependencies": { @@ -1265,6 +1266,8 @@ "uuid": ["uuid@8.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="], + "uuidv7": ["uuidv7@1.1.0", "", { "bin": { "uuidv7": "cli.js" } }, "sha512-2VNnOC0+XQlwogChUDzy6pe8GQEys9QFZBGOh54l6qVfwoCUwwRvk7rDTgaIsRgsF5GFa5oiNg8LqXE3jofBBg=="], + "valibot": ["valibot@1.2.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg=="], "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], diff --git a/package.json b/package.json index b13b4ba..13ffa66 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "prisma:push": "bunx prisma db push", "prisma:generate": "bunx prisma generate", "prisma:dbml": "bunx prisma db pull && bunx prisma dbml --output ./prisma/dbml/schema.dbml", + "prisma:reset": "bunx prisma db push --force-reset", "prisma:seed": "bun run ./prisma/seed/index.ts", "route:sync": "bun run ./scripts/sync-routes.ts", "env:publish": "bun run ./scripts/create-example-env.ts" @@ -37,6 +38,7 @@ "nock": "^14.0.4", "pg": "^8.17.1", "slugify": "^1.6.6", + "uuidv7": "^1.1.0", "zod": "^4.0.5" }, "devDependencies": { diff --git a/prisma/dbml/schema.dbml b/prisma/dbml/schema.dbml index 26fb935..226b24a 100644 --- a/prisma/dbml/schema.dbml +++ b/prisma/dbml/schema.dbml @@ -52,7 +52,7 @@ Table genres { id String [pk] name String [not null] slug String [unique, not null] - malId Int [not null] + malId Int [unique, not null] malUrl String [not null] creator users [not null] createdBy String [not null] @@ -68,7 +68,7 @@ Table studios { name String [not null] slug String [unique, not null] linkAbout String [not null] - malId Int [not null] + malId Int [unique, not null] logoUrl String creator users [not null] createdBy String [not null] diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 681a94b..ef3b20a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -23,7 +23,7 @@ generator dbml { //// Prisma Model //// model Media { - id String @id @default(uuid()) + id String @id @db.Uuid title String @db.Text titleAlternative Json slug String @db.Text @unique @@ -44,7 +44,7 @@ model Media { characters Character[] @relation("MediaCharacters") onDraft Boolean @default(true) uploader User @relation("UserUploadedMedias", fields: [uploadedBy], references: [id]) - uploadedBy String + uploadedBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -62,28 +62,28 @@ model Media { } model MediaLog { - id String @id @default(uuid()) + id String @id @db.Uuid status MediaOperation approval Boolean @default(false) proposer User @relation("UserProposedMedias", fields: [proposedBy], references: [id]) - proposedBy String + proposedBy String @db.Uuid approver User @relation("UserApprovedMedias", fields: [approvedBy], references: [id]) - approvedBy String + approvedBy String @db.Uuid media Media @relation("MediaLogs", fields: [mediaId], references: [id]) - mediaId String + mediaId String @db.Uuid createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@map("media_logs") } model Genre { - id String @id @default(uuid()) + id String @id @db.Uuid name String @db.VarChar(255) slug String @db.VarChar(255) @unique - malId Int + malId Int @unique malUrl String @db.VarChar(255) creator User @relation("UserCreatedGenres", fields: [createdBy], references: [id]) - createdBy String + createdBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -95,14 +95,14 @@ model Genre { } model Studio { - id String @id @default(uuid()) + id String @id @db.Uuid name String @db.VarChar(255) slug String @db.VarChar(255) @unique linkAbout String @db.Text - malId Int + malId Int @unique logoUrl String? @db.Text creator User @relation("UserCreatedStudios", fields: [createdBy], references: [id]) - createdBy String + createdBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -112,7 +112,7 @@ model Studio { } model Character { - id String @id @default(uuid()) @db.Uuid + id String @id@db.Uuid malId Int @unique name String role CharacterRole @@ -120,7 +120,7 @@ model Character { imageUrl String? smallImageUrl String? createdBy User @relation("UserCreatedCharacters", fields: [creatorId], references: [id]) - creatorId String + creatorId String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -131,7 +131,7 @@ model Character { } model VoiceActor { - id String @id @default(uuid()) @db.Uuid + id String @id @db.Uuid malId Int @unique name String birthday DateTime? @@ -140,7 +140,7 @@ model VoiceActor { imageUrl String? websiteUrl String? createdBy User @relation("UserCreatedVoiceActors", fields: [creatorId], references: [id]) - creatorId String + creatorId String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -150,14 +150,14 @@ model VoiceActor { } model LangVAChar { - id String @id @default(uuid()) @db.Uuid + id String @id @db.Uuid language String voiceActor VoiceActor @relation("VACharLanguage", fields: [vaId], references: [id]) vaId String @db.Uuid character Character @relation("CharVALanguage", fields: [charId], references: [id]) charId String @db.Uuid createdBy User @relation("UserCreatedLangVAChar", fields: [creatorId], references: [id]) - creatorId String + creatorId String @db.Uuid createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -166,9 +166,9 @@ model LangVAChar { } model Episode { - id String @id @default(uuid()) + id String @id @db.Uuid media Media @relation("MediaEpisodes", fields: [mediaId], references: [id]) - mediaId String + mediaId String @db.Uuid episode Int name String @db.VarChar(255) pictureThumbnail String @db.Text @@ -177,7 +177,7 @@ model Episode { dislikes BigInt @default(0) pendingUpload Boolean @default(true) uploader User @relation("UserEpisodes", fields: [uploadedBy], references: [id]) - uploadedBy String + uploadedBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -190,28 +190,28 @@ model Episode { } model EpisodeLike { - id String @id @default(uuid()) + id String @id @db.Uuid user User @relation("UserEpisodeLikes", fields: [userId], references: [id]) - userId String + userId String @db.Uuid session UserSession @relation("SessionEpisodeLikes", fields: [sessionId], references: [id]) - sessionId String + sessionId String @db.Uuid episode Episode @relation("EpisodeLikes", fields: [episodeId], references: [id]) - episodeId String + episodeId String @db.Uuid createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@map("episode_likes") } model Video { - id String @id @default(uuid()) + id String @id @db.Uuid episode Episode @relation("EpisodeVideos", fields: [episodeId], references: [id]) - episodeId String + episodeId String @db.Uuid service VideoService @relation("VideoServices", fields: [serviceId], references: [id]) - serviceId String + serviceId String @db.Uuid code String @db.VarChar(255) pendingUpload Boolean @default(true) uploader User @relation("UserVideos", fields: [uploadedBy], references: [id]) - uploadedBy String + uploadedBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -219,7 +219,7 @@ model Video { } model VideoService { - id String @id @default(uuid()) + id String @id @db.Uuid name String @db.VarChar(255) @unique domain String @db.VarChar(255) logo String? @db.Text @@ -227,7 +227,7 @@ model VideoService { endpointVideo String @db.Text endpointThumbnail String? @db.Text creator User @relation("UserVideoServices", fields: [createdBy], references: [id]) - createdBy String + createdBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -238,7 +238,7 @@ model VideoService { } model User { - id String @id @default(uuid()) + id String @id @db.Uuid name String @db.VarChar(255) username String @unique @db.VarChar(255) email String @unique @db.Text @@ -295,16 +295,16 @@ model User { } model UserPreference { - id String @id @default(uuid()) + id String @id @db.Uuid user User @relation(fields: [userId], references: [id]) - userId String @unique + userId String @unique @db.Uuid lang Language? @relation("UserPreferenceLang", fields: [langPreference], references: [code]) - langPreference String? + langPreference String? adultFiltering AdultFiltering @default(hide) adultAlert AdultAlert @default(show) videoQuality VideoQuality @default(Q1080) serviceDefault VideoService? @relation("UserServiceDefault", fields: [serviceDefaultId], references: [id]) - serviceDefaultId String? + serviceDefaultId String? @db.Uuid hideContries Country[] favoriteGenres Genre[] @relation("UserFavoriteGenres") createdAt DateTime @default(now()) @@ -313,7 +313,7 @@ model UserPreference { } model UserRole { - id String @id @default(uuid()) + id String @id @db.Uuid name String @db.VarChar(255) @unique description String? @db.Text primaryColor String? @db.VarChar(10) @@ -332,7 +332,7 @@ model UserRole { canEditSystem Boolean @default(false) canManageSystem Boolean @default(false) creator User @relation("UserCreateRoles", fields: [createdBy], references: [id]) - createdBy String + createdBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -343,10 +343,10 @@ model UserRole { model UserRoleAssignment { user User @relation(fields: [userId], references: [id]) - userId String + userId String @db.Uuid role UserRole @relation(fields: [roleId], references: [id]) - roleId String + roleId String @db.Uuid assignmentAt DateTime @default(now()) @@ -355,14 +355,14 @@ model UserRoleAssignment { } model UserNotification { - id String @id @default(uuid()) + id String @id @db.Uuid title String @db.VarChar(255) content String @db.Text picture String @db.Text state UserNotificationState ctaLink String @db.Text user User @relation("UserNotifications", fields: [userId], references: [id]) - userId String + userId String @db.Uuid isReaded Boolean @default(false) deletedAt DateTime? createdAt DateTime @default(now()) @@ -371,10 +371,10 @@ model UserNotification { } model UserSession { - id String @id @default(uuid()) + id String @id @db.Uuid isAuthenticated Boolean @default(false) user User @relation("UserSession", fields: [userId], references: [id]) - userId String + userId String @db.Uuid deviceType String @db.VarChar(255) deviceOs String @db.VarChar(255) deviceIp String @db.VarChar(255) @@ -393,24 +393,24 @@ model UserSession { } model UserLog { - id String @id @default(uuid()) + id String @id @db.Uuid title String @db.VarChar(255) notes String @db.Text user User @relation("UserLogs", fields: [userId], references: [id]) - userId String + userId String @db.Uuid session UserSession @relation("UserSessionLogs", fields: [sessionId], references: [id]) - sessionId String + sessionId String @db.Uuid createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@map("user_logs") } model Collection { - id String @id @default(uuid()) + id String @id @db.Uuid name String @db.VarChar(255) medias Media[] @relation("MediaCollections") owner User @relation("UserCollections", fields: [ownerId], references: [id]) - ownerId String + ownerId String @db.Uuid accessStatus AccessStatus @default(private) password String? @db.VarChar(255) usersAllowed User[] @relation("UserSelectedSharingCollention") @@ -422,28 +422,28 @@ model Collection { } model WatchHistory { - id String @id @default(uuid()) + id String @id @db.Uuid episode Episode @relation("EpisodeWatchHistories", fields: [id], references: [id]) - episodeId String + episodeId String @db.Uuid user User @relation("UserWatchHistories", fields: [userId], references: [id]) - userId String + userId String @db.Uuid session UserSession @relation("SessionWatchHistories", fields: [sessionId], references: [id]) - sessionId String + sessionId String @db.Uuid createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@map("watch_histories") } model MediaReview { - id String @id @default(uuid()) + id String @id @db.Uuid media Media @relation("MediaReviews", fields: [mediaId], references:[id]) - mediaId String + mediaId String @db.Uuid rating Int title String @db.VarChar(255) text String @db.Text reaction MediaReviewReaction creator User @relation("UserMediaReviews", fields: [createdBy], references: [id]) - createdBy String + createdBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -451,15 +451,15 @@ model MediaReview { } model Comment { - id String @id @default(uuid()) + id String @id @db.Uuid episode Episode @relation("EpisodeComments", fields: [episodeId], references: [id]) - episodeId String + episodeId String @db.Uuid text String @db.Text isParent Boolean @default(false) parent Comment? @relation("ParentReplyComments", fields: [parentId], references: [id]) - parentId String? + parentId String? @db.Uuid user User @relation("UserComments", fields: [userId], references: [id]) - userId String + userId String @db.Uuid createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -469,40 +469,40 @@ model Comment { } model CommentLike { - id String @id @default(uuid()) + id String @id @db.Uuid comment Comment @relation("CommentLikes", fields: [commentId], references: [id]) - commentId String + commentId String @db.Uuid user User @relation("UserCommentLikes", fields: [userLiked], references: [id]) - userLiked String + userLiked String @db.Uuid createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@map("comment_likes") } model CommentReport { - id String @id @default(uuid()) + id String @id @db.Uuid reporter User @relation("UserReportComments", fields: [userReporter], references: [id]) - userReporter String - commentReported String + userReporter String @db.Uuid + commentReported String @db.Uuid isSupervisorReport Boolean @default(false) reason ReportReason status ReportStatus description String @db.VarChar(255) approver User? @relation("ApprovedReportComments", fields: [approvedBy], references: [id]) - approvedBy String? + approvedBy String? @db.Uuid createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@map("comment_reports") } model Language { - id String @id @default(uuid()) + id String @id @db.Uuid name String @db.VarChar(255) code String @db.VarChar(5) @unique countryFlag String @db.VarChar(10) fileLocation String @db.Text creator User @relation("UserCreateLanguages", fields: [craetedBy], references: [id]) - craetedBy String + craetedBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -512,7 +512,7 @@ model Language { } model EmailSystemAccount { - id String @id @default(uuid()) + id String @id @db.Uuid name String @unique host String @db.VarChar(255) port Int @@ -522,7 +522,7 @@ model EmailSystemAccount { password String @db.VarChar(255) purpose EmailPorpose creator User @relation("UserCreateSystemAccount", fields: [createdBy], references: [id]) - createdBy String + createdBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -530,12 +530,12 @@ model EmailSystemAccount { } model EmailSystemHistory { - id String @id @default(uuid()) + id String @id @db.Uuid purpose EmailPorpose fromEmail String @db.Text toEmail String @db.Text user User @relation("UserEmails", fields: [userRelated], references: [id]) - userRelated String + userRelated String @db.Uuid title String @db.VarChar(255) htmlContent String @db.Text deletedAt DateTime? @@ -545,7 +545,7 @@ model EmailSystemHistory { } model SystemPreference { - id String @id @default(uuid()) + id String @id @db.Uuid key String @db.VarChar(225) value String @db.VarChar(225) description String @db.Text @@ -556,14 +556,14 @@ model SystemPreference { } model SystemNotification { - id String @id @default(uuid()) + id String @id @db.Uuid type TypeSystemNotification componentName String? @db.VarChar(255) popupImage String? @db.Text titleToast String? @db.VarChar(255) contentToast String? @db.Text creator User @relation("UserCreatorSystemNotifications", fields: [createdBy], references: [id]) - createdBy String + createdBy String @db.Uuid deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@ -571,11 +571,11 @@ model SystemNotification { } model SystemLog { - id String @id @default(uuid()) + id String @id @db.Uuid title String @db.VarChar(255) notes String @db.Text user User? @relation("UserSystemLogs", fields: [relatedUser], references: [id]) - relatedUser String? + relatedUser String? @db.Uuid createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt @@map("system_logs") diff --git a/src/helpers/databases/uuidv7.ts b/src/helpers/databases/uuidv7.ts new file mode 100644 index 0000000..b29bebd --- /dev/null +++ b/src/helpers/databases/uuidv7.ts @@ -0,0 +1,4 @@ +// utils/uuidv7.ts +import { uuidv7 } from "uuidv7"; + +export const generateUUIDv7 = () => uuidv7(); diff --git a/src/utils/databases/prisma/connection.ts b/src/utils/databases/prisma/connection.ts index 7e2704a..3a5e1b0 100644 --- a/src/utils/databases/prisma/connection.ts +++ b/src/utils/databases/prisma/connection.ts @@ -2,6 +2,7 @@ import { PrismaClient } from "@prisma/client"; import { PrismaPg } from "@prisma/adapter-pg"; import pg from "pg"; import dotenv from "dotenv"; +import { generateUUIDv7 } from "../../../helpers/databases/uuidv7"; dotenv.config(); const pool = new pg.Pool({ @@ -9,4 +10,26 @@ const pool = new pg.Pool({ }); const adapter = new PrismaPg(pool); -export const prisma = new PrismaClient({ adapter }); +export const prisma = new PrismaClient({ adapter }).$extends({ + query: { + $allModels: { + async create({ args, query }) { + if ( + args.data && + typeof args.data === "object" && + !("id" in args.data) + ) { + // do nothing + } else if (args.data && !args.data.id) { + (args.data as { id?: string }).id = generateUUIDv7(); + } + return query(args); + }, + async upsert({ args, query }) { + const create = args.create as any; + if (create && !create.id) create.id = generateUUIDv7(); + return query(args); + }, + }, + }, +});