Implementing Design Patterns

1. Implementing Repository Pattern

export class UserRepository {
  constructor(private prisma: PrismaClient) {}
  findById(id: number) { return this.prisma.user.findUnique({ where: { id } }); }
  create(data: Prisma.UserCreateInput) { return this.prisma.user.create({ data }); }
}
BenefitDetail
EncapsulationHide query details
TestabilityMock the repo, not Prisma

2. Using Unit of Work Pattern

await prisma.$transaction(async (tx) => {
  await new UserRepository(tx).create(userData);
  await new AuditRepository(tx).log("user.create");
});
AspectDetail
Single txAll-or-nothing
Repo injectionPass tx client to repos

3. Implementing Service Layer

ResponsibilityDetail
Use casesOrchestrate repos + domain logic
TransactionsDefine boundaries
ValidationDomain invariants

4. Using Singleton Pattern

// lib/prisma.ts
import { PrismaClient } from "@prisma/client";
const globalAny = global as any;
export const prisma: PrismaClient = globalAny.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== "production") globalAny.prisma = prisma;
ReasonDetail
Hot reloadAvoid pool exhaustion in Next.js dev
Single poolOne client per process

5. Implementing Factory Pattern

UseDetail
Per-tenant clientFactory builds client by URL
Test dataFactory functions for fixtures

6. Using Builder Pattern for Queries

class UserQuery {
  private args: Prisma.UserFindManyArgs = {};
  where(w: Prisma.UserWhereInput) { this.args.where = { ...this.args.where, ...w }; return this; }
  paginate(skip: number, take: number) { Object.assign(this.args, { skip, take }); return this; }
  exec(p: PrismaClient) { return p.user.findMany(this.args); }
}
BenefitDetail
FluencyChainable filters
ReuseCompose conditions

7. Implementing Observer Pattern

MechanismDetail
PulseDB-level observer
Extension hooksApp-level observation
EventEmitterIn-process pub/sub

8. Using Strategy Pattern

ExampleDetail
PricingSwap pricing strategies
NotificationEmail/SMS/Push providers

9. Implementing CQRS Pattern

Commands

  • Write side
  • Validate + persist
  • Use transactions

Queries

  • Read side
  • Optimized projections
  • Cacheable via Accelerate

10. Using Domain-Driven Design

ConceptDetail
AggregatesRoot entity + invariants
Value objectsImmutable types
Bounded contextSeparate Prisma schemas per context