
-- prisma.wrk_danme_calc definition
CREATE TABLE `wrk_danme_calc` (
`Open` varchar(6) NOT NULL COMMENT '영화open',
`Code` varchar(2) NOT NULL COMMENT '영화code',
`DanmesaCode` varchar(1) NOT NULL COMMENT '단매사code',
`boxoffice_amount` bigint(20) unsigned DEFAULT NULL COMMENT '박스오피스 금액',
`boxoffice_score` int(20) unsigned DEFAULT NULL COMMENT '박스오피스 관객수',
`csb_amount` bigint(20) unsigned DEFAULT NULL COMMENT 'CSB 금액',
`csb_score` int(20) unsigned DEFAULT NULL COMMENT 'CSB 관객수',
`gonggb_amount` bigint(20) unsigned DEFAULT NULL COMMENT 'WB 순 박스오피스 CSB 공급가액',
`suryoung_amount` bigint(20) unsigned DEFAULT NULL COMMENT '단매사 순 박스오피스 정산서 수령액(공급가액)',
PRIMARY KEY (`Open`,`Code`,`DanmesaCode`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
일때 nestjs prisma6 에서 crud하는 모듈,컨트롤러,서비스를 만들어줘
다음은 NestJS 모듈, 컨트롤러, 서비스를 사용하여 wrk_danme_calc 테이블에 대한 CRUD 작업을 수행하는 구현 방안입니다. 이 테이블은 복합 기본 키(Open, Code, DanmesaCode)를 가지고 있으므로, 단일 레코드를 조회, 수정, 삭제할 때 이 세 필드를 함께 처리해야 합니다.
1. Prisma Schema 설정 (필수)
NestJS 파일을 만들기 전에, schema.prisma 파일이 올바르게 설정되었는지 확인해야 합니다. 복합 키는 명시적으로 정의되어야 합니다.
// prisma/schema.prisma
model wrk_danme_calc {
Open String @db.VarChar(6) // 영화open
Code String @db.VarChar(2) // 영화code
DanmesaCode String @db.VarChar(1) // 단매사code
boxoffice_amount BigInt? @db.UnsignedBigInt // 박스오피스 금액
boxoffice_score Int? @db.UnsignedInt // 박스오피스 관객수
csb_amount BigInt? @db.UnsignedBigInt // CSB 금액
csb_score Int? @db.UnsignedInt // CSB 관객수
gonggb_amount BigInt? @db.UnsignedBigInt // WB 순 박스오피스 CSB 공급가액
suryoung_amount BigInt? @db.UnsignedBigInt // 단매사 순 박스오피스 정산서 수령액(공급가액)
@@id([Open, Code, DanmesaCode])
@@map("wrk_danme_calc")
}
2. 모듈 (danme-calc.module.ts)
이 모듈은 PrismaModule을 가져오고 컨트롤러와 서비스를 설정합니다.
// src/danme-calc/danme-calc.module.ts
import { Module } from '@nestjs/common';
import { DanmeCalcController } from './danme-calc.controller';
import { DanmeCalcService } from './danme-calc.service';
import { PrismaModule } from '../prisma/prisma.module'; // 전역 PrismaModule이 있다고 가정
@Module({
imports: [PrismaModule],
controllers: [DanmeCalcController],
providers: [DanmeCalcService],
})
export class DanmeCalcModule {}
3. 서비스 (danme-calc.service.ts)
서비스는 비즈니스 로직을 처리하고 Prisma 클라이언트와 직접 상호 작용합니다.
// src/danme-calc/danme-calc.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service'; // 경로에 맞게 수정 필요
import { wrk_danme_calc, Prisma } from '@prisma/client';
// 복합 기본 키 타입을 정의하여 사용하기 쉽게 합니다.
type DanmeCalcUniqueKey = {
Open: string;
Code: string;
DanmesaCode: string;
};
@Injectable()
export class DanmeCalcService {
constructor(private prisma: PrismaService) {}
// ** 1. 모든 레코드 조회 (READ all) **
async findAll(): Promise<wrk_danme_calc[]> {
return this.prisma.wrk_danme_calc.findMany();
}
// ** 2. 복합 키로 단일 레코드 조회 (READ one) **
async findOne(key: DanmeCalcUniqueKey): Promise<wrk_danme_calc | null> {
return this.prisma.wrk_danme_calc.findUnique({
where: key, // Prisma는 여기서 복합 키를 자동으로 처리합니다.
});
}
// ** 3. 새 레코드 생성 (CREATE) **
async create(
data: Prisma.wrk_danme_calcCreateInput,
): Promise<wrk_danme_calc> {
return this.prisma.wrk_danme_calc.create({
data,
});
}
// ** 4. 복합 키로 기존 레코드 업데이트 (UPDATE) **
async update(
key: DanmeCalcUniqueKey,
data: Prisma.wrk_danme_calcUpdateInput,
): Promise<wrk_danme_calc> {
return this.prisma.wrk_danme_calc.update({
where: key,
data,
});
}
// ** 5. 복합 키로 레코드 삭제 (DELETE) **
async remove(key: DanmeCalcUniqueKey): Promise<wrk_danme_calc> {
return this.prisma.wrk_danme_calc.delete({
where: key,
});
}
}
4. 컨트롤러 (danme-calc.controller.ts)
컨트롤러는 들어오는 HTTP 요청을 처리하고, 서비스를 호출하며, 응답을 반환합니다.
// src/danme-calc/danme-calc.controller.ts
import {
Controller,
Get,
Post,
Body,
Put,
Param,
Delete,
NotFoundException,
} from '@nestjs/common';
import { DanmeCalcService } from './danme-calc.service';
import { Prisma } from '@prisma/client';
@Controller('danme-calc')
export class DanmeCalcController {
constructor(private readonly danmeCalcService: DanmeCalcService) {}
// URL 매개변수에서 복합 키를 추출하는 헬퍼 함수
private getKeyParams(params: { Open: string; Code: string; DanmesaCode: string }) {
return {
Open: params.Open,
Code: params.Code,
DanmesaCode: params.DanmesaCode,
};
}
// POST /danme-calc (생성)
@Post()
create(@Body() createDanmeCalcDto: Prisma.wrk_danme_calcCreateInput) {
return this.danmeCalcService.create(createDanmeCalcDto);
}
// GET /danme-calc (전체 조회)
@Get()
findAll() {
return this.danmeCalcService.findAll();
}
// GET /danme-calc/:Open/:Code/:DanmesaCode (단일 조회)
// 참고: 키의 세 부분이 모두 URL을 통해 전달되어야 합니다.
@Get(':Open/:Code/:DanmesaCode')
async findOne(@Param() params: { Open: string; Code: string; DanmesaCode: string }) {
const key = this.getKeyParams(params);
const record = await this.danmeCalcService.findOne(key);
if (!record) {
throw new NotFoundException(
`키 ${key.Open}/${key.Code}/${key.DanmesaCode} 를 가진 레코드를 찾을 수 없습니다.`,
);
}
return record;
}
// PUT /danme-calc/:Open/:Code/:DanmesaCode (업데이트)
@Put(':Open/:Code/:DanmesaCode')
update(
@Param() params: { Open: string; Code: string; DanmesaCode: string },
@Body() updateDanmeCalcDto: Prisma.wrk_danme_calcUpdateInput,
) {
const key = this.getKeyParams(params);
return this.danmeCalcService.update(key, updateDanmeCalcDto);
}
// DELETE /danme-calc/:Open/:Code/:DanmesaCode (삭제)
@Delete(':Open/:Code/:DanmesaCode')
remove(@Param() params: { Open: string; Code: string; DanmesaCode: string }) {
const key = this.getKeyParams(params);
return this.danmeCalcService.remove(key);
}
}
🛠️ 다음 단계
- Prisma 설정: PrismaService와 PrismaModule이 올바르게 구현되어 ../prisma/ 경로에서 사용 가능한지 확인하세요.
- 클라이언트 생성: npx prisma generate를 실행하여 Prisma 클라이언트와 생성된 TypeScript 타입을 업데이트하세요.
- 모듈 등록: 루트 AppModule에 DanmeCalcModule을 임포트(Import)하세요.
- DTO (Data Transfer Object): 상용 수준의 코드를 위해서는 요청 본문(request body)에 Prisma 생성 타입을 직접 사용하는 대신, class-validator 및 class-transformer를 사용하여 명시적인 DTO(예: CreateDanmeCalcDto, UpdateDanmeCalcDto)를 만드는 것이 좋습니다.
Prisma 모듈 설정과 DTO 파일을 포함하여 필요한 모든 코드를 제공해 드릴게요. 이 파일들을 사용하면 바로 NestJS 프로젝트에 적용할 수 있습니다.
1. Prisma 설정 및 서비스
1-1. prisma/prisma.module.ts (Prisma 모듈)
이 모듈은 PrismaService를 전역적으로 제공할 수 있게 설정합니다.
// src/prisma/prisma.module.ts
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Module({
providers: [PrismaService],
exports: [PrismaService], // 다른 모듈에서 사용 가능하도록 export
})
export class PrismaModule {}
1-2. prisma/prisma.service.ts (Prisma 서비스)
NestJS 생명 주기(OnModuleInit, OnModuleDestroy)에 맞게 Prisma 클라이언트 연결을 초기화하고 종료합니다.
// 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 onModuleDestroy() {
// 애플리케이션 종료 시 데이터베이스 연결을 끊습니다.
await this.$disconnect();
}
}
2. DTO (Data Transfer Objects) 파일
Prisma 타입을 직접 사용하는 대신, 유효성 검사(class-validator)를 위해 DTO를 생성하는 것이 모범 사례입니다.
2-1. danme-calc.dto.ts
// src/danme-calc/dto/danme-calc.dto.ts
import {
IsString,
IsInt,
IsOptional,
IsNotEmpty,
MinLength,
MaxLength,
IsPositive,
} from 'class-validator';
// ----------------------------------------------------
// 1. 레코드 생성 시 사용 (POST)
// ----------------------------------------------------
export class CreateDanmeCalcDto {
// Primary Keys (필수 입력)
@IsString()
@IsNotEmpty()
@MaxLength(6)
Open: string; // 영화open
@IsString()
@IsNotEmpty()
@MaxLength(2)
Code: string; // 영화code
@IsString()
@IsNotEmpty()
@MaxLength(1)
DanmesaCode: string; // 단매사code
// Optional Fields (선택적 입력)
@IsOptional()
@IsInt()
@IsPositive()
boxoffice_amount?: bigint; // bigint는 JS에서 Number로 정확히 표현하기 어려워 Prisma에서는 BigInt 타입으로 매핑되지만, DTO에서는 validation만 진행합니다.
@IsOptional()
@IsInt()
@IsPositive()
boxoffice_score?: number;
@IsOptional()
@IsInt()
@IsPositive()
csb_amount?: bigint;
@IsOptional()
@IsInt()
@IsPositive()
csb_score?: number;
@IsOptional()
@IsInt()
@IsPositive()
gonggb_amount?: bigint;
@IsOptional()
@IsInt()
@IsPositive()
suryoung_amount?: bigint;
}
// ----------------------------------------------------
// 2. 레코드 수정 시 사용 (PUT/PATCH)
// ----------------------------------------------------
// 모든 필드를 선택적으로 만들고, Primary Key는 제외합니다.
// Primary Key는 URL 파라미터로 받기 때문입니다.
import { PartialType } from '@nestjs/mapped-types';
export class UpdateDanmeCalcDto extends PartialType(CreateDanmeCalcDto) {
// 복합 키 필드는 상속받지만, PartialType 덕분에 모두 Optional이 됩니다.
// 이 DTO는 Body 데이터에 사용되며, 키 필드(Open, Code, DanmesaCode)는 제외하고 데이터를 수정합니다.
// 실제 키는 @Param()으로 전달받습니다.
}
3. 수정된 서비스 및 컨트롤러
3-1. danme-calc.service.ts (수정)
DTO 대신 Prisma의 입력 타입을 사용하도록 유지하되, 필요 함수를 그대로 사용합니다.
// src/danme-calc/danme-calc.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { wrk_danme_calc, Prisma } from '@prisma/client';
// 복합 기본 키 타입
export type DanmeCalcUniqueKey = {
Open: string;
Code: string;
DanmesaCode: string;
};
@Injectable()
export class DanmeCalcService {
constructor(private prisma: PrismaService) {}
// 1. 생성 (CREATE)
async create(
data: Prisma.wrk_danme_calcCreateInput,
): Promise<wrk_danme_calc> {
return this.prisma.wrk_danme_calc.create({
data,
});
}
// 2. 전체 조회 (READ all)
async findAll(): Promise<wrk_danme_calc[]> {
return this.prisma.wrk_danme_calc.findMany();
}
// 3. 단일 조회 (READ one)
async findOne(key: DanmeCalcUniqueKey): Promise<wrk_danme_calc | null> {
return this.prisma.wrk_danme_calc.findUnique({
where: key,
});
}
// 4. 업데이트 (UPDATE)
async update(
key: DanmeCalcUniqueKey,
data: Prisma.wrk_danme_calcUpdateInput,
): Promise<wrk_danme_calc> {
return this.prisma.wrk_danme_calc.update({
where: key,
data,
});
}
// 5. 삭제 (DELETE)
async remove(key: DanmeCalcUniqueKey): Promise<wrk_danme_calc> {
return this.prisma.wrk_danme_calc.delete({
where: key,
});
}
}
3-2. danme-calc.controller.ts (수정)
DTO를 임포트하고 @Body()에 적용하여 유효성 검사를 수행합니다.
// src/danme-calc/danme-calc.controller.ts
import {
Controller,
Get,
Post,
Body,
Put,
Param,
Delete,
NotFoundException,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { DanmeCalcService, DanmeCalcUniqueKey } from './danme-calc.service';
import { CreateDanmeCalcDto, UpdateDanmeCalcDto } from './dto/danme-calc.dto';
// 컨트롤러 레벨에서 ValidationPipe를 적용하여 DTO 유효성 검사를 활성화합니다.
@Controller('danme-calc')
@UsePipes(new ValidationPipe({ transform: true }))
export class DanmeCalcController {
constructor(private readonly danmeCalcService: DanmeCalcService) {}
// URL 매개변수에서 복합 키를 추출하는 헬퍼 함수
private getKeyParams(params: { Open: string; Code: string; DanmesaCode: string }): DanmeCalcUniqueKey {
return {
Open: params.Open,
Code: params.Code,
DanmesaCode: params.DanmesaCode,
};
}
// 1. 생성 (POST /danme-calc)
@Post()
create(@Body() createDanmeCalcDto: CreateDanmeCalcDto) {
// DTO를 Prisma CreateInput으로 사용
return this.danmeCalcService.create(createDanmeCalcDto);
}
// 2. 전체 조회 (GET /danme-calc)
@Get()
findAll() {
return this.danmeCalcService.findAll();
}
// 3. 단일 조회 (GET /danme-calc/:Open/:Code/:DanmesaCode)
@Get(':Open/:Code/:DanmesaCode')
async findOne(@Param() params: { Open: string; Code: string; DanmesaCode: string }) {
const key = this.getKeyParams(params);
const record = await this.danmeCalcService.findOne(key);
if (!record) {
throw new NotFoundException(
`키 ${key.Open}/${key.Code}/${key.DanmesaCode} 를 가진 레코드를 찾을 수 없습니다.`,
);
}
return record;
}
// 4. 업데이트 (PUT /danme-calc/:Open/:Code/:DanmesaCode)
@Put(':Open/:Code/:DanmesaCode')
update(
@Param() params: { Open: string; Code: string; DanmesaCode: string },
@Body() updateDanmeCalcDto: UpdateDanmeCalcDto,
) {
const key = this.getKeyParams(params);
// DTO를 Prisma UpdateInput으로 사용
return this.danmeCalcService.update(key, updateDanmeCalcDto);
}
// 5. 삭제 (DELETE /danme-calc/:Open/:Code/:DanmesaCode)
@Delete(':Open/:Code/:DanmesaCode')
remove(@Param() params: { Open: string; Code: string; DanmesaCode: string }) {
const key = this.getKeyParams(params);
return this.danmeCalcService.remove(key);
}
}
🚀 적용 순서 요약
- Prisma Schema 확인: schema.prisma에 복합 키가 올바르게 설정되었는지 확인하세요.
- Prisma 설치 및 생성:
npm install @prisma/client npx prisma generate - 파일 배치: 위에 제공된 파일들을 적절한 경로(e.g., src/prisma/, src/danme-calc/, src/danme-calc/dto/)에 배치하세요.
- Module 등록: AppModule에 PrismaModule과 DanmeCalcModule을 등록하세요.
이 코드는 복합 키를 효율적으로 처리하고 NestJS의 모범 사례인 DTO 기반 유효성 검사를 포함하고 있습니다.
NestJS 컨트롤러 코드(DanmeCalcController)를 바탕으로 Postman에서 테스트할 수 있는 컬렉션(collection.json) 형태로 JSON을 생성해 드릴 수 있습니다.
이 컬렉션은 기본 URL을 http://localhost:3000/danme-calc (NestJS 기본 포트 3000 가정)로 설정하고, 컨트롤러에 정의된 생성(POST), 전체 조회(GET), 단일 조회(GET), 업데이트(PUT), 삭제(DELETE) 엔드포인트에 대한 요청 예시를 포함합니다.
🏗️ Postman 컬렉션 JSON
다음 JSON 코드를 Postman에서 Import 기능을 사용하여 불러오시면 됩니다.
danme-calc_collection.json
{
"info": {
"_postman_id": "YOUR_UNIQUE_POSTMAN_ID",
"name": "Danme Calc API",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Create wrk_danme_calc (POST)",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"Open\": \"TEST_OPEN_KEY\",\n \"Code\": \"TEST_CODE\",\n \"DanmesaCode\": \"TEST_DANMESA\",\n \"DanmeName\": \"단메 이름 예시\",\n \"CalculateValue\": 1234.56,\n \"UsedValue\": 100.00,\n \"CalculatedAt\": \"2025-01-01T10:00:00Z\"\n}"
},
"url": {
"raw": "{{baseUrl}}/danme-calc",
"host": [
"{{baseUrl}}"
],
"path": [
"danme-calc"
]
},
"description": "새로운 단메 계산 레코드를 생성합니다. 복합 키 필드(Open, Code, DanmesaCode)를 포함해야 합니다."
},
"response": []
},
{
"name": "Find All wrk_danme_calc (GET)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/danme-calc",
"host": [
"{{baseUrl}}"
],
"path": [
"danme-calc"
]
},
"description": "모든 단메 계산 레코드를 조회합니다."
},
"response": []
},
{
"name": "Find One wrk_danme_calc (GET)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/danme-calc/TEST_OPEN_KEY/TEST_CODE/TEST_DANMESA",
"host": [
"{{baseUrl}}"
],
"path": [
"danme-calc",
"TEST_OPEN_KEY",
"TEST_CODE",
"TEST_DANMESA"
]
},
"description": "복합 키를 사용하여 특정 단메 계산 레코드를 조회합니다. 경로 매개변수 순서는 Open, Code, DanmesaCode 입니다."
},
"response": []
},
{
"name": "Update wrk_danme_calc (PUT)",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"DanmeName\": \"업데이트된 단메 이름\",\n \"CalculateValue\": 9999.99\n}"
},
"url": {
"raw": "{{baseUrl}}/danme-calc/TEST_OPEN_KEY/TEST_CODE/TEST_DANMESA",
"host": [
"{{baseUrl}}"
],
"path": [
"danme-calc",
"TEST_OPEN_KEY",
"TEST_CODE",
"TEST_DANMESA"
]
},
"description": "복합 키를 사용하여 특정 단메 계산 레코드를 업데이트합니다."
},
"response": []
},
{
"name": "Delete wrk_danme_calc (DELETE)",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{baseUrl}}/danme-calc/TEST_OPEN_KEY/TEST_CODE/TEST_DANMESA",
"host": [
"{{baseUrl}}"
],
"path": [
"danme-calc",
"TEST_OPEN_KEY",
"TEST_CODE",
"TEST_DANMESA"
]
},
"description": "복합 키를 사용하여 특정 단메 계산 레코드를 삭제합니다."
},
"response": []
}
],
"variable": [
{
"key": "baseUrl",
"value": "http://localhost:3000",
"type": "string"
}
]
}
📝 사용 방법 안내
1. 환경 설정
- Postman의 오른쪽 상단에 있는 Environments 드롭다운 메뉴를 클릭하고 Manage Environments를 선택합니다.
- 새로운 환경을 추가하고 이름을 지정합니다 (예: NestJS Local).
- 다음 변수를 추가합니다:
- Variable: baseUrl
- Initial Value: http://localhost:3000 (NestJS 서버가 실행 중인 주소와 포트)
- Current Value: http://localhost:3000
- 환경을 저장하고 드롭다운에서 방금 생성한 환경을 선택합니다.
2. 컬렉션 가져오기
- Postman 왼쪽 상단의 Import 버튼을 클릭합니다.
- 위의 JSON 코드를 복사하여 Raw Text 탭에 붙여넣거나, 파일로 저장하여 File 탭에서 업로드합니다.
- 컬렉션이 성공적으로 가져와지면, 왼쪽 사이드바의 Collections 탭에서 Danme Calc API를 확인할 수 있습니다.
3. 테스트 시 유의사항
- 키 값: Find One, Update, Delete 요청 URL에 포함된 TEST_OPEN_KEY, TEST_CODE, TEST_DANMESA 값은 Create 요청 시 사용한 값과 일치해야 성공적으로 동작합니다.
- POST/PUT Body: wrk_danme_calc 테이블의 실제 스키마에 맞게 필드 이름과 데이터 타입을 조정해야 할 수 있습니다. 위에 제공된 예시는 일반적인 데이터베이스 필드를 가정한 것입니다.
- 실행 순서: 일반적으로 Create $\rightarrow$ Find All $\rightarrow$ Find One $\rightarrow$ Update $\rightarrow$ Delete 순서로 테스트하는 것이 좋습니다.
'Nest.js를 배워보자' 카테고리의 다른 글
| 🛠️ NestJS 컨트롤러에 HATEOAS 적용 (수정된 danme-calc.controller.ts) (0) | 2025.12.11 |
|---|---|
| 🚀 prisma db push는 무엇인가요? (0) | 2025.12.09 |
| 🔄 MySQL CREATE TABLE 문으로 Prisma 스키마 만들기 (0) | 2025.12.09 |
| 🛠️ NestJS Prisma 6에서 자료가 없을 때 Seed 데이터 자동 추가하기 (0) | 2025.12.09 |
| 🛠️ NestJS + Prisma에서 MyBatis처럼 XML로 SQL 소스를 관리하는 방법 (0) | 2025.12.09 |