agentsclimarketplace

Prisma patterns

Skill Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack/plugins/devtools-pack/skills/prisma-patterns

A curated pack of custom Claude Code skills for developers — installable as a Claude Code plugin marketplace.

Install
npx -y skills add Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack --skill prisma-patterns

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

When to activate: Prisma ORM, schema.prisma, migrations, Prisma Client, relations, transactions, raw queries, seeding

SKILL.md

5.9 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it

Prisma Patterns

schema.prisma Baseline

generator client {
  provider = "prisma-client-js"
}

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

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String
  role      Role     @default(USER)
  posts     Post[]
  profile   Profile?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([email])
  @@map("users")
}

model Post {
  id          String   @id @default(cuid())
  title       String
  content     String?
  published   Boolean  @default(false)
  authorId    String
  author      User     @relation(fields: [authorId], references: [id], onDelete: Cascade)
  tags        Tag[]    @relation("PostTags")
  publishedAt DateTime?
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([authorId])
  @@index([published, publishedAt(sort: Desc)])
  @@map("posts")
}

model Profile {
  id     String  @id @default(cuid())
  bio    String?
  userId String  @unique
  user   User    @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@map("profiles")
}

model Tag {
  id    String @id @default(cuid())
  name  String @unique
  posts Post[] @relation("PostTags")

  @@map("tags")
}

enum Role {
  USER
  ADMIN
}

Prisma Client Singleton

// lib/prisma.ts
import { PrismaClient } from '@prisma/client'

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient }

export const prisma =
  globalForPrisma.prisma ??
  new PrismaClient({ log: process.env.NODE_ENV === 'development' ? ['query'] : [] })

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

CRUD Patterns

// Create
const user = await prisma.user.create({
  data: { email: '[email protected]', name: 'Alice', role: 'USER' },
})

// Read with relations
const userWithPosts = await prisma.user.findUniqueOrThrow({
  where: { email: '[email protected]' },
  include: { posts: { where: { published: true }, orderBy: { publishedAt: 'desc' }, take: 5 } },
})

// Selective fields
const users = await prisma.user.findMany({
  select: { id: true, email: true, name: true },
  where: { role: 'ADMIN' },
  orderBy: { createdAt: 'desc' },
})

// Update
const updated = await prisma.user.update({
  where: { id: userId },
  data: { name: 'Alice Smith' },
})

// Upsert
const tag = await prisma.tag.upsert({
  where: { name: 'typescript' },
  create: { name: 'typescript' },
  update: {},
})

// Delete
await prisma.user.delete({ where: { id: userId } })

Pagination

// Offset pagination
async function getUsers(page: number, limit = 20) {
  const [users, total] = await prisma.$transaction([
    prisma.user.findMany({
      skip: (page - 1) * limit,
      take: limit,
      orderBy: { createdAt: 'desc' },
    }),
    prisma.user.count(),
  ])
  return { users, total, pages: Math.ceil(total / limit) }
}

// Cursor pagination (better for large datasets)
async function getUsersCursor(cursor?: string, limit = 20) {
  const users = await prisma.user.findMany({
    take: limit + 1,
    cursor: cursor ? { id: cursor } : undefined,
    orderBy: { id: 'asc' },
  })
  const hasMore   = users.length > limit
  const items     = hasMore ? users.slice(0, -1) : users
  const nextCursor = hasMore ? items[items.length - 1].id : null
  return { items, nextCursor }
}

Transactions

// Interactive transaction (safe for complex logic)
const result = await prisma.$transaction(async (tx) => {
  const from = await tx.account.findUniqueOrThrow({ where: { id: fromId } })
  if (from.balance < amount) throw new Error('Insufficient funds')

  const [debit, credit] = await Promise.all([
    tx.account.update({ where: { id: fromId }, data: { balance: { decrement: amount } } }),
    tx.account.update({ where: { id: toId },   data: { balance: { increment: amount } } }),
  ])

  await tx.transaction.create({ data: { fromId, toId, amount } })
  return { debit, credit }
}, { timeout: 5000 })

Filtering & Search

// Full-text search (PostgreSQL)
const posts = await prisma.post.findMany({
  where: {
    OR: [
      { title:   { contains: query, mode: 'insensitive' } },
      { content: { contains: query, mode: 'insensitive' } },
    ],
    AND: { published: true },
  },
})

// Date range
const recent = await prisma.post.findMany({
  where: {
    createdAt: {
      gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
    },
  },
})

// Relation filter
const usersWithPosts = await prisma.user.findMany({
  where: { posts: { some: { published: true } } },
})

Raw Queries

// Use for complex queries that Prisma can't express efficiently
const result = await prisma.$queryRaw<{ id: string; postCount: number }[]>`
  SELECT u.id, COUNT(p.id)::int AS "postCount"
  FROM users u
  LEFT JOIN posts p ON p.author_id = u.id AND p.published = true
  GROUP BY u.id
  HAVING COUNT(p.id) > ${minPosts}
  ORDER BY "postCount" DESC
  LIMIT ${limit}
`

Migrations

# Development workflow
npx prisma migrate dev --name add_post_tags

# Production deployment
npx prisma migrate deploy

# Reset dev database
npx prisma migrate reset

# Generate client after schema change
npx prisma generate

Seed Script

// prisma/seed.ts
import { prisma } from '../lib/prisma'

async function main() {
  await prisma.user.upsert({
    where: { email: '[email protected]' },
    create: { email: '[email protected]', name: 'Admin', role: 'ADMIN' },
    update: {},
  })
}

main()
  .then(() => prisma.$disconnect())
  .catch(async (e) => { console.error(e); await prisma.$disconnect(); process.exit(1) })

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 327,069. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.