[typeORM] Migration 이슈

HeumHeum2·2021년 2월 7일
3
post-thumbnail

typeORM은 곧바로 데이터 변경이 있는 sync 옵션이 있다. 개발할 때는 편하지만 운영할 때는 오히려 악영향을 미칠 수 있기에 Migration을 이용해야했다. 운영파일이 나는 dist폴더에서 서버가 실행되기에 아래와 같이 설정했다.

// ormconfig.js
{
    name: "production",
    type: "mysql",
    host: process.env.DB_HOST,
    port: process.env.DB_PORT,
    username: process.env.DB_USERNAME,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_DBNAME,
    extra: {
      charset: "utf8mb4_unicode_ci",
    },
    synchronize: false,
    logging: false,
    entities: ["dist/entity/**/*.js"],
    subscribers: ["dist/subscriber/**/*.js"],
    migrations: ["dist/migration/**/*.js"],
    cli: {
      entitiesDir: "src/entity",
      migrationsDir: "src/migration",
      subscribersDir: "src/subscriber",
    },
  },

설정이 끝났으면 typeORM CLI를 통해 migration을 생성.. 하기 전에 CLI를 설정해야한다.

TypeScript를 사용자는 ts-node를 설치해야했다.

npm install -g ts-node

그 뒤에 package.json에서 "scripts"부분에 typeorm 명령을 추가한다.

"scripts" {
  ...
  "typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js"
}

이제 cli를 사용할 수 있는 환경은 갖추어졌다. 진짜로 생성해보자.

생성에는 두가지 방법이 있다.

첫번 째 방법은 create가 있고, 두번 째 방법으로 generate가 있다.

createnpm run typeorm migration:create -- -c production -n NewMigration를 사용하면 내가 지정한 디렉토리에 {TIMESTAMP}-NewMigration.ts로 파일이 생성된다. 해당 파일에 들어가보면 아래와 같은 코드가 들어가 있다.
(-c 옵션은 ormconfig.js의 name과 일치하는 옵션으로 설정한다.)

import {MigrationInterface, QueryRunner} from "typeorm";

export class NewMigrationTIMESTAMP implements MigrationInterface {

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

    }

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

    }

}

여기서 up은 해당 메소드에 작성한 코드를 db에 반영할 때 이용하고, down은 반대로 반영되었던 내용을 복구할때 이용한다.

generate는 npm run typeorm migration:generate -- -c production -n NewMigration을 이용하면 create와 비슷하게 파일이 생성되지만 다른 점이 있다면 entity의 모델과 DB를 비교하여 업데이트 부분을 알아서 작성한다는 점이다.

import {MigrationInterface, QueryRunner} from "typeorm";

export class NewMigrationTIMESTAMP implements MigrationInterface {

    async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE "post" ALTER COLUMN "title" RENAME TO "name"`);
    }

    async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE "post" ALTER COLUMN "name" RENAME TO "title"`);
    }

}

이는 분명 편하다. 하지만 나는 generate를 추천하지 않는다.

컬럼의 길이를 변경하거나 타입을 바뀔 때, 해당 테이블의 컬럼을 DROP 한 뒤, 재생성이 이뤄지기에 데이터가 날아가버린다.
해당 이슈는 아래에서 확인하기 바란다.

https://github.com/typeorm/typeorm/issues/3357

그래서 위의 해결방법으로는 개발자가 불편하겠지만 마이그레이션을 직접 작성하는 create를 사용해야한다.

migration 파일을 만들면 ts파일이 생성되고, 빌드를 한 뒤 npm run typeorm migration:run -- -c production 을 해주면 up부분의 내용들이 실행된다.

만약 되돌려야한다면 npm run typeorm migration:revert -- -c production을 이용하면 down이 실행되면서 최근 실행했던 migration의 db 변경을 되돌릴 수 있다.

profile
커피가 본체인 개발자 ☕️

0개의 댓글