skills/doanchienthangdev/omgkit/Developing with Prisma

Developing with Prisma

SKILL.md

Developing with Prisma

Quick Start

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  posts     Post[]
  createdAt DateTime @default(now())
  @@index([email])
}

model Post {
  id       String @id @default(cuid())
  title    String
  authorId String
  author   User   @relation(fields: [authorId], references: [id])
}
npx prisma migrate dev --name init
npx prisma generate

Features

Feature Description Guide
Schema Design Declarative data modeling with relations Define models, relations, indexes in schema.prisma
Type-Safe Queries Auto-generated TypeScript types Use findMany, findUnique, create, update
Migrations Version-controlled schema changes prisma migrate dev for development, deploy for production
Relations One-to-one, one-to-many, many-to-many Use include or select to load related data
Transactions ACID operations across multiple queries Use $transaction for atomic operations
Raw Queries Execute raw SQL when needed Use $queryRaw for complex queries

Common Patterns

Repository with Pagination

async function findUsers(page = 1, limit = 20, where?: Prisma.UserWhereInput) {
  const [data, total] = await prisma.$transaction([
    prisma.user.findMany({ where, skip: (page - 1) * limit, take: limit, include: { profile: true } }),
    prisma.user.count({ where }),
  ]);
  return { data, pagination: { page, limit, total, totalPages: Math.ceil(total / limit) } };
}

Interactive Transaction

async function createOrder(userId: string, items: { productId: string; qty: number }[]) {
  return prisma.$transaction(async (tx) => {
    let total = 0;
    for (const item of items) {
      const product = await tx.product.update({
        where: { id: item.productId },
        data: { stock: { decrement: item.qty } },
      });
      if (product.stock < 0) throw new Error(`Insufficient stock: ${product.name}`);
      total += product.price * item.qty;
    }
    return tx.order.create({ data: { userId, total, items: { create: items } } });
  });
}

Cursor-Based Pagination

async function getPaginatedPosts(cursor?: string, take = 20) {
  const posts = await prisma.post.findMany({
    take: take + 1,
    ...(cursor && { skip: 1, cursor: { id: cursor } }),
    orderBy: { createdAt: 'desc' },
  });
  const hasMore = posts.length > take;
  return { data: hasMore ? posts.slice(0, -1) : posts, nextCursor: hasMore ? posts[take - 1].id : null };
}

Best Practices

Do Avoid
Use select to fetch only needed fields Exposing Prisma Client directly in APIs
Create indexes for frequently queried fields Skipping migrations in production
Use transactions for multi-table operations Ignoring N+1 query problems
Run migrations in CI/CD pipelines Hardcoding connection strings
Use connection pooling in production Using raw queries unless necessary
Validate input before database operations Using implicit many-to-many for complex joins
Seed development databases consistently Ignoring transaction isolation levels
Weekly Installs
0
GitHub Stars
3
First Seen
Jan 1, 1970