Fullstack React GraphQL TypeScript Tutorial をやってみた #1 ~MikroORMのセットアップまで~

# はじめに
30代未経験からエンジニアを目指して勉強中のYNと申します。
この記事は`Ben Awad`さんの[Fullstack React GraphQL TypeScript Tutorial](https://youtu.be/I6ypD7qv3Z8)を初学者が進めていく、という内容です。
`Ben`さんの動画は本当に質が高く、とても学びが多いのですが、自分のような初学者は躓きが多く、なかなか前に進まなかったので、振り返りのメモとして書きます。

# 今回の対象
動画の下記内容までです。
0:00:00 [Intro](https://youtu.be/I6ypD7qv3Z8)
0:02:02 [Node/TypeScript Setup](https://youtu.be/I6ypD7qv3Z8?t=115)
0:11:29 [MikroORM Setup](https://youtu.be/I6ypD7qv3Z8?t=690)

#始める前に

### ローカルにコードをクローン
まずは[Benさんのレポジトリ](https://github.com/benawad/lireddit)を自分のgithubアカウントにFork。
そしてローカルにクローン。

```
git clone https://github.com/your-account-name/lireddit.git
```

### ブランチをコピー
動画の内容ごとに細かく[ブランチ](https://github.com/benawad/lireddit/tree/0_node-typescript-setup)を切ってくれています。ありがたや。
まずはブランチをローカルにコピーして、そのブランチに移ります。

```
git pull origin 1_mikroORM-setup:1_mikroORM-setup
git checkout 1_mikroORM-setup
```

# Typescriptのはじめかた
### `tsconfig.json`を作成
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=372)
ルートディレクトリで下記コマンドを実行してtsconfig.jsonを作成。コンパイルやデバックなどに関するtypescriptの設定ファイルを作成します。

```
npx tsconfig.json
```
 

### `tsc -w`と`nodemon dist/index.js`を同時に実行する
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=637)
`ts-node`でtsファイルを実行するよりも、`tsc`でtsファイルをコンパイルした後にjsファイルを実行した方が速いとのことです。

# MikroORMの設定
### データベースの作成
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=747)
この動画では PostgreSQLを使っています。ない人はインストールしましょう。
動画のように、`createdb database-name`コマンドでデータベースを作成できますが、下記SQLコマンドでもできます。

```
psql 
# ログイン

CREATE DATABASE database-name;
# データベース作成

\l
# データベースの一覧を表示

DROP DATABASE database-name;
# データベースの削除

\q
# 退出
```

### VScodeのオートコンプリートについて
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=796)
(自分のMac/JISキーボード環境では)`cmd + .` でオートコンプリートが使えます。

### mikro-ORMの全体像について
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=689)
ORMとはObject-relational mapperのことで、面倒なSQL文を用いることなく、TypeScriptのみでデータベースとデータのやりとりをすることができます。

```src/index.ts
const main = async () => {
  const orm = await MikroORM.init({
    dbname : 'lireddit',
    type : 'postgresql',
    entities : [Post]
  });
};

main()
```
上記のようにコードで`MikroORM`を初期化し、Postテーブルと情報をやりとりできるようになります。

![スクリーンショット 2020-11-10 13.48.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/819b1134-7710-d273-a62b-efba0b2587b3.png)


### Entityについて
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=1042)
Entityとはつまりテーブルのことです。
今回、TypeScriptのクラス構文とデコレータを使って下記テーブルのスキーマを定義します。
![スクリーンショット 2020-11-10 13.57.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/f0caf031-bc10-740f-5fe6-246dd6e5fcec.png)
([公式ドキュメント](https://mikro-orm.io/docs/decorators#entity-properties)はこちら)


```src/entities/Post.ts
import { Entity, PrimaryKey, Property } from "@mikro-orm/core";

@Entity() // クラスをテーブルスキーマに変換する
export class Post {
  @PrimaryKey() // idをプライマリキーのカラムとして定義する。SQLでインサートする際にはオートインクリメントしてくれる。
  id!: number // プライマリキーなので!をつける。nullを許さない。

  @Property({ type: "date" }) // createdAtをカラムとして定義する。SQLにDateという型はないので、date型を明示する。
  createdAt = new Date();

  @Property({ type: "date", onUpdate: () => new Date() }) // 同上。updateの度に新しい日付で上書きするhookを書き足す。
  updatedAt = new Date();

  @Property({ type: "text" }) // 同上。SQLにstringという型はないので、SQLではtext型を使うことを明示的に示す。
  title!: string;
}

```

まずもって最初に`@~~`とかいう見慣れない構文が唐突に出てきて困惑します。（しました。）
これがデコレータです。
デコレータはTypeScriptに導入された新しい構文で、近いうちにJavaScriptにも実装されるみたいです。
デコレータの機能を使うには、`tsconfig.json`に下記の設定を付け加える必要があります。

```tsconfig.json
{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,  
  },
}
```

`@Entity()`はクラスを修飾するクラスデコレータ、`@PrimaeryKey()`はプロパティを修飾するプロパティデコレータです。
このデコレータを使うことによって、TypeScriptのclassをSQLのスキーマに翻訳できる魔法のようなものと捉えればいいと思います。
実際にどうやって翻訳するかが気になるひとは[こちら](https://github.com/mikro-orm/mikro-orm/blob/master/packages/core/src/decorators/Entity.ts)に中身が書いてありますが、中身を意識せずありがたく使わせていただきましょう。
自分としては、

* クラスデコレータはクラスを引数として受け取って、編集したクラスを返す関数
* プロパティデコレータはプロパティを引数として受け取って、何かをする関数
* デコレータを作るためには、決まった引数と決まったやり方がある

ぐらいを抑えておけば十分かなと思いました。
(自分は[Udemy](https://www.udemy.com/share/102AoGBUoSdFhQQX4=/)でデコレータについて勉強しましたが、デコレータを「使う」分には「便利だな」ぐらいに捉えておけばよいと感じました。)

### Postテーブルを作成する
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=1397)

#### 1) `mikro-orm.config.ts`を作成
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=1486)

```src/mikro-orm.config.ts
export default {
  ...
} as Parameters<typeof MikroORM.init>[0];
```

ここでの一番の学びは、最後の`as Parameters<typeof MikroORM.init>[0]`です。
`Parameters<>`を付け加えることで、オブジェクトからMikroORMの初期化に関する引数以外を排除することができます。

#### 2) migrationの設定
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=1720)

`migration`プロパティに、テーブルを作成するためのmigrationファイルを保存/実行する場所を設定します。

```src/mikro-orm.config.ts
export default {
  migrations: {
    path: path.join(__dirname, "./migrations"),
    pattern: /^[\w-]+\d+\.[tj]s$/,
  },
  ...
} as Parameters<typeof MikroORM.init>[0];

```
#### 3) migrationファイルの作成
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=1914)
`mikro-orm.config.ts`に記載されたmigrationファイルを実行します。

```
npx mikro-orm migration:create
```
これにより、`Entity`プロパティに記載されているテーブルでまだ作成されていないものを自動的に検知し、（今回はPostテーブル）、`Post.ts`に記述されたスキーマに従ってテーブルを作成します。

#### 4) migrationファイルの実行
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=2042)

