feat(cart): update CartItem model to use composite key and adjust related logic

fix(cart): ensure cart item updates and deletions are based on cartId and itemId

feat(buy): implement balance checks and updates during purchase process

fix(sellable): ensure cart items are deleted when a sellable is removed

feat(user): add conflict checks for shop creation to prevent ID collisions
This commit is contained in:
2026-03-26 20:33:11 +01:00
parent f588672894
commit 8b4eaee510
11 changed files with 119 additions and 31 deletions
File diff suppressed because one or more lines are too long
+8 -2
View File
@@ -12274,15 +12274,16 @@ export namespace Prisma {
}
export type CartItemWhereUniqueInput = Prisma.AtLeast<{
itemId?: string
cartId_itemId?: CartItemCartIdItemIdCompoundUniqueInput
AND?: CartItemWhereInput | CartItemWhereInput[]
OR?: CartItemWhereInput[]
NOT?: CartItemWhereInput | CartItemWhereInput[]
itemId?: StringFilter<"CartItem"> | string
quantity?: IntFilter<"CartItem"> | number
cartId?: StringFilter<"CartItem"> | string
cart?: XOR<CartScalarRelationFilter, CartWhereInput>
sellable?: XOR<SellableScalarRelationFilter, SellableWhereInput>
}, "itemId">
}, "cartId_itemId">
export type CartItemOrderByWithAggregationInput = {
itemId?: SortOrder
@@ -13532,6 +13533,11 @@ export namespace Prisma {
search: string
}
export type CartItemCartIdItemIdCompoundUniqueInput = {
cartId: string
itemId: string
}
export type CartItemCountOrderByAggregateInput = {
itemId?: SortOrder
quantity?: SortOrder
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "prisma-client-60cecad7f5344b2ab216d0c215477a4a9f0fb3ec9e5201c830e0c4ac3caafb77",
"name": "prisma-client-7f3601640bc9191b9770c2fe70db074b0364e5d01ec2def94d81cee0c9a18abc",
"main": "index.js",
"types": "index.d.ts",
"browser": "default.js",
+3 -1
View File
@@ -117,12 +117,14 @@ model Cart {
}
model CartItem {
itemId String @id
itemId String
quantity Int
cartId String
cart Cart @relation(fields: [cartId], references: [userId], onDelete: Cascade, onUpdate: Cascade)
sellable Sellable @relation(fields: [itemId], references: [id], onDelete: Cascade, onUpdate: Cascade)
@@id([cartId, itemId])
}
//////////////////////
+4 -4
View File
@@ -263,7 +263,7 @@ const config = {
"value": "prisma-client-js"
},
"output": {
"value": "/var/home/zaremate/Documents/cc-create-shop/generated/prisma",
"value": "/var/mnt/f5a90b51-c040-4601-a32c-9629866f15a2/Documents/cc-create-shop/generated/prisma",
"fromEnvVar": null
},
"config": {
@@ -277,7 +277,7 @@ const config = {
}
],
"previewFeatures": [],
"sourceFilePath": "/var/home/zaremate/Documents/cc-create-shop/prisma/schema.prisma",
"sourceFilePath": "/var/mnt/f5a90b51-c040-4601-a32c-9629866f15a2/Documents/cc-create-shop/prisma/schema.prisma",
"isCustomOutput": true
},
"relativeEnvPaths": {
@@ -299,8 +299,8 @@ const config = {
}
}
},
"inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n provider = \"prisma-client-js\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"mysql\"\n // NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below\n // Further reading:\n // https://next-auth.js.org/adapters/prisma#create-the-prisma-schema\n // https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string\n url = env(\"DATABASE_URL\")\n}\n\n// Necessary for Next auth\nmodel Account {\n id String @id @default(cuid())\n userId String\n type String\n provider String\n providerAccountId String\n refresh_token String? @db.Text\n access_token String? // @db.Text\n expires_at Int?\n token_type String?\n scope String?\n id_token String? // @db.Text\n session_state String?\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n refresh_token_expires_in Int?\n\n @@unique([provider, providerAccountId])\n}\n\nmodel Session {\n id String @id @default(cuid())\n sessionToken String @unique\n userId String\n expires DateTime\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel User {\n id String @id @default(cuid())\n name String?\n email String? @unique\n emailVerified DateTime?\n image String?\n balance Float @default(1000)\n\n accounts Account[]\n sessions Session[]\n shops Shop[]\n carts Cart[]\n adresses Adress[]\n}\n\nmodel VerificationToken {\n identifier String\n token String @unique\n expires DateTime\n\n @@unique([identifier, token])\n}\n\n//////////////////////\n// SHOP\n//////////////////////\n\nmodel Shop {\n id Int @id\n userId String\n label String\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)\n items Item[]\n sellables Sellable[]\n}\n\nmodel Item {\n item_name String\n shopId Int\n stock Int\n\n shop Shop @relation(fields: [shopId], references: [id], onDelete: Cascade, onUpdate: Cascade)\n sellables Sellable[]\n\n @@id([item_name, shopId])\n}\n\nmodel Sellable {\n id String @id @default(cuid())\n item_name String\n shopId Int\n amount Int\n price Float\n enabled Boolean @default(true)\n\n shop Shop @relation(fields: [shopId], references: [id], onDelete: Cascade)\n item Item @relation(fields: [item_name, shopId], references: [item_name, shopId], onDelete: Cascade)\n\n cartItems CartItem[]\n}\n\n//////////////////////\n// CART\n//////////////////////\n\nmodel Cart {\n userId String @id\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)\n cartItems CartItem[]\n}\n\nmodel CartItem {\n itemId String @id\n quantity Int\n cartId String\n\n cart Cart @relation(fields: [cartId], references: [userId], onDelete: Cascade, onUpdate: Cascade)\n sellable Sellable @relation(fields: [itemId], references: [id], onDelete: Cascade, onUpdate: Cascade)\n}\n\n//////////////////////\n// ADDRESS\n//////////////////////\n\nmodel Adress {\n id String @id @default(cuid())\n userId String\n adress String\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)\n}\n",
"inlineSchemaHash": "6067e34ba0a13fe49002e5198964784b3870ee91700e9649c3b9ffe64ee9c688",
"inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n provider = \"prisma-client-js\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"mysql\"\n // NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below\n // Further reading:\n // https://next-auth.js.org/adapters/prisma#create-the-prisma-schema\n // https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string\n url = env(\"DATABASE_URL\")\n}\n\n// Necessary for Next auth\nmodel Account {\n id String @id @default(cuid())\n userId String\n type String\n provider String\n providerAccountId String\n refresh_token String? @db.Text\n access_token String? // @db.Text\n expires_at Int?\n token_type String?\n scope String?\n id_token String? // @db.Text\n session_state String?\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n refresh_token_expires_in Int?\n\n @@unique([provider, providerAccountId])\n}\n\nmodel Session {\n id String @id @default(cuid())\n sessionToken String @unique\n userId String\n expires DateTime\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel User {\n id String @id @default(cuid())\n name String?\n email String? @unique\n emailVerified DateTime?\n image String?\n balance Float @default(1000)\n\n accounts Account[]\n sessions Session[]\n shops Shop[]\n carts Cart[]\n adresses Adress[]\n}\n\nmodel VerificationToken {\n identifier String\n token String @unique\n expires DateTime\n\n @@unique([identifier, token])\n}\n\n//////////////////////\n// SHOP\n//////////////////////\n\nmodel Shop {\n id Int @id\n userId String\n label String\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)\n items Item[]\n sellables Sellable[]\n}\n\nmodel Item {\n item_name String\n shopId Int\n stock Int\n\n shop Shop @relation(fields: [shopId], references: [id], onDelete: Cascade, onUpdate: Cascade)\n sellables Sellable[]\n\n @@id([item_name, shopId])\n}\n\nmodel Sellable {\n id String @id @default(cuid())\n item_name String\n shopId Int\n amount Int\n price Float\n enabled Boolean @default(true)\n\n shop Shop @relation(fields: [shopId], references: [id], onDelete: Cascade)\n item Item @relation(fields: [item_name, shopId], references: [item_name, shopId], onDelete: Cascade)\n\n cartItems CartItem[]\n}\n\n//////////////////////\n// CART\n//////////////////////\n\nmodel Cart {\n userId String @id\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)\n cartItems CartItem[]\n}\n\nmodel CartItem {\n itemId String\n quantity Int\n cartId String\n\n cart Cart @relation(fields: [cartId], references: [userId], onDelete: Cascade, onUpdate: Cascade)\n sellable Sellable @relation(fields: [itemId], references: [id], onDelete: Cascade, onUpdate: Cascade)\n\n @@id([cartId, itemId])\n}\n\n//////////////////////\n// ADDRESS\n//////////////////////\n\nmodel Adress {\n id String @id @default(cuid())\n userId String\n adress String\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)\n}\n",
"inlineSchemaHash": "f1f25ffbae59b74d980dd4ecdf5d9929994691bf2809d9a3468ab2985796fd99",
"copyEngine": true
}
config.dirname = '/'