5.3 KiB
5.3 KiB
trigger
| trigger |
|---|
| always_on |
Prisma Database Patterns
When to Use This Skill
Use this skill when:
- Setting up Prisma for a new service
- Creating or modifying database schemas
- Writing database migrations
- Implementing repository patterns
- Optimizing database queries
- Setting up database connections
- Implementing transactions
- Working with Neon PostgreSQL
Core Concepts
Architecture
- Repository pattern for data access
- Prisma as ORM for type safety
- Neon PostgreSQL as primary database
- Connection pooling for performance
- Transaction support for data consistency
Key Patterns
Prisma Setup
npm install @prisma/client prisma
npx prisma init
Schema Definition
model User {
id String @id @default(cuid())
email String @unique
name String?
role Role @default(USER)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
posts Post[]
@@index([email])
@@index([createdAt])
@@map("users")
}
Database Connection
import { PrismaClient } from '@prisma/client';
const globalForPrisma = global as unknown as { prisma: PrismaClient | undefined };
export const prisma = globalForPrisma.prisma ?? new PrismaClient({
log: process.env.NODE_ENV === 'development' ? ['query', 'error'] : ['error'],
});
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
Repository Pattern
export class UserRepository {
async findById(id: string) {
return prisma.user.findUnique({ where: { id }, include: { profile: true } });
}
async findAll({ page = 1, limit = 10, search }: QueryOptions) {
const where = search ? { OR: [
{ email: { contains: search, mode: 'insensitive' } },
{ name: { contains: search, mode: 'insensitive' } }
]} : {};
const [data, total] = await Promise.all([
prisma.user.findMany({ where, skip: (page - 1) * limit, take: limit }),
prisma.user.count({ where })
]);
return { data, total };
}
async create(data: CreateUserDto) {
return prisma.user.create({ data });
}
}
Transactions
await prisma.$transaction(async (tx) => {
await tx.account.update({ where: { id: from }, data: { balance: { decrement: amount } } });
await tx.account.update({ where: { id: to }, data: { balance: { increment: amount } } });
}, { maxWait: 5000, timeout: 10000 });
Best Practices
- Schema Design: Use appropriate field types, add indexes for frequently queried fields
- Performance: Use select to fetch only needed fields, implement pagination
- Security: Never expose sensitive fields, use parameterized queries
- Maintenance: Keep migrations small and focused, test before production
Common Mistakes
-
N+1 Query Problem: Fetching related data in a loop
// BAD: N+1 queries for (const user of users) { await prisma.post.findMany({ where: { authorId: user.id } }); } // GOOD: Include relations await prisma.user.findMany({ include: { posts: true } }); -
No Indexes: Missing indexes on frequently queried columns
// GOOD: Add index @@index([createdAt]) -
Raw Queries Without Parameters: SQL injection risk
// BAD: prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`); // GOOD: prisma.$queryRaw`SELECT * FROM users WHERE email = ${email}`; -
Not Using Transactions: Data inconsistency risk
// GOOD: Use transaction for related operations await prisma.$transaction([update1, update2]); -
Exposing Internal IDs: Leaking database structure
// GOOD: Use CUID or UUID model User { id String @id @default(cuid()) }
Quick Reference
| Operation | Command |
|---|---|
| Create migration | npx prisma migrate dev --name <name> |
| Apply migrations | npx prisma migrate deploy |
| Reset database | npx prisma migrate reset |
| Generate client | npx prisma generate |
| Open Studio | npx prisma studio |
| Seed database | npx prisma db seed |
Common Query Patterns:
await prisma.user.findUnique({ where: { id } }); // Find unique
await prisma.user.findMany({ include: { posts: true } }); // With relations
await prisma.user.findMany({ select: { id: true } }); // Select fields
await prisma.user.findMany({ skip: 10, take: 10 }); // Pagination
await prisma.$transaction(async (tx) => { ... }); // Transaction
Schema Field Types:
| Type | PostgreSQL | Description |
|---|---|---|
String |
TEXT | Variable-length string |
Int |
INTEGER | 32-bit integer |
BigInt |
BIGINT | 64-bit integer |
Float |
DOUBLE PRECISION | Floating point |
Boolean |
BOOLEAN | True/false |
DateTime |
TIMESTAMP | Date and time |
Json |
JSONB | JSON data |
Resources
- Prisma Documentation - Official Prisma docs
- Prisma Schema Reference
- Detailed Code Examples
- Repository Pattern - Data access patterns
- Caching Patterns - Query caching
- Testing Patterns - Database mocking