TypeORM でハマったところを書いておく

# ormconfig は .json ではなく .js または .ts にしたほうが便利

デフォルトだと `ormconfig.json` ファイルが生成されるけど、ファイルフォーマットは選べる。
https://typeorm.io/#/using-ormconfig/creating-a-new-connection-from-the-configuration-file

で、`ormconfig` にデータベースの接続情報を書くけど、直書きしたくはないので、`.js`としておくと
以下のように環境変数を読めるので、便利!

```js:ormconfig.js
module.exports = {
  'type': 'mysql',
  'host': process.env['MYSQL_HOST'] || 'localhost',
  'port': process.env['MYSQL_PORT'] || 3306,
  'username': process.env['MYSQL_USER'] || 'username',
  'password': process.env['MYSQL_PASSWORD'] || 'password',
  'database': process.env['MYSQL_DATABASE'] || 'database',
  ...
};

```

# synchronize オプションは false (デフォルト false なので設定しないでよい)

ドキュメントにある通り、`synchronize` オプションを `true` にすると、Entity の設定がデータベースに反映されちゃう。
Entity に[リレーション設定](https://typeorm.io/#/many-to-one-one-to-many-relations)をしてると、外部キーカラムが勝手に追加されたりする。
急に Migration に書いてない `userId` カラムが増えてて「は？」ってなった。
> Setting synchronize makes sure your entities will be synced with the database, every time you run the application.

# 命名規則が Laravel の Migration と違う

Laravel の Migration からインスピレーションを受けた的なことがライブラリの説明に書いてあった気がしまして、
勝手に命名規則は同じものを思ってたらそうじゃなかった。
例えば Laravel はテーブル名は複数形、Entity(EloquentModel) は単数形だけど、TypeORM そうなってない。
TypeORM の命名規則は DefaultNamingStrategy にあって継承することでカスタマイズは可能とのこと。

[参考1](https://zenn.dev/tatta/books/5096cb23126e64/viewer/3e8ebc)
[参考2](https://www.wakuwakubank.com/posts/730-typeorm-custom-naming/)
[参考3](https://qiita.com/techneconn/items/cd8b7c5a973771d46489)

**追記**
テーブル名を複数、Entity名を単数にする場合は、@Entity() の引数にテーブル名を渡せば良い。
カラム名をスネークケース、プロパティ名をキャメルケースにする場合は、@Column() の option の name プロパティにカラム名を指定してあげれば良いみたいです！

```ts
@Entity('hoges')
export class Hoge {

    @PrimaryGeneratedColumn()
    id!: number;

    @Column({type: 'varchar', name: 'column_name', nullable: false})
    columnName!: string;
}
```

# `isPrimary: true` だけだと auto increment じゃないっぽい

Migration でサンプル通り `id` カラムに `isPrimary: true` を指定したら当然 auto increment になると思ってたけど、そうじゃなかった。
`Field 'id' doesn't have a default value?` って言われる。
なので、`isGenerated: true` と `generationStrategy: 'increment'`を指定する。
[参考](https://bleepcoder.com/ja/typeorm/438871887/auto-incrementing-column-does-not-auto-increment)

```
import {MigrationInterface, QueryRunner, Table, TableIndex, TableColumn, TableForeignKey } from "typeorm";

export class QuestionRefactoringTIMESTAMP implements MigrationInterface {

    async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.createTable(new Table({
            name: "question",
            columns: [
                {
                    name: "id",
                    type: "int",
                    isPrimary: true,
                    isGenerated: true,
                    generationStrategy: 'increment'
                },
                {
                    name: "name",
                    type: "varchar",
                }
            ]
        }), true)

    }

    async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.dropTable("question");
    }

}
```

# docker-compose を使う場合、host 名はDBコンテナ名

TypeORM に直接関係ないけど。
https://qiita.com/kajirikajiri/items/c2b557d884689a2b851e

# nullable カラムの Entity プロパティ指定方法

https://qiita.com/maruware/items/08c9ad594e14e4ea1497

# Entity　から Migration を作るコマンドがおそらくある

たぶんある。先にマイグレーションを書いたのでちゃんと確認してない。

# Cannot use import statement outside a module

https://qiita.com/toki_k/items/dbbb77aa0d6ebd96139c

# EntityMetadataNotFound: No metadata for “Hoge” was found

テーブル名とEntity名があってない(命名規則に則ってない)とか、コンパイル後のファイルが指定箇所以外に残ってるとかでこのエラーは解消できた気がする。

# connection が生成できない

default がなんちゃらで connenction が生成できなかった。
`keepConnectionAlive` オプションを `true` 指定すれば良いとか見たけど。うまく行かなかった。
以下の実装で回避できた。

```
const connection = async (): Promise<Connection> => {
    try {
        return await getConnection();
    } catch (error) {
        return await createConnection();
    }
};

const connection = await connection();