
repository-pattern-nestjs
by allenlin90
SKILL.md
name: repository-pattern-nestjs description: Provides Prisma-specific repository implementation patterns for NestJS. This skill should be used when implementing repositories that extend BaseRepository or use Prisma delegates.
Repository Pattern - Prisma/NestJS Implementation
Implementation guide for NestJS Repositories using Prisma.
For core database concepts (Soft Delete, Bulk Ops, Transactions), see Database Patterns. For general repository theory, see Repository Pattern.
BaseRepository Extension
All repositories MUST extend BaseRepository<T, C, U, W>.
import { BaseRepository, IBaseModel } from '@/lib/repositories/base.repository';
// 1. Define Wrapper (bridges BaseRepo generics to Prisma Delegate)
class UserModelWrapper implements IBaseModel<User, Prisma.UserCreateInput, Prisma.UserUpdateInput, Prisma.UserWhereInput> {
constructor(private readonly delegate: Prisma.UserDelegate) {}
create(args: any) { return this.delegate.create(args); }
findFirst(args: any) { return this.delegate.findFirst(args); }
findMany(args: any) { return this.delegate.findMany(args); }
update(args: any) { return this.delegate.update(args); }
delete(args: any) { return this.delegate.delete(args); }
count(args: any) { return this.delegate.count(args); }
}
// 2. Implement Repository
@Injectable()
export class UserRepository extends BaseRepository<
User,
Prisma.UserCreateInput,
Prisma.UserUpdateInput,
Prisma.UserWhereInput
> {
constructor(private readonly prisma: PrismaService) {
super(new UserModelWrapper(prisma.user));
}
}
Specialized Find Methods
Implement domain-specific queries here (not in Service).
// Find by UID (Standard)
async findByUid(uid: string): Promise<User | null> {
return this.model.findFirst({
where: { uid, deletedAt: null },
});
}
// Find or Throw (Let Prisma throw P2025 -> converted to 404 by Global Filter)
async findByUidOrThrow(uid: string): Promise<User> {
return this.model.findFirstOrThrow({
where: { uid, deletedAt: null },
});
}
Type-Safe Includes
Return typed payloads based on includes.
async findWithRelations<T extends Prisma.UserInclude>(
include: T,
): Promise<Prisma.UserGetPayload<{ include: T }>[]> {
return this.model.findMany({
where: { deletedAt: null },
include,
});
}
Implementation of Database Patterns
Refer to Database Patterns for the "Why". Here is the "How".
Soft Delete
The BaseRepository handles this for standard methods. If bypassing base methods:
async softDelete(where: Prisma.UserWhereInput): Promise<void> {
await this.model.updateMany({
where: { ...where, deletedAt: null },
data: { deletedAt: new Date() },
});
}
Bulk Create
async createMany(data: Prisma.UserCreateInput[]): Promise<Prisma.BatchPayload> {
return this.model.createMany({
data,
skipDuplicates: true,
});
}
Pagination
async findPaginated(params: PaginationParams): Promise<PaginatedResult<User>> {
const [data, total] = await Promise.all([
this.model.findMany({
where: { ...params.where, deletedAt: null },
skip: params.skip,
take: params.take
}),
this.model.count({ where: { ...params.where, deletedAt: null } }),
]);
return { data, total, page: params.page, limit: params.limit };
}
Module Registration
@Module({
imports: [PrismaModule],
providers: [UserRepository],
exports: [UserRepository], // Export for Services to use!
})
export class UserModule {}
Testing
Integration Tests with Real Database (Recommended)
it('should not find soft-deleted user', async () => {
await prisma.user.create({ data: { uid: 'u_del', deletedAt: new Date() } });
const user = await repository.findByUid('u_del');
expect(user).toBeNull();
});
Best Practices Checklist
- Extend
BaseRepository - Implement
findByUidandfindByUidOrThrow - Always filter
deletedAt: nullin custom queries - Use
Promise.allfor pagination (count + data) - Return
nullfor not found (unlessOrThrow) - Never throw HTTP Exceptions (leave that to Service/Controller)
- Use
Prisma.GetPayloadfor typed relations
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon