본문 바로가기
javascript/express

마이그레이션 관리

by choi-dev 2024. 9. 24.

예전에 장고를 배웠을 때는 마이그레이션 로그들이 자동으로 생성되었던 기억이 있는데 스프링부트와 express.js를 사용해본 이 기점에서 마이그레이션 관리는 따로 해주지 않고 있는 것으로 보였다.

 

스프링부트는 개인 프로젝트에서 Flyway라고 하는 의존성을 설치해 사용해봤고 이번 회사에서는 knex ORM을 활용해서 마이그레이션 관리 라이브러리를 사용해보았다.

 

마이그레이션 관리를 왜 해야되지?

실제로 신입 개발자 때 팀 프로젝트를 진행했던 적이 있었는데 당시 깃을 관리하던 팀원이 마이그레이션 소스를 깃 이그노어 처리했었다. 한 회사의 면접에서 왜 이그노어 처리했냐고 물었을 때 우물쭈물 대답했던 기억이 났다. 물론 그건 정답도 아니었고.

 

돌이켜 생각해보면 어차피 오픈소스로 공개하지 않는 이상 코드는 외부로 노출시키지 않지만 마이그레이션 로그 또한 굳이 외부에 노출시킬 이유는 없다고 생각한다. 테이블의 스키마 변경 내역, 어떤 테이블인지 예측 등 다양하게 추측해볼 수 있기에 보안 관점에서는 주의가 필요하겠다.

 

단, 회사 내에서는 마이그레이션 로그를 생성했을 때 깃 이그노어처리하면 안된다. 그 이유는 지금부터 진행할 knex로 마이그레이션 관리하는 법을 상기하면서 적어두려고 한다. 미리 말해두자면, 해당 마이그레이션 로그가 있어야 새로운 마이그레이션을 적용할 때 문제가 되지 않는다.

 

knex

ORM 관련해서는 여러 라이브러리 소스들이 존재할텐데 나는 knex를 사용했다. knex는 ORM으로써 DDL, DML 등의 쿼리를 질의할 때 사용하는데 이 라이브러리는 마이그레이션도 같이 관리해준다. 나는 마이그레이션을 관리하는 것만 사용했다.

 

https://knexjs.org/guide/

 

Installation | Knex.js

Installation Knex can be used as an SQL query builder in both Node.JS and the browser, limited to WebSQL's constraints (like the inability to drop tables or read schemas). Composing SQL queries in the browser for execution on the server is highly discourag

knexjs.org

설치에 대해서는 위 사이트를 참고하자.

 

npx knex init

프로젝트 최상단에 다음과 같은 쉘 명령어를 입력하자. 그럼 knexfile.js가 자동으로 생성된다. 이 파일은 knex의 config를 설정하는 것이다.

 

module.exports = {
  localhost: {
    client: 'mysql2',
    connection: {
      host: process.env.DB_LOCAL_HOST,
      database: process.env.DB_LOCAL_NAME,
      user: process.env.DB_LOCAL_USER,
      password: process.env.DB_LOCAL_PASSWORD
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      tableName: 'migrations_logs',
      directory: './migrations'
    }
  },

  main: {
    client: 'mysql2',
    connection: {
      host: process.env.DB_MAIN_HOST,
      database: process.env.DB_MAIN_NAME,
      user: process.env.DB_MAIN_USER,
      password: process.env.DB_MAIN_PASSWORD,
      port: process.env.DB_MAIN_PORT
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      tableName: 'migrations_logs',
      directory: './migrations'
    }
  }
};

예시로는 다음과 같다. 각각의 환경마다 마이그레이션 적용할 수 있다. 위에서는 localhost, main 두 가지 세팅 방향을 제시하고 있고 내부는 env를 통해 전역적으로 접근할 수 있게 설정했다. 

 

