본문으로 바로가기

typeORM 배포 끝났으면 Migration 하셔야죠?

category DB, ORM/🧊 typeORM 2021. 3. 16. 03:04

typeorm.io/#/migrations

 

TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server,

 

typeorm.io

 

개발 단계야 뭐 synchronize 설정을 키면 자동으로 테이블을 생성해주지만, production 환경에서는 이런 짓을 하면, 기존 고객이나 정보들이 전부 삭제되고 제로 베이스에서 시작하고 새로 테이블을 만들 수 있기 때문에 절대로 true로 놓아서는 안된다.

 

그렇다면 수작업으로 CREATE TABLE ... 로 직접 테이블을 만들어야 하는가? 그것도 방법이긴하다. 

그런데 서비스를 운영하는 등 장기적으로 생각해보면 migration이 좀 더 현명한 방법이다.

앞으로도 migration을 하게 될 것 같으니 해보자!~

 

본래 django에서도 migration해봐서 알겠지만, migration이란 현재 작성된 DB 스키마와 실제 DB 스키마를 sync해주는 것이다.

production 환경에서 DB 스키마에 수정사항이 생기면 migration해야 한다. 처음 synchronize를 끈 후 production에 올릴 때도 migration을 하면 된다.

 

=> (수정) No. 처음 올릴 때는 synchronize를 켠 후, 정상 작동을 확인한 뒤에 끄자. 이 방법이 훨씬 시간을 절약해준다. CREATE TABLE이 너무 번거롭다. migration은 기존 DB 스키마를 수정하는 데에만 사용하자.

 

테이블이 존재 하지 않으면, 생성하는 코드를 굳이 만들 수도 있지만, migration을 하는 것이 일반적이다.

 

1. migration configuration

migrations, cli를 성격에 맞게 다음과 같이 구성해주자.

문서에는 나와있지 않지만 migrations와 migrationsDir는 가급적 같은 곳으로 지정하는 것이 좋다. 지저분해진다.

const connectionOptions: ConnectionOptions = {
  type: 'mariadb',
  host: process.env.DB_ENDPOINT,
  port: Number(process.env.DB_PORT),
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  database: 'fuze', // 실제 db이름
  synchronize: env === 'production' ? false : true,
  logging: ['warn', 'error'],
  entities: [join(__dirname, '/entities/**/*.ts')],
  migrations: [env === 'production' ? join(__dirname, '../dist/migrations/*{.ts,.js}') : join(__dirname, '/migrations/*{.ts,.js}')],
  cli: {
    entitiesDir: join(__dirname, '/entities'),
    migrationsDir: join(__dirname, '/migrations'),
  },
};

 

이제 마이그레이션 코드를 생성해주도록하자.

명령어를 살펴보면 알겠지만 typeorm을 전역 설치해줘야 한다. 기본이니 굳이 설명은 패스~

typeorm migration:create -n [whateverYouWantName]

 

만약 connection 에러나 cli를 못찾겠다고 하면 typeorm.io/#/using-cli 참고해보자.

script에서 옵션을 주려면 -- -c [name] 꼴로 -- 붙이면 되고, cli로 사용하려면 그냥 옵션 주면 된다.

아래처럼 세팅하기도 한다던데, 안되는 경우에 시도해보자.

"typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js --config ./src/ormconfig.ts",
"migration": "yarn typeorm migration:run",
"migration:create": "yarn typeorm migration:create -n",
"migration:revert": "yarn typeorm migration:revert",

 

🚨 typeorm migration:generate 도 존재하는데, entity의 모델과 DB를 비교하여 업데이트 부분을 알아서 작성해준다.

TypeORM is able to automatically generate migration files with schema changes you made.

그러나 이는 컬럼의 길이, 타입 변경 시, 해당 테이블의 컬럼을 DROP 한 뒤, 재 생성하는 방식으로 이뤄지기 때문에

'기존 컬럼에 있던 데이터 전부가 날아간다!' - github.com/typeorm/typeorm/issues/3357

결론은 현재 작동 중인 서비스에서는 사용하지 말아라!

 

 

2. 생성된 migration 보일러 플레이트에서 migration 코드 작성하기

migration:create를 통해 다음과 같이 생성되었습니다. up은 마이그레이션을 위한 코드고 down은 되돌리기 위한 코드입니다.

import {MigrationInterface, QueryRunner} from "typeorm";

export class UserTableCreate1615828367540 implements MigrationInterface {

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

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

}

 

구체적으로는 다음과 같은 cli 명령어로 실행됩니다.

// up 메서드가 실행됩니다.
typeorm migration:run

// down 메서드가 실행됩니다.
typeorm migration:revert

 

실제로 작성해볼까요?

설명을 쉽게하기 위해, 생성된 데이터 모델을 먼저 보도록합시다.

 

아... mariaDB에 익숙하진 않아서 오류가 좀 있습니다.

TEXT, Blob에서는 인덱싱을 할 수 없으므로 UNIQUE 속성을 줄 수 없죠. (최신 버전 mariaDB에서 가능하긴 하지만, RDS에서 지원 안함)

여튼, 이런 식으로 작성합니다.

import { MigrationInterface, QueryRunner } from 'typeorm';

export class UserTableCreate1615829427764 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`CREATE TABLE "user" (
            id INT(11) PRIMARY KEY NOT NULL AUTOINCREMENT,
            email VARCHAR(20) NOT NULL UNIQUE,
            password VARCHAR(200) NOT NULL,
            name VARCHAR NOT NULL,
            birthday VARCHAR NOT NULL,
            phone VARCHAR NOT NULL,
            createAt Date NOT NULL DEFAULT CURRENT_TIMESTAMP() ,
            updatedAt Date NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP(),
        )COLLATE='utf8_bin'`);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP TABLE "user"`);
  }
}

 

 

그럼 이제 migration을 돌려보자

 

The migration:run and migration:revert commands only work on .js files. Thus the typescript files need to be compiled before running the commands. Alternatively you can use ts-node in conjunction with typeorm to run .ts migration files.

 

글로벌 설치도 지쳐서 그냥 npx 붙여서 돌렸드아. 그래도 된다.

ts-node ./node_modules/typeorm/cli.js migration:run

 

 

reference)

velog.io/@heumheum2/typeORM-Migration-%EC%9D%B4%EC%8A%88 

 

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체