본문 바로가기
Back-End/NestJs

[NestJS] typeOrm migration 정리

by 흐암졸령 2022. 6. 10.
반응형

 typeorm 에서 database migration을 하기 위해서는 ormconfig에 마이그레이션 파일이 들어갈 위치를 지정해 주어야 합니다. root directory에 ormconfig.json파일에 써도 무방하지만 저는 develop 환경과 production 환경을 분리하기 위해서 ormconfig.ts파일을 만들고 환경변수 NODE_ENV에 따라서 두 환경을 분리하였습니다.

import { ConnectionOptions } from 'typeorm';

const typeormConfig: ConnectionOptions = process.env.NODE_ENV
  ? {
      url: process.env.DATABASE_URL,
      type: 'postgres',
      synchronize: false,
      ssl: {
        rejectUnauthorized: false,
      },
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      migrations: [__dirname + '/src/migrations/*.{ts,js}'],
      migrationsTableName: 'migrations',
      cli: {
        entitiesDir: __dirname + '/**/*.entity.{js,ts}',
        migrationsDir: 'src/migrations/',
      },
    }
  : {
      type: 'sqlite',
      database: 'db',
      synchronize: false,
      logging: true,
      entities: [__dirname + '/**/*.entity.{ts,js}'],
      migrations: [__dirname + '/src/migrations/*.{ts,js}'],
      cli: {
        entitiesDir: __dirname + '/**/*.entity.{ts,js}',
        migrationsDir: 'src/migrations',
      },
    };

export = typeormConfig;

 type의 부분을 보면 아시겠지만 개발환경에서는 sqlite3, production 환경에서는 heroku의 postgres를 사용하고 있습니다. 개발환경에서야 지금은 false로 되어있는 synchronize 값을 true로 설정한다면 자동으로 마이그레이션을 해줍니다. 그러나 배포환경에서도 이를 설정해두면 테이블을 다 드랍한 후 새로 만들어서 이미 저장되어 있는 데이터가 날라갈 수 있으니 false로 설정하고 마이그레이션을 해보겠습니다.

 

 마이그레이션 명령어를 위해서 package.json의 script의 다음을 넣어줍니다. 명령어를 보시면 아시겠지만 당연하게 typeorm이 설치되어 있어야 합니다.

"typeorm": "ts-node --transpile-only ./node_modules/typeorm/cli.js"

 

 마이그레이션 명령어는 네 가지로 create, revert, generate, run이 있습니다. 명령어 실행 방법은 다음과 같습니다.

npm run typeorm -- migration:create -n [migrationName]
npm run typeorm -- migration:revert
npm run typeorm -- migration:generate -n [migrationName]
npm run typeorm -- migration:run

물론 npm이 아니라 yarn을 쓰시는 분들은 npm run 대신에 yarn을 입력해주시면 됩니다. 스크립트에서 npm run typeorm은 package.json에 있는 스크립트를 실행하는데 이때 뒤의 스크립트도 붙여서 실행하기 위해서 --라는 것을 사용합니다.

 

 create나 generate을 하게되면 마이그레이션 파일을 만들어 줍니다. 파일 이름은 1644698694030-createUserTable.ts 와 같이 생성되며 파일 형식은 다음과 같습니다.

import { MigrationInterface, QueryRunner } from 'typeorm';

export class createUserTable1644698694030 implements MigrationInterface {
  name = 'createUserTable1644698694030';

  public async up(queryRunner: QueryRunner): Promise<void> {
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
  }
}

migration:run을 하게되면 up에 있는 부분이 실행되고, migration:revert를 하게되면 dowm에 있는 부분이 실행되게 됩니다.

 

create랑 generate모두 마이그레이션 파일이 생성된다고 설명했는데 둘 사이에는 큰 차이가 있습니다. create는 그냥 빈 파일만을 생성시켜 줄 뿐이지만 generate는 데이터베이스와 entity사이의 차이점이 있으면 이를 자동으로 파악하고 sql구문을 작성합니다. 그러나 이는 컬럼의 길이, 타입 변경 시, 해당 테이블의 컬럼을 DROP한 뒤에 재 생성하는 방식이기 때문에

기존 컬럼에 있던 데이터가 모두 삭제됩니다.

따라서 generate가 아닌 create로 파일을 만들고 sql구문을 따로 작성하는 것이 안정적입니다. 그러나 저는 아직까지 sql을 잘 알지는 못하기 때문에 우선 generate로 현재 entity와 비교하여서 마이그레이션 파일을 만듭니다. 그 후에 마이그레이션 파일을 보고 DROP하는 식으로 이루어진다면 해당 기능을 DROP하지 않으면서 변경하는 sql을 찾아서 해결합니다.

반응형

댓글