```src/index.ts
const main = async () => {
  const orm = await MikroORM.init(microConfig);
  await orm.getMigrator().up(); // 先ほど作成したmigrationファイルを実行する
};

main()
```
ちなみに、`orm.getMigrator().up()`の部分で、一度実行されたmigrationファイルは裏で履歴をカウントされており、`main()`が再度実行されても、同じmigrationが再度実行されることはありません。[動画のここ](https://youtu.be/I6ypD7qv3Z8?t=4492)にて言及されています。

### Postテーブルにデータをinsertする
[動画のこの部分です](https://youtu.be/I6ypD7qv3Z8?t=2264)

```src/index.ts
const main = async () => {
  const orm = await MikroORM.init(microConfig);
  const post = orm.em.create(Post, { title: "my first post" }); 
  // SQLのcreate tableとinsertを実行する。Postテーブルのスキーマに記載の通り、入力が必要なカラムはtitleだけであることに注意。
  // https://mikro-orm.io/docs/entity-manager-api#createentityname-entitynamet-data-entitydatat-newt-p
  await orm.em.persistAndFlush(post);
  const posts = await orm.em.find(Post, {});
  // 空オブジェクトを第二引数とすると、テーブル内のすべての行が帰ってくる
};

main()
```
`persistAndFlush`の使い方は[こちら](https://mikro-orm.io/docs/entity-manager)を参照。
Mikro-ORMによるSQL文の実行については[こちら](https://mikro-orm.io/docs/repositories-api)を参照。
# 最後に
今回は`MikroORM`の設定まで書きました。
チュートリアル全14時間のうち、40分ぐらい進みました。
先は長い。。。

次回=>https://qiita.com/theFirstPenguin/items/5ce4ca5b424b4fb4d9ef