typeormの設定をormconfig.tsから読み込む

2021/11/07に公開

概要

typeorm の設定ファイルはデフォルトで、ormcofig.json ですが、このままだと以下の問題点があると考えます。

  • 環境変数を埋め込みづらい
  • プロジェクトのルートディレクトリにファイルが増える
  • 自動で読み込まれるのでデバッグしづらい

環境変数を読み込むには ts ファイルの方が楽ですし、ほかの config とまとめることができるので、ormconfig.ts から読み込む方法を記述します。

環境構築の方法は、以下の記事を参考にしていただきたいです(Node.js 14.17.0 をインストールまで)。

https://zenn.dev/msksgm/articles/20211106-anyenv-nodenv

完成したソースコードは以下です。

https://github.com/Msksgm/typeorm_ormcofig.ts_example

環境構築

typeorm init

ディレクトリを作成します。

mkdir typeorm_ormcofig.ts_example
cd typeorm_ormcofig.ts_example

typerom initで typeorm の構成を自動生成できます。
typerom を使う時に必須ではないですが、簡略化のため使用しました。
DB は MySQL を使用しました。

npx typeorm init --database mysql

生成されるファイル構成は以下(node_modules は除外して表示)になります。

tree -I node_modules
.
├── README.md
├── ormconfig.json
├── package-lock.json
├── package.json
├── src
│   ├── entity
│   │   └── User.ts
│   ├── index.ts
│   └── migration
└── tsconfig.json

3 directories, 7 files

MySQL サーバ をコンテナで作成

docker compose

Docker で、MySQL サーバを作成します。

プロジェクトのルートディレクトリにdocker-compose.yml を作成します。

./docker-compose.yml
version: "3.5"
services:
  db:
    image: mysql:5.7.34
    container_name: mysql-container
    environment:
      MYSQL_DATABASE: "typeorm_db"
      MYSQL_ROOT_PASSWORD: "password"
    restart: "always"
    ports:
      - "3306:3306"

MySQL へ接続を確認

コンテナを起動。

docker compose up -d

接続確認。パスワードはdocker-compose.ymlに記述したpasswordtypeorm_dbになります。
ログインできたら成功です。

mysql -u root --port 3306 -h 127.0.0.1 -D typeorm_db -p

.env ファイルを作成

プロジェクトのルートディレクトリに.envファイルを作成します。

.env

./.env
# DB
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=password
DB_DATABASE=typeorm_db

.env ファイルを.gitignore に追加します。

./.gitignore
.idea/
.vscode/
node_modules/
build/
tmp/
temp/
# 追加
.env

以下のコマンドで読み込む。

