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가 있다.
create은 npm 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 변경을 되돌릴 수 있다.