Server/NodeJS & NestJS

NestJS에서 Prisma 사용하기

Juzdalua 2022. 3. 15. 12:26

NestJS에서 TypeORM을 사용하다 Prisma로 마이그레이션 하기로 결정했다.

기존 TypeORM의 entity나 repository는 주석, 또는 삭제를 먼저 해야한다.

그러지 않으면 충돌이 생겨 접속조차 되지 않는다.

 

https://docs.nestjs.com/recipes/prisma#prisma

공식 Docs를 따라하면 쉽다.

 

해당 프로젝트에 프리즈마를 설치하고 실행시킨다.

npm install prisma --save-dev
npx prisma init

 

schma.prisma라는 파일이 생기는데, extension에서 prisma를 검색하면 syntax highlight를 볼 수 있다.

provide에 sqlite, postgresql, mysql 중 사용할 db를 작성한다.

// schema.prisma

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

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

 

접속할 DB 정보는 url에 직접 입력해도 무방하나, 암호 등 들어가므로 환경변수에 적어주자.

env.local / env.dev 파일 등 다른 환경변수를 활용하려면 dotenv를 활용해야한다.

https://www.prisma.io/docs/guides/development-environment/environment-variables/using-multiple-env-files

 

// .env

DATABASE_URL="DB://USER:PASSWORD@HOST:PORT/DB_BANE"

디비정보를 적어주면 접속 준비 완료.

Prisma는 migration을 적용하면 DB가 초기화 되므로, db pull / db push를 활용할 수 있다.

 

// schema.prisma

model User {
  id   Int    @id @default(autoincrement())
  name String
  age  Int
}

npx prisma db pull 명령어를 쉘에서 실행시키면 DB 모델을 자동으로 가져온다. 처음일 경우 schema.prisma 파일에 직접 작성해도 된다.

 

npx prisma migrate dev --name init

처음 마이그레이션을 실행시킨다.

DB가 이미 존재한다면 주의해서 실행하자.

 

npm install @prisma/client

이제 코드에 작성할 라이브러리를 설치한다.

 

// prisma.service.ts

import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient
  implements OnModuleInit {

  async onModuleInit() {
    await this.$connect();
  }

  async enableShutdownHooks(app: INestApplication) {
    this.$on('beforeExit', async () => {
      await app.close();
    });    
  }
}

DB와 연동 할 비지니스 로직을 작성할 곳에 해당 코드를 입력한다. 연습용은 이렇게 했지만, 추후에는 각각 서비스단에서 수행할 예정이다.

 

// app.controller.ts

import { Controller, Get, NotFoundException } from '@nestjs/common';
import { AppService } from './app.service';
import { PrismaService } from './prisma/prisma.service';
import { UserService } from './user/user.service';

@Controller()
export class AppController {
    // constructor(private appService: AppService){}
    constructor(private appService: AppService, private userService: UserService, private prismaService: PrismaService){}
    
    @Get("/overview")
        async getData(){
            const overview = await this.prismaService.findJunRawQuery();
            console.log(overview)
            return overview;
        };
 };

http://localhost:3000/overview에 get method로 prisma를 활용해보겠다.

 

// prisma.module.ts

import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Module({
    imports: [],
    controllers: [],
    providers: [PrismaService],
    exports: [PrismaService]
})
export class PrismaModule {}

exports를 하지 않으면 에러가 발생한다. app.motule.ts에서 providers 배열에 PrismaService를 추가해 임포트 해야한다. 확인하자.

 

import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient, Prisma, User } from '@prisma/client';

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

    async enableShutdownHooks(app: INestApplication){
        this.$on('beforeExit', async () => {
            await app.close();
        });
    }

    //read data
    async findUserById(id: number) {
        return await this.user.findUnique({
            where: {
                id: id,
            }
        })
    };

    //find all
    async getAll(){
        return await this.user.findMany();
    }

    //find jun
    async findJun(){
        return await this.user.findMany({
            where:{
                name:'jun'
            },
            orderBy:{
                id:"desc"
            }
        })
    }

    //find jun with raw query
    async findJunRawQuery(){
        const query = "jun";
        const result = await this.$queryRaw`SELECT * FROM USER WHERE NAME=${query} ORDER BY ID DESC`
        // const result = await this.$queryRaw(
        //     Prisma.sql`SELECT * FROM USER`
        // )        
        return result;
    }

    //create data
    async createUser(createUserReq: Prisma.UserCreateInput): Promise<User|null> {
        return await this.user.create({
            data: {
                name: createUserReq.name,
                age: createUserReq.age,
            }
        })
    };

    // delete data
    async deleteUser(id: number): Promise<User> {
        return await this.user.delete({
            where: {
                id: id
            }
        });
    }
}

최종적으로 prisma로 CURD 서비스를 만들었다. update는 작성하지 않았는데 공식문서를 찾아보면 쉽게 연결할 수 있다.

https://www.prisma.io/docs/concepts/components/prisma-client/crud

 

 

// package.json

"scripts": {    
    "migrate": "npx prisma migrate dev",
    "dbpush": "npx prisma db push",
    "dbpull": "npx prisma db pull",
    "studio": "npx prisma studio"
  },

prisma 관련 scripts를 추가했다.