카테고리 없음

PrismaService에 트랜잭션 기반 시드 추가 / NestJS CLI 커맨드로 실행하는 방법

김영수 2025. 4. 5. 13:49

 

PrismaService에 트랜잭션 기반 시드 추가, 또는 NestJS CLI 커맨드로 실행하는 방법도 확장해주시고. 그리고 seed.ts에 타입 안전성과 트랜잭션까지 적용된 버전도 만들어주시고, .env 설정 자동 전환 스크립트도 추가해 주세요.

 

응답:

1. PrismaService에 트랜잭션 기반 시드 지원 추가

🔹 prisma.service.ts 확장

// src/prisma/prisma.service.ts
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
  async onModuleInit() {
    await this.$connect();
  }

  async enableShutdownHooks() {
    process.on('beforeExit', async () => {
      await this.$disconnect();
    });
  }

  async transaction<T>(callback: (prisma: PrismaClient) => Promise<T>): Promise<T> {
    return this.$transaction(async (tx) => {
      return callback(tx);
    });
  }

  async onModuleDestroy() {
    await this.$disconnect();
  }
}

 

🔸 이제 PrismaService.transaction() 메서드로 안전한 트랜잭션 실행 가능

 

2. 타입 안전성 + 트랜잭션 적용된 seed.ts

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

const prisma = new PrismaClient();

async function seedData(prisma: PrismaClient) {
  // 타입 자동 인식 가능
  const user = await prisma.user.upsert({
    where: { email: 'test@example.com' },
    update: {},
    create: {
      email: 'test@example.com',
      name: 'Test User',
    },
  });

  console.log('Seeded user:', user);
}

export async function seed(prisma?: PrismaClient) {
  const client = prisma ?? new PrismaClient();

  await client.$transaction(async (tx) => {
    await seedData(tx);
  });

  if (!prisma) await client.$disconnect();
}

if (require.main === module) {
  // CLI로 직접 실행될 때
  seed()
    .then(() => console.log('✅ Seeding complete'))
    .catch((e) => {
      console.error(e);
      process.exit(1);
    });
}

 

3. NestJS CLI 명령으로 시드 실행하기

🔹 별도 커맨드 파일 생성

// scripts/seed.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from '../src/app.module';
import { PrismaService } from '../src/prisma/prisma.service';
import { seed } from '../prisma/seed/seed';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const prisma = app.get(PrismaService);

  await prisma.enableShutdownHooks();

  console.log('🌱 Starting seed...');
  await seed(prisma);
  console.log('✅ Seed completed!');

  await app.close();
}

bootstrap();

 

🔹 package.json 스크립트에 등록

 

"scripts": {
  "start:dev": "nest start --watch",
  "seed": "ts-node scripts/seed.ts"
}

 

npm run seed

 

4. .env 자동 전환 스크립트

🔹 scripts/set-env.ts 추가

// scripts/set-env.ts
import { writeFileSync } from 'fs';

const env = process.argv[2] || 'development';

const envFile = `.env.${env}`;
const target = '.env';

try {
  const content = require('fs').readFileSync(envFile);
  writeFileSync(target, content);
  console.log(`🔄 Switched to ${envFile}`);
} catch (e) {
  console.error(`❌ Failed to switch to ${envFile}`);
}

 

🔹 package.json에 명령어 추가

"scripts": {
  "env:dev": "ts-node scripts/set-env.ts development",
  "env:prod": "ts-node scripts/set-env.ts production"
}

 

🔹 사용 예시

npm run env:dev     # .env 파일을 .env.development 내용으로 대체
npm run env:prod    # .env 파일을 .env.production 내용으로 대체

 

정리된 디렉토리 구조 예시

/prisma
  ├─ schema.prisma
  ├─ seed/
  │   ├─ seed.ts
  │   └─ data.ts
/scripts
  ├─ seed.ts         # NestJS CLI 기반 시드
  └─ set-env.ts      # .env 자동 전환
/src/prisma
  ├─ prisma.module.ts
  └─ prisma.service.ts