Relaciones en Base de Datos
Vamos a modelar las relaciones complejas del e-commerce con Prisma.
Schema Completo
prisma
// prisma/schema.prismamodel User { id String @id @default(uuid()) email String @unique name String password String role Role @default(USER) orders Order[] reviews Review[] addresses Address[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt} model Product { id String @id @default(uuid()) name String slug String @unique description String? price Decimal @db.Decimal(10, 2) stock Int @default(0) images String[] category Category @relation(fields: [categoryId], references: [id]) categoryId String orderItems OrderItem[] reviews Review[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([categoryId])} model Category { id String @id @default(uuid()) name String @unique slug String @unique products Product[]} model Order { id String @id @default(uuid()) user User @relation(fields: [userId], references: [id]) userId String items OrderItem[] address Address @relation(fields: [addressId], references: [id]) addressId String total Decimal @db.Decimal(10, 2) status OrderStatus @default(PENDING) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([userId])} model OrderItem { id String @id @default(uuid()) order Order @relation(fields: [orderId], references: [id], onDelete: Cascade) orderId String product Product @relation(fields: [productId], references: [id]) productId String quantity Int price Decimal @db.Decimal(10, 2) @@unique([orderId, productId])} model Review { id String @id @default(uuid()) rating Int comment String? user User @relation(fields: [userId], references: [id]) userId String product Product @relation(fields: [productId], references: [id]) productId String createdAt DateTime @default(now()) @@unique([userId, productId])} model Address { id String @id @default(uuid()) user User @relation(fields: [userId], references: [id]) userId String street String city String state String zipCode String country String orders Order[]} enum Role { USER ADMIN} enum OrderStatus { PENDING PAID SHIPPED DELIVERED CANCELLED}Consultas con Relaciones
typescript
// Pedido con todos los itemsconst order = await prisma.order.findUnique({ where: { id: orderId }, include: { items: { include: { product: true } }, user: { select: { id: true, name: true, email: true } }, address: true, },}); // Productos con promedio de reviewsconst products = await prisma.product.findMany({ include: { reviews: true, _count: { select: { reviews: true } }, },});Transacciones
typescript
// Crear pedido (transacción)const order = await prisma.$transaction(async (tx) => { // Verificar stock for (const item of items) { const product = await tx.product.findUnique({ where: { id: item.productId }, }); if (!product || product.stock < item.quantity) { throw new AppError(`Sin stock: ${product?.name}`); } } // Crear pedido const order = await tx.order.create({ data: { userId, addressId, total: calculateTotal(items), items: { create: items.map(item => ({ productId: item.productId, quantity: item.quantity, price: item.price, })), }, }, }); // Actualizar stock for (const item of items) { await tx.product.update({ where: { id: item.productId }, data: { stock: { decrement: item.quantity } }, }); } return order;});Resumen
- ✅ Relaciones Uno-a-Muchos y Muchos-a-Muchos
- ✅ Índices para rendimiento
- ✅ Consultas anidadas
- ✅ Transacciones para integridad
Próxima clase: Autenticación JWT! 🚀