아래에 migrations 라고 하는 key 값에 해당하는 객체의 의미는 마이그레이션 관리에 대한 로그를 남기는 영역이다. tableName은 해당 호스트에 대한 데이터베이스 내에 생성되는 테이블의 이름이고 directory는 프로젝트 내에서 마이그레이션 로그를 읽는 부분이다.

 

이제 knex를 가지고 어떻게 하는지 진행해보자.

 

npx knex migrate:make '본인이 남길 파일 이름'

해당 쉘은 마이그레이션 파일을 생성한다. config 설정에서 본인이 지정했던 루트에 파일이 생성될 것이다. 예를 들면 npx knex migrate:make user 이런 식으로 하게 되면 OOOOOO_user.js 라는 마이그레이션 파일이 생성되게 된다.

 

/**
 * @param { import("knex").Knex } knex
 * @returns { Promise<void> }
 */
exports.up = async function(knex) {
	
}

/**
 * @param { import("knex").Knex } knex
 * @returns { Promise<void> }
 */
exports.down = function(knex) {

}

해당 파일로 이동해보면 다음과 같이 자동으로 코드가 생성되어있다. up과 down의 차이는 up은 실제로 테이블 스키마가 어떻게 변경되었지 또는 열이 추가되었는지에 대한 DDL, 또는 특정 로우 데이터가 추가되는 DML 등을 적으면 된다. down은 up을 통해 변경되는 테이블 내용을 어떻게 롤백할 것인지를 적으면 된다.

 

https://knexjs.org/guide/query-builder.html

 

Knex Query Builder | Knex.js

Knex Query Builder The heart of the library, the knex query builder is the interface used for building and executing standard SQL queries, such as select, insert, update, delete. Identifier Syntax In many places in APIs identifiers like table name or colum

knexjs.org

knex에서는 여러 queryBuilder들을 제공해준다. 이걸 보고 사용해도 되고 로우로 사용하고 싶으면 다음과 같이 작성하면 된다.

 

/**
 * @param { import("knex").Knex } knex
 * @returns { Promise<void> }
 */
exports.up = async function(knex) {
    await knex.raw(`
        적을 로우 쿼리
    `);
};

/**
 * @param { import("knex").Knex } knex
 * @returns { Promise<void> }
 */
exports.down = function(knex) {

};

로우 쿼리 작성 또한 지원해주고 있으니 편한 방법을 사용하면 될 것 같다.

 

npx knex migrate:latest --env localhost
npx knex migrate:latest --env main

config 설정 때 여러 환경에서 진행할 수 있도록 구성했는데 그 상황에 맞게 마이그레이션을 실행시키는 쉘 명령어이다. 

 

저걸 실행시켜보면 이런 테이블이 생기는데 이 테이블은 config에서도 설정했다. 이 테이블은 어떤 마이그레이션 실행했는지 관리하는 테이블이다. 위에서 사내에서 마이그레이션 로그는 서로 공유하고 있어야된다고 했는데 이 이유 때문이다. 어떤 마이그레이션이 실행됐는지 로그를 가지고 있어야 knex는 혼란스러워하지 않는다.

 

저 테이블에 마이그레이션 변경 내역이 존재하는데 내 기준에서는 해당 마이그레이션이 코드 상에서 없다면 프로젝트를 실행시킬 수 없다. 

 

migrations_logs 테이블에는 마이그레이션을 실행시켰는지 검증할 수 있다. 한 번 실행시킨 마이그레이션은 두 번 실행시키지 않는다.

 

이렇게 마이그레이션을 관리할 수 있고 지금은 가려놨지만 마이그레이션 파일을 생성할 때 어떤 테이블에 대한 내용인지 적으면 직관적으로 확인할 수 있어 타 개발자가 이를 보아도 이해할 수 있을 것이다.

'javascript > express' 카테고리의 다른 글

함수에서 변수를 명시하지 않았는데 할당됐다  (0) 2024.09.13
jest  (0) 2024.08.26