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을 찾아서 해결합니다.
'Back-End > NestJs' 카테고리의 다른 글
[NestJS] must be a number conforming to the specified constraints - body dto 타입 에러 해결 (0) | 2022.06.11 |
---|---|
[NestJS] Heroku, no pg_hba.conf entry for host, SSL off 해결하기 (0) | 2022.02.12 |
댓글