Typeormの設定のメモ

## 目的

- typeorm（ActiveRecord）の使い方を学ぶ

## ゴール

- userテーブルを作る
- CRUDができることを確認する

## 準備
Typescriptとexpress.jsの環境設定についてはこちらにまとめています。
↓↓↓
https://qiita.com/cedrictarou/items/24f9dbc1391193bae24b

## 手順

### DB(MySQL)を用意する

今回はdocker-composeを使ってDBを用意する

*docker-composeについての解説

[【連載】世界一わかりみが深いコンテナ & Docker入門 〜 その4:docker-composeってなに？ 〜 | SIOS Tech. Lab](https://tech-lab.sios.jp/archives/20051)

`docker-compose.yml`ファイルをワーキングディレクトリー直下に作る

`docker-compose.yml`ファイルに以下の内容をペーストする

```yaml
version: '3'

services:
  db:
    image: mysql:8.0.25
    restart: always
    ports:
      - '3307:3306' #←使われていないポート番号を指定してください。
    volumes:
      - mydb:/var/lib/mysql
    networks:
      - app_network
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_USER: test
      MYSQL_PASSWORD: test
      TZ: 'Asia/Tokyo'

volumes:
  mydb:
```

*今回は最低限の設定にしています。

Docker-composeを立ち上げる

```bash
//docker-compose がある階層でターミナルにコマンドを打つ
$ docker-compose up
```

DBと接続できるかを確認する

```bash
//docker内に入いる
$ docker-compose exec db
docker内でmysqlを立ち上げる ユーザー名はroot パスワードはrootとしている(docker-compose.yml ないで設定している)
$ mysql -u root -p
// パスワードを入力　ここではroot
// 成功するとmysqlが立ち上がる
```

### typeormをインストールする

基本的には公式サイトを参考に必要なものをインストール、設定していく。

```bash
$ npm install typeorm --save

$ npm install reflect-metadata --save

$ npm install mysql2 --save
```

`ormconfig.json` をワーキングディレクトリ直下に作成する

```json
{
  "type": "mysql", // 今回はmysql
  "host": "localhost", 
  "port": 3307, //docker-composeで指定したもの
  "username": "root", //docker-composeで指定したもの
  "password": "root", //docker-composeで指定したもの
  "database": "test", //docker-composeで指定したもの
  "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"
  }
}
```

`typeorm init` コマンドで作られた `ormconfig.json` のtype, host, portなどを設定する

### User entityを作成する
entitiy = model の認識で大丈夫かと

`entity`フォルダーを作成しその中に `User.ts`ファイルを作成する

```tsx
import { BaseEntity, Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from "typeorm";

@Entity()
export class User extends BaseEntity {
  @PrimaryGeneratedColumn()
  readonly id?: number;

  @Column({ type: 'varchar' })
  name: string;

  @Column({ type: 'varchar' })
  email: string;

  @CreateDateColumn()
  readonly createdAt?: Date;

  @UpdateDateColumn()
  readonly updatedAt?: Date;

  // コンストラクタで初期化
  constructor(name: string, email: string) {
    super();
    this.name = name;
    this.email = email;
  }
}
```

*コンストラクタで初期化についてしたの記事を参考にしました。

[TypeORMでエンティティを定義する際のガイドライン](https://tech.bitbank.cc/typeorm-entity-guideline/)

### `index.ts`にユーザーのCRUDを記述する。

```tsx
import express, { Request, Response, NextFunction } from 'express'
// import todoRoutes from './routes/todos'
import "reflect-metadata";
import { createConnection } from "typeorm";
import { User } from './entity/User'
// create typeorm connection
createConnection()
  .then(() => {

    // create and setup express app
    const app = express()
    app.use(express.json());

    // register routes
    // app.use('/todos', todoRoutes)

    // ユーザー詳細
    app.get("/users/:id", async (req: Request, res: Response) => {
      const results = await User.findOneOrFail(req.params.id);
      return res.json(results);
    });
    // 全ユーザーを表示
    app.get("/users", async (req: Request, res: Response) => {
      const results = await User.find();
      return res.json(results);
    });
    // ユーザーを登録
    app.post("/users", async (req: Request, res: Response) => {
      const user = await User.create(req.body);
      const results = await User.save(user);
      return res.json(results);
    });
    // ユーザー情報を更新
    app.put("/users/:id", async (req: Request, res: Response) => {
      // User.findOne()を使用するとエラーになるのでFindOneOrFailを使用
      const user = await User.findOneOrFail(req.params.id);
      User.merge(user, req.body);
      const results = await User.save(user);
      return res.json(results);
    });
    // ユーザーを削除
    app.delete("/users/:id", async (req: Request, res: Response) => {
      await User.delete(req.params.id);
      const message = "The user is deleted!!"
      return res.json(message);
    });

    app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
      res.status(500).json({ message: err.message })
    })

    // start express server
    app.listen(3000, () => console.log('Server up at http://localhost:3000'))
  }).catch(error => console.log(error));
```

*todoのルートは今は使用しないのでコメントアウトしています。

typeormがちゃんと動作してuserテーブルができているか確認する

```bash
// エラーなく動けばOKI
$ npm start

[nodemon] restarting due to changes...
[nodemon] starting `ts-node src/index.ts`
Server up at http://localhost:3000
```

*ユーザーを登録するにはpostメソッドを使う必要がります。お好きな方法で試して見てください。

*今回はpostmanを使用しました。

[Postman API Platform | Sign Up for Free](https://www.postman.com/)

## 参考

[TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.](https://typeorm.io/#/)

[TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.](https://typeorm.io/#/example-with-express)

[typeORM + Express で NodeJS バックエンドするメモ - Qiita](https://qiita.com/natsuhiko/items/4fa64d6fb78e2ef62fd7)