export $(cat .env | grep -v ^# | xargs)

実装

ormconfig.ts を作成

src/configディレクトリを作成し、src/config/ormconfig.tsファイルを作成します。

記述内容は以下になります。

./src/config/ormconfig.ts
/** 全て追加 **/
import { ConnectionOptions } from "typeorm";

const ormconfig: ConnectionOptions = {
  type: "mysql",
  host: process.env.DB_HOST,
  port: parseInt(process.env.DB_PORT, 10),
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_DATABASE,
  synchronize: true,
  logging: false,
  entities: ["src/entity/**/*.ts"],
  migrations: ["src/migration/**/*.ts"],
  subscribers: ["src/subscriber/**/*.ts"],
  cli: {
    entitiesDir: "src/entity",
    migrationsDir: "src/migration",
    subscribersDir: "src/subscriber",
  },
};

export default ormconfig;

ormconfig.jsonは不要になったので削除します。

rm ormconfig.json

ormconfig.ts を読み込む

src/index.tsを以下のように修正します。

./src/index.ts
import "reflect-metadata";
import { createConnection } from "typeorm";
import { User } from "./entity/User";
import connectionOption from "./config/ormconfig"; // 追加

createConnection(connectionOption) // 修正
  .then(async (connection) => {
    console.log("Inserting a new user into the database...");
    const user = new User();
    user.firstName = "Timber";
    user.lastName = "Saw";
    user.age = 25;
    await connection.manager.save(user);
    console.log("Saved a new user with id: " + user.id);

    console.log("Loading users from the database...");
    const users = await connection.manager.find(User);
    console.log("Loaded users: ", users);

    console.log("Here you can setup and run express/koa/any other framework.");
  })
  .catch((error) => console.log(error));

動作確認

MySQL でデータベースにはテーブルが存在しないことを確認

以下のコマンドで何も表示されないことを確認します。

mysql -u root --port 3306 -h 127.0.0.1 -D typeorm_db -e 'SHOW TABLES;' -p

migration ファイルを生成

migration:generateで migration ファイルが生成されます。
-f で ormconfig.ts へのパスを書くのがポイントです。デフォルトではルートにある ormconfig.json を取得しようとします。

npx ts-node ./node_modules/.bin/typeorm migration:generate -n user -f ./src/config/ormconfig.ts

以下のような表示がされたら成功です。

Migration /PATH/TO/typeorm_ormcofig.ts_example/src/migration/1623800662217-user.ts has been generated successfully.

migration 実行

migration:runで migration を実行できます。
以下のコマンドで typeorm_db データベースに user テーブルが追加されます。

npx ts-node ./node_modules/.bin/typeorm migration:run -f ./src/config/ormconfig.ts
query: SELECT * FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = 'typeorm_db' AND `TABLE_NAME` = 'migrations'
query: CREATE TABLE `typeorm_db`.`migrations` (`id` int NOT NULL AUTO_INCREMENT, `timestamp` bigint NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB
query: SELECT * FROM `typeorm_db`.`migrations` `migrations` ORDER BY `id` DESC
0 migrations are already loaded in the database.
1 migrations were found in the source code.
1 migrations are new migrations that needs to be executed.
query: START TRANSACTION
query: CREATE TABLE `user` (`id` int NOT NULL AUTO_INCREMENT, `firstName` varchar(255) NOT NULL, `lastName` varchar(255) NOT NULL, `age` int NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB
query: INSERT INTO `typeorm_db`.`migrations`(`timestamp`, `name`) VALUES (?, ?) -- PARAMETERS: [1623800662217,"user1623800662217"]
Migration user1623800662217 has been executed successfully.
query: COMMIT

MySQL でテーブルを確認

さきほどと同じコマンドを実行して、テーブルが追加されていることを確認します。

mysql -u root --port 3306 -h 127.0.0.1 -D typeorm_db -e 'show tables;' -p
+----------------------+
| Tables_in_typeorm_db |
+----------------------+
| migrations           |
| user                 |
+----------------------+

また、以下のコマンドで user テーブルにはカラムが存在しないことを確認できます。
実行してもなにも表示されません。

mysql -u root --port 3306 -h 127.0.0.1 -D typeorm_db -e 'SELECT * FROM user;' -p

user テーブルにカラムを追加。

typeorm initでは、src/index.ts上でデータベースにカラムを追加する処理が含まれているので実行します、
実行後、ctrl + cで停止しても大丈夫です。

ts-node ./src/index.ts

出力。

Inserting a new user into the database...
Saved a new user with id: 1
Loading users from the database...
Loaded users:  [ User { id: 1, firstName: 'Timber', lastName: 'Saw', age: 25 } ]
Here you can setup and run express/koa/any other framework.

MySQL でカラムを確認

先ほどと同様にカラムを確認します。
カラム追加されたことがわかります。

mysql -u root --port 3306 -h 127.0.0.1 -D typeorm_db -e 'SELECT * FROM user;' -p

出力。

+----+-----------+----------+-----+
| id | firstName | lastName | age |
+----+-----------+----------+-----+
|  1 | Timber    | Saw      |  25 |
+----+-----------+----------+-----+

その他

typeorm の設定ファイルを ormconfig.json から、ormconfig.ts に変更する方法と動作確認について執筆しました。
一般的に使われる手法がどちらなのかはわからないので、設計を考えるときや一緒に作業する人と相談などして決めましょう。
また今回は、src/config/ormconfig.tsにまとめましたが、src/config/index.tsを作成して、ほかの設定とまとめても良いと思いました。

備考

DB 関連

MySQL に接続するコマンドを実行すると、エラーがでる

以下のエラーの場合、DB サーバが起動できていないです。もう少し待ったら動くようになります。

ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0

DB を永続化したい。

volume の設定を追加します。
以下は、一例です。

./docker-compose.yml
version: "3.5"
services:
  db:
    image: mysql:5.7.34
    container_name: mysql-container
    environment:
      MYSQL_DATABASE: "typeorm_db"
      MYSQL_ROOT_PASSWORD: "password"
    restart: "always"
    ports:
      - "3306:3306"
    volumes:
      - ./.data/db:/var/lib/mysql

DB に接続するときに、127.0.0.1を指定するのか

何も指定しないと、localhost:3306に接続されてしまう現象を確認しています。自分も詳細は理解していませんが、
以下の記事が参考になりました。
https://qiita.com/saken649/items/00e752d89f2a6c5a82f6#127001にしないといけない理由推測

TypeScript 関連

"mysql"の箇所も環境変数にしたい。

以下の箇所ですが、型チェックで怒られて対処できていないです。
as なんとかによって解決できそうですが、どなたか教えていただきたいです。

./src/config/ormconfig.ts
/** 全て追加 **/
import { ConnectionOptions } from "typeorm";

const ormconfig: ConnectionOptions = {
  type: "mysql",
  host: process.env.DB_HOST,
  port: parseInt(process.env.DB_PORT, 10),
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_DATABASE,
  synchronize: true,
  logging: false,
  entities: ["src/entity/**/*.ts"],
  migrations: ["src/migration/**/*.ts"],
  subscribers: ["src/subscriber/**/*.ts"],
  cli: {
    entitiesDir: "src/entity",
    migrationsDir: "src/migration",
    subscribersDir: "src/subscriber",
  },
};

export default ormconfig;

Discussion