【TypeORM】tsファイルにて定義した接続環境と、テーブル定義を表現したEntityファイルにもとづいたマイグレーションファイル自動生成を行う



https://qiita.com/kss_nm/items/d971eb2e64e7dcc94814

https://qiita.com/kss_nm/items/5e258e182f8458aae376

上記の続編。上記ではsyncronizeによるテーブル自動生成を行っていた。
今回は上記Entityファイルおよび接続設定によるマイグレーションファイル自動作成を行う。

# 前提

https://typeorm.io/#/

上記のTypeORMを導入していること。本記事にて用いているバージョンは以下。

```
    "mysql2": "^2.3.0",
    "typeorm": "^0.2.37",

    "@types/node": "^16.7.10",
```

# 参考記事

https://qiita.com/techneconn/items/0655f4d88187b65a8520

書き始めようとしたら見つけた先駆者様。より全体的な実装例を書いてくださっている。

https://stackoverflow.com/questions/52187328/how-to-specify-ormconfig-ts-for-typeorm

`--config` なるオプションがあり、そこからconfigファイルを指定できるらしい。

# 躓いたところ＋解決法

## 躓いたところ：ormconfig.jsonじゃないファイルを個別に指定してできないの？

## →できた。migrateコマンドにconfigファイルを指定するオプションがあるのでソレを指定する。

### 実際にやってみる

### package.json

```json
  "scripts": {
    "migrate:generate:training": "ts-node ./node_modules/typeorm/cli.js migration:generate  --config ./server/typeorm/togoconfig.ts -n",
    "migrate:up:training": "ts-node ./node_modules/typeorm/cli.js migration:run  --config ./server/typeorm/togoconfig.ts",
    "migrate:down:training": "ts-node ./node_modules/typeorm/cli.js migration:revert  --config ./server/typeorm/togoconfig.ts"
  }

```

`migrate:generate`部分の末尾にはファイル名オプションの`-n`を付けてあるので、
`yarn migrate:generate:training filename`のようなイメージでマイグレーションファイルを自動生成できる。
この`"migrate:generate:training"`部分はコマンドのエイリアス（別名）に過ぎないので、お好みでいいと思う。


### ガチャガチャ組み込んだ接続設定、server/typeorm/togoconfig.ts

```ts
import connectConfig from './index'

export = connectConfig.tougouConfig
```

### 上記ファイルの親玉、server/typeorm/index.ts（一部）

各設定などは公式ページなどを参照。

```ts

import dotenv from 'dotenv'
import { ConnectionOptions } from "typeorm";
import { Log4jsLogger } from "./common/logger"

// nuxt.js v14.12なので.envを有効活用している。
// 接続設定を環境変数process.env.～にすることで他環境へも適用できるようにする。
dotenv.config({ path: __dirname + '/.env' });

// https://typeorm.io/#/connection-options
const tougouConfig: ConnectionOptions = {
    type: "mysql",
    host: process.env.CONNECT_HOST,
    port: Number(process.env.CONNECT_PORT),
    username: process.env.CONNECT_USER,
    password: process.env.CONNECT_PASS,
    database: process.env.CONNECT_DATABASE,
    // 指定したフォルダ内の@Entityを認識してくれる。
    // Nuxt.jsのservermiddlewareにて動かしてる扱いなので以下のようなフォルダ階層としている。
    entities: [
        "server/typeorm/models/*.*"
    ],
    // migrate時に確認するファイル。
    migrations: [
        "migration/tougou/*.ts"
    ],
    // cli起動時に生成するmigrationファイルのフォルダ位置
    cli: {
        migrationsDir: 'migration/tougou',
    },
    // synchronize: trueの時、上記entityを正としてスキーマに接続、同期させる。
    // デバッグや開発時に役立つ。

    // 公式ドキュメントに書いてあるが、本番環境では絶対にfalseにしておくこと。
    synchronize: false,
    logging: true,
    // https://typeorm.io/#/logging
    // カスタムしてるので割愛。
    // Visual Code Studio + typescriptのクイックフィックスで編集必要なメソッドはわかる。
    logger: new Log4jsLogger(),
    timezone: "+09:00"
}

export default {
    tougouConfig: tougouConfig
}
```

上記exportによって複数の接続設定がtsファイルによって可能。その中から一つを選んでCLI利用migrationをするという選択肢を取ることができる。


## 躓いたところ：バージョン管理としてEntityを保存・更新してmigrate:generateしたら変更した箇所のデータが消える
## →列定義変更箇所は、MODIFYで済む変更もDROP＋ADDを行ってしまっている。仕方がないのでヒトの手で直す


### 変更例

#### 列のlengthを変更する

```ts
  @Column({ nullable: false, type: "varchar", length: 12, comment: "グループコードID" })
  codeGroupId!: string;
```

to

```ts
  @Column({ nullable: false, type: "varchar", length: 24, comment: "グループコードID" })
  codeGroupId!: string;
```

### できあがったマイグレーションファイル一部

```ts
    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE \`nuxt_typescript_training\`.\`m_code\` DROP COLUMN \`codeGroupId\``);
        await queryRunner.query(`ALTER TABLE \`nuxt_typescript_training\`.\`m_code\` ADD \`codeGroupId\` varchar(24) NOT NULL COMMENT 'グループコードID'`);

```

DROP COLUMN＋ADD をしている。
これだとアップデート・ダウングレード時にカラムデータが抜けてしまう…。
仕方がないのでヒトの手で直す。

```ts
        // await queryRunner.query(`ALTER TABLE \`nuxt_typescript_training\`.\`m_code\` DROP COLUMN \`codeGroupId\``);
        // await queryRunner.query(`ALTER TABLE \`nuxt_typescript_training\`.\`m_code\` ADD \`codeGroupId\` varchar(24) NOT NULL COMMENT 'グループコードID'`);
        await queryRunner.query(`ALTER TABLE \`nuxt_typescript_training\`.\`m_code\` MODIFY \`codeGroupId\` varchar(24) NOT NULL COMMENT 'グループコードID'`);
```

マイグレーションファイルのdown側も同じなので、同じく書き直す。
もっと良い方法があればいいなと思っている。