TypeORMで定義したエンティティをER図に出力してみた

2021.07.16

TypeORM で定義したエンティティのリレーションを確認するのにER図を出力できないだろうか?と探してみると、Extensionで ER Diagram generator - typeorm-uml というのを見つけたので、実際にER図を出力してみました。

環境

今回は以下の環境で試してみました。

  • node: v14.17.1
  • TypeScript: 4.3.5
  • TypeORM: 0.2.34
  • typeorm-uml: 0.2.34

環境構築

まずは必要なパッケージをインストールしていきます。

npm install typeorm reflect-metadata pg --save
npm install typescript ts-node @types/node prettier typeorm-uml --save-dev

TypeORM のエンティティが実際のデータベースにどのように作成されるか確認するため PostgreSQL を Docker で起動するための設定もしておきます。

docker-compose.yml

version: "3.9"

services:
  db:
    image: postgres:13.3
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=test
      - POSTGRES_PASSWORD=test
      - POSTGRES_DB=test
    ports:
      - "5432:5432"

volumes:
  db-data:

TypeORMのエンティティを作成

環境構築が終わったので、エンティティを定義していきます。今回は、公式ドキュメントのガイドに沿って、Photo, PhotoMetadata, Author, Album エンティティを以下のように作成しました。

src/entity/Photo.ts

import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  OneToOne,
  ManyToOne,
  ManyToMany,
} from "typeorm";
import { PhotoMetadata } from "./PhotoMetadata";
import { Author } from "./Author";
import { Album } from "./Album";

@Entity()
export class Photo {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column({
    length: 100,
  })
  name!: string;

  @Column("text")
  description!: string;

  @Column()
  filename!: string;

  @Column("int")
  views!: number;

  @Column()
  isPublished!: boolean;

  @OneToOne((type) => PhotoMetadata, (photoMetadata) => photoMetadata.photo)
  metadata!: PhotoMetadata;

  @ManyToOne((type) => Author, (author) => author.photos)
  author!: Author;

  @ManyToMany((type) => Album, (album) => album.photos)
  albums!: Album[];
}

src/entity/PhotoMetadata.ts

import {
  Column,
  Entity,
  JoinColumn,
  OneToOne,
  PrimaryGeneratedColumn,
} from "typeorm";
import { Photo } from "./Photo";

@Entity()
export class PhotoMetadata {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column("int")
  height!: number;

  @Column("int")
  width!: number;

  @Column()
  orientation!: string;

  @Column()
  compressed!: boolean;

  @Column()
  comment!: string;

  @OneToOne((type) => Photo, (photo) => photo.metadata)
  @JoinColumn()
  photo!: Photo;
}

src/entity/Author.ts

import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from "typeorm";
import { Photo } from "./Photo";

@Entity()
export class Author {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column()
  name!: string;

  @OneToMany((type) => Photo, (photo) => photo.author)
  photos!: Photo[];
}

src/entity/Album.ts

import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  ManyToMany,
  JoinTable,
} from "typeorm";
import { Photo } from "./Photo";

@Entity()
export class Album {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column()
  name!: string;

  @ManyToMany((type) => Photo, (photo) => photo.albums)
  @JoinTable()
  photos!: Photo[];
}

テーブルを作成

作成したエンティティからデータベースにテーブルを作成してみました。コネクション情報を設定し( synchronize 設定を true )、createConnection を実行することで実際にテーブルを作成してみます。

src/index.ts

import "reflect-metadata";
import { createConnection } from "typeorm";

createConnection()
  .then(async (connection) => {
    console.log("createConnection success.");
  })
  .catch((error) => console.log(error));
docker compose up
npx ts-node src/index

テーブルが作成できたか確認してみます。

SELECT tablename FROM pg_tables WHERE schemaname = 'public' ;
photo
photo_metadata
author
album
album_photos_photo

意図したテーブルが作成されていました。

ER図を出力

ここまで準備できると簡単にER図を出力することができます。 ER図の出力は以下のコマンドを実行すると、実行したディレクトリ(プロジェクトのルートディレクトリ)に、er-diagram.png というファイルが出来上がります。

npx typeorm-uml --download=er-diagram.png

--download=[ファイル名] オプションを指定することで、生成した画像をダウンロードすることができます。オプションを指定しなかった場合は、PlantUMLで生成された画像へのリンクURLが出力されます。

その他、出力するER図のカラーを変更したり、出力対象を設定したりカスタマイズするためのオプションが用意されているので、詳しくはこちらを確認してみてください。

さいごに

比較的簡単にER図を出力することができました。手動でメンテナンスするとどうしても実装との乖離が発生して、これあってるの?となることがありますが、実装をベースに生成できると実装との乖離を少なくできて便利だと思います。CIなどに組み込んで自動で定期的に更新すると、いつも最新のER図を確認することができてより良さそうですね。

今回サンプルで作成したソース一式は以下に配置してありますので、興味を持たれた方は実際に動かしてみてください。

ore88ore/type-orm-uml-sample

参考