DBMLを使ってみた

DBML

DSLの一つであり、シンプルで可読性の良いDBML(Database Markup Language)を使ってみました。

Home | DBML
Open source

モデル設計を容易にする目的で作られている為、AIエージェントに与える指示や、プロジェクトメンバー間で共有するモデリングの共通言語として使えそうです。

ER図はDBMLを基に dbdiagram.io で生成させれば良いかもしれません。

DBMLとは

DBML(Database Markup Language)は、データベースのスキーマと構造を定義および文書化するために設計されたオープンソースのDSLです。シンプルで一貫性があり、非常に読みやすいように設計されています。

また、DBMLとSQL間の変換を支援するコマンドラインツールとオープンソースモジュールも付属しています。

Intro | DBML

コマンドラインツールで対応しているDBMSは次の通りです。

  • DBML⇒SQL変換: mysql / postgres / mssql / oracle
  • SQL⇒DBML変換: mysql / postgres / mssql / snowflake
  • DB⇒DBML変換: mysql / postgres / mssql / snowflake / bigquery

▼DBMLの例

Table users {
  id integer
  username varchar
  role varchar
  created_at timestamp
}

Table posts {
  id integer [primary key]
  title varchar
  body text [note: 'Content of the post']
  user_id integer
  status post_status
  created_at timestamp
}

Enum post_status {
  draft
  published
  private [note: 'visible via URL only']
}

dbdiagram.io のサービスを利用して、DBMLからER図を作成したサンプルが次のリンクで閲覧できます。

dbdiagram.io - Database Relationship Diagrams Design Tool
Quick and simple free tool to help you draw your database relationship diagrams and flow quickly using simple DSL langua...

導入のメリット

メリット
DBMLは、大規模で複雑なソフトウェアプロジェクトに取り組む開発者の悩みを解決するために生まれました。

  • プロジェクト全体のデータベース構造の全体像を把握するのが難しい。
  • テーブルとそのフィールドの意味、そしてそれらがどの機能と関連しているかを理解するのが難しい。
  • 既存のER図やSQL DDLコードは、記述が不十分で読みにくい(そして多くの場合、古くなっている)

推奨されるベストプラクティスは、ルートリポジトリにdatabase.dbmlファイルを置くことです(他の設定ファイルや定型ファイル(packages.jsonやREADME.mdなど)と同様に)。

Benefits | DBML

これからやることの概要

  • 環境構築
  • DBML CLIインストール
  • DBMLを作ってみる
  • DBMLからMySQL用のSQL生成⇒テーブル生成
  • MySQLの既存DBからDBML出力
  • DBMLからERD生成

前提条件

  • Ubuntu24.04.2 LTS (WSL2 on Windows11)を使っています
  • dockerを使います
  • npmを使います
  • MySQLを使っています

環境構築

▼構築するコンテナ

  • 作業用コンテナ: Amazon Linux 2023, Node.js, DBML CLI
  • DBコンテナ: MySQL

▼フォルダ構成

[プロジェクト]
 ├─ bin/ ・・・コンテナ操作用コマンド
 ├─ docker/ ・・・Dockerコンテナ構築用
 ├─ html/ ・・・作業場所
 └─ docker-compose.yml

▼手っ取り早く次のリポジトリをクローンしていじります

GitHub - macocci7/docker-la12-al2023-minio: Skelton of docker environment with Laravel12, Amazon Linux 2023 and MinIO
Skelton of docker environment with Laravel12, Amazon Linux 2023 and MinIO - macocci7/docker-la12-al2023-minio

ローカルに「using-dbml」とでもしてクローンします。

git clone https://github.com/macocci7/docker-la12-al2023-minio using-dbml

プロジェクトフォルダに入って「.git」を削除します。

cd using-dbml
rm -rf .git

▼docker-compose.yml を編集

※「al2023」の「depends_on」から「mailpit」と「minio」を削除

※「services」から「mailpit」と「minio」を削除

services:
  al2023:
    build:
      context: ./docker/al2023
      dockerfile: Dockerfile
    privileged: true
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./docker/al2023/bin:/root/bin
      - ./html:/var/www/html
    networks:
      - skynet
    depends_on:
      - mysql
  mysql:
    build:
      context: ./docker/mysql
      dockerfile: Dockerfile
    volumes:
      - ./docker/mysql/data:/var/lib/mysql
      - ./docker/mysql/bin:/root/bin
      - ./dump:/root/dump
    ports:
        - '3306:3306'
    environment:
        - MYSQL_ROOT_PASSWORD=pass
    networks:
      - skynet
networks:
  skynet:
    driver: bridge

▼「docker/al2023/Dockerfile」を編集

※基本的なパッケージとnode.jsインストール以外はほぼ削除

ARG amazonlinux_version="2023.7.20250512.0"

FROM amazonlinux:${amazonlinux_version}

RUN dnf update \
    && dnf install \
    systemd \
    systemd-devel \
    tar \
    zip \
    unzip \
    sudo \
    yum \
    procps-ng \
    net-tools \
    which \
    vim \
    git \
    -y

# create user
RUN useradd "ec2-user" && echo "ec2-user ALL=NOPASSWD: ALL" >> /etc/sudoers

# install nodejs
WORKDIR /root
RUN curl -fsSL https://rpm.nodesource.com/setup_22.x -o nodesource_setup.sh \
    && bash nodesource_setup.sh \
    && dnf install nodejs -y \
    && node -v


# install mysql client
RUN dnf install -y mariadb105

COPY ./systemd/systemd-networkd-wait-online.service /usr/lib/systemd/system/

WORKDIR /var/www/html

# starting process
CMD ["/sbin/init"]

EXPOSE 80
EXPOSE 443

▼作業用フォルダ作成

mkdir html

▼コンテナ構築&起動

docker compose up -d

DBML CLIインストール

作業用コンテナにroot権限で接続します。

bin/al-root

npmでグローバルインストールします。(Yarn / pnpmも可

npm install -g @dbml/cli

これによって使用できるコマンドは次の3つです。

  • dbml2sql ・・・DBMLからSQLへ変換
  • sql2dbml ・・・SQLからDBMLへ変換
  • db2dbml ・・・DBMSからDBML出力

一旦、exitします。

exit

※説明のためにステップを分けましたが、DBML CLIのインストールまでを「Dockerfile」に記述してもかまいません。

まずはDBMLを作ってみよう

DBMLの構文については別記事にしてあります。

▼「html/sample.dbml」を新規作成

※DBMSの互換性を考慮すると、「serial」よりも「”bigint unsigned” [pk, not null, increment]」とする方が良いでしょう。

Project using_dbml {
    database_type: 'MySQL'
    Note: 'DBMLを使ってみた'
}

TablePartial tail_template {
    // 全テーブル必須の共通パーツ
    create_user_id bigint(20) [not null, note: '作成者']
    update_user_id bigint(20) [not null, note: '更新者']
    create_date datetime [not null, note: '作成日時']
    update_date datetime [not null, note: '更新日時']
    delete_flag tinyint(2) [not null, default: 0, note: '''
        削除フラグ:
        0: 未削除
        1: 削除済
    ''']
}

Table users {
    id serial [pk, note: 'ID']
    name varchar(255) [not null, note: 'ユーザー名']
    email varchar(255) [not null, unique, note: 'メールアドレス']
    password varchar(255) [not null, note: 'パスワード']
    ~tail_template

    Note: 'ユーザー'
}

Table groups {
    id serial [pk, note: 'ID']
    name varchar(255) [not null, note: 'グループ名']
    description text [note: 'グループ詳細']
    ~tail_template

    Note: 'グループ'
}

Table group_user {
    id serial [pk, note: 'ID']
    group_id "bigint unsigned" [ref: > groups.id, not null, note: 'グループID']
    user_id "bigint unsigned" [ref: > users.id, not null, note: 'ユーザーID']
    ~tail_template

    Note: 'グループとユーザーの対応'
}

Table roles {
    id serial [pk, note: 'ID']
    name varchar [not null, note: 'ロール名']
    description text [note: 'ロール詳細']
    ~tail_template

    Note: 'ロール'
}

Table group_role {
    id serial [pk, note: 'ID']
    group_id "bigint unsigned" [ref: > groups.id, not null, note: 'グループID']
    role_id "bigint unsigned" [ref: > roles.id, not null, note: 'ロールID']
    ~tail_template

    Note: 'グループとロールの対応'
}

DBMLからSQLを生成する

では、上記で作成したDBMLから、MySQL用のSQLを生成してみます。

作業用コンテナに接続します。

bin/al-user

上記で作成した「sample.dbml」があることを確認します。

「dbml2sql」コマンドで変換後のSQLを「sample.sql」に保存します。

dbml2sql sample.dbml --mysql -o sample.sql

▼「sample.sql」

-- SQL dump generated using DBML (dbml.dbdiagram.io)
-- Database: MySQL
-- Generated at: 2025-07-10T06:57:44.615Z

CREATE TABLE `users` (
  `id` serial PRIMARY KEY COMMENT 'ID',
  `name` varchar(255) NOT NULL COMMENT 'ユーザー名',
  `email` varchar(255) UNIQUE NOT NULL COMMENT 'メールアドレス',
  `password` varchar(255) NOT NULL COMMENT 'パスワード',
  `create_user_id` bigint(20) NOT NULL COMMENT '作成者',
  `update_user_id` bigint(20) NOT NULL COMMENT '更新者',
  `create_date` datetime NOT NULL COMMENT '作成日時',
  `update_date` datetime NOT NULL COMMENT '更新日時',
  `delete_flag` tinyint(2) NOT NULL DEFAULT 0 COMMENT '削除フラグ:
0: 未削除
1: 削除済
'
);

CREATE TABLE `groups` (
  `id` serial PRIMARY KEY COMMENT 'ID',
  `name` varchar(255) NOT NULL COMMENT 'グループ名',
  `description` text COMMENT 'グループ詳細',
  `create_user_id` bigint(20) NOT NULL COMMENT '作成者',
  `update_user_id` bigint(20) NOT NULL COMMENT '更新者',
  `create_date` datetime NOT NULL COMMENT '作成日時',
  `update_date` datetime NOT NULL COMMENT '更新日時',
  `delete_flag` tinyint(2) NOT NULL DEFAULT 0 COMMENT '削除フラグ:
0: 未削除
1: 削除済
'
);

CREATE TABLE `group_user` (
  `id` serial PRIMARY KEY COMMENT 'ID',
  `group_id` bigint unsigned NOT NULL COMMENT 'グループID',
  `user_id` bigint unsigned NOT NULL COMMENT 'ユーザーID',
  `create_user_id` bigint(20) NOT NULL COMMENT '作成者',
  `update_user_id` bigint(20) NOT NULL COMMENT '更新者',
  `create_date` datetime NOT NULL COMMENT '作成日時',
  `update_date` datetime NOT NULL COMMENT '更新日時',
  `delete_flag` tinyint(2) NOT NULL DEFAULT 0 COMMENT '削除フラグ:
0: 未削除
1: 削除済
'
);

CREATE TABLE `roles` (
  `id` serial PRIMARY KEY COMMENT 'ID',
  `name` varchar(255) NOT NULL COMMENT 'ロール名',
  `description` text COMMENT 'ロール詳細',
  `create_user_id` bigint(20) NOT NULL COMMENT '作成者',
  `update_user_id` bigint(20) NOT NULL COMMENT '更新者',
  `create_date` datetime NOT NULL COMMENT '作成日時',
  `update_date` datetime NOT NULL COMMENT '更新日時',
  `delete_flag` tinyint(2) NOT NULL DEFAULT 0 COMMENT '削除フラグ:
0: 未削除
1: 削除済
'
);

CREATE TABLE `group_role` (
  `id` serial PRIMARY KEY COMMENT 'ID',
  `group_id` bigint unsigned NOT NULL COMMENT 'グループID',
  `role_id` bigint unsigned NOT NULL COMMENT 'ロールID',
  `create_user_id` bigint(20) NOT NULL COMMENT '作成者',
  `update_user_id` bigint(20) NOT NULL COMMENT '更新者',
  `create_date` datetime NOT NULL COMMENT '作成日時',
  `update_date` datetime NOT NULL COMMENT '更新日時',
  `delete_flag` tinyint(2) NOT NULL DEFAULT 0 COMMENT '削除フラグ:
0: 未削除
1: 削除済
'
);

ALTER TABLE `users` COMMENT = 'ユーザー';

ALTER TABLE `groups` COMMENT = 'グループ';

ALTER TABLE `group_user` COMMENT = 'グループとユーザーの対応';

ALTER TABLE `roles` COMMENT = 'ロール';

ALTER TABLE `group_role` COMMENT = 'グループとロールの対応';

ALTER TABLE `group_user` ADD FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`);

ALTER TABLE `group_user` ADD FOREIGN KEY (`user_id`) REFERENCES `users` (`id`);

ALTER TABLE `group_role` ADD FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`);

ALTER TABLE `group_role` ADD FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`);

テーブルを作成してみる

上記で出力したSQLから、MySQL上のデータベースにテーブルを作成してみます。

作業用コンテナ上からデータベース「using_dbml」を作成してみます。

※パスワード「pass」

mysql -h mysql -u root -p -e'create database using_dbml;'

データベース一覧を確認してみます。

mysql -h mysql -u root -p -e'show databases;'

「using_dbml」が作成されています。

では、上記で作成した「sample.sql」を「using_dbml」流し込んでいきます。

mysql -h mysql -u root -p using_dbml < sample.sql

テーブル一覧を表示してみます。

mysql -h mysql -u root -p using_dbml -e'show tables;'

mysqldumpでダンプしてみます。

mysqldump -h mysql -u root -p using_dbml > using_dbml.dump

▼「using_dbml.dump」

/*!999999\- enable the sandbox mode */ 
-- MariaDB dump 10.19  Distrib 10.5.25-MariaDB, for Linux (x86_64)
--
-- Host: mysql    Database: using_dbml
-- ------------------------------------------------------
-- Server version	9.3.0

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `group_role`
--

DROP TABLE IF EXISTS `group_role`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `group_role` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `group_id` bigint unsigned NOT NULL COMMENT 'グループID',
  `role_id` bigint unsigned NOT NULL COMMENT 'ロールID',
  `create_user_id` bigint NOT NULL COMMENT '作成者',
  `update_user_id` bigint NOT NULL COMMENT '更新者',
  `create_date` datetime NOT NULL COMMENT '作成日時',
  `update_date` datetime NOT NULL COMMENT '更新日時',
  `delete_flag` tinyint NOT NULL DEFAULT '0' COMMENT '削除フラグ:\n0: 未削除\n1: 削除済\n',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`),
  KEY `group_id` (`group_id`),
  KEY `role_id` (`role_id`),
  CONSTRAINT `group_role_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`),
  CONSTRAINT `group_role_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='グループとロールの対応';
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `group_role`
--

LOCK TABLES `group_role` WRITE;
/*!40000 ALTER TABLE `group_role` DISABLE KEYS */;
/*!40000 ALTER TABLE `group_role` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `group_user`
--

DROP TABLE IF EXISTS `group_user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `group_user` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `group_id` bigint unsigned NOT NULL COMMENT 'グループID',
  `user_id` bigint unsigned NOT NULL COMMENT 'ユーザーID',
  `create_user_id` bigint NOT NULL COMMENT '作成者',
  `update_user_id` bigint NOT NULL COMMENT '更新者',
  `create_date` datetime NOT NULL COMMENT '作成日時',
  `update_date` datetime NOT NULL COMMENT '更新日時',
  `delete_flag` tinyint NOT NULL DEFAULT '0' COMMENT '削除フラグ:\n0: 未削除\n1: 削除済\n',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`),
  KEY `group_id` (`group_id`),
  KEY `user_id` (`user_id`),
  CONSTRAINT `group_user_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`),
  CONSTRAINT `group_user_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='グループとユーザーの対応';
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `group_user`
--

LOCK TABLES `group_user` WRITE;
/*!40000 ALTER TABLE `group_user` DISABLE KEYS */;
/*!40000 ALTER TABLE `group_user` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `groups`
--

DROP TABLE IF EXISTS `groups`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `groups` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'グループ名',
  `description` text COLLATE utf8mb4_general_ci COMMENT 'グループ詳細',
  `create_user_id` bigint NOT NULL COMMENT '作成者',
  `update_user_id` bigint NOT NULL COMMENT '更新者',
  `create_date` datetime NOT NULL COMMENT '作成日時',
  `update_date` datetime NOT NULL COMMENT '更新日時',
  `delete_flag` tinyint NOT NULL DEFAULT '0' COMMENT '削除フラグ:\n0: 未削除\n1: 削除済\n',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='グループ';
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `groups`
--

LOCK TABLES `groups` WRITE;
/*!40000 ALTER TABLE `groups` DISABLE KEYS */;
/*!40000 ALTER TABLE `groups` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `roles`
--

DROP TABLE IF EXISTS `roles`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `roles` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ロール名',
  `description` text COLLATE utf8mb4_general_ci COMMENT 'ロール詳細',
  `create_user_id` bigint NOT NULL COMMENT '作成者',
  `update_user_id` bigint NOT NULL COMMENT '更新者',
  `create_date` datetime NOT NULL COMMENT '作成日時',
  `update_date` datetime NOT NULL COMMENT '更新日時',
  `delete_flag` tinyint NOT NULL DEFAULT '0' COMMENT '削除フラグ:\n0: 未削除\n1: 削除済\n',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='ロール';
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `roles`
--

LOCK TABLES `roles` WRITE;
/*!40000 ALTER TABLE `roles` DISABLE KEYS */;
/*!40000 ALTER TABLE `roles` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `users`
--

DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `users` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ユーザー名',
  `email` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'メールアドレス',
  `password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'パスワード',
  `create_user_id` bigint NOT NULL COMMENT '作成者',
  `update_user_id` bigint NOT NULL COMMENT '更新者',
  `create_date` datetime NOT NULL COMMENT '作成日時',
  `update_date` datetime NOT NULL COMMENT '更新日時',
  `delete_flag` tinyint NOT NULL DEFAULT '0' COMMENT '削除フラグ:\n0: 未削除\n1: 削除済\n',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='ユーザー';
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `users`
--

LOCK TABLES `users` WRITE;
/*!40000 ALTER TABLE `users` DISABLE KEYS */;
/*!40000 ALTER TABLE `users` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2025-07-10  7:22:50

SQLからDBMLに変換してみる

まずは、最初に生成した「sample.sql」をDBMLに変換してみます。

sql2dbml sample.sql --mysql -o from_sql.dbml

▼「from_sql.dbml」

Table "users" {
  "id" serial [pk, note: 'ID']
  "name" varchar(255) [not null, note: 'ユーザー名']
  "email" varchar(255) [unique, not null, note: 'メールアドレス']
  "password" varchar(255) [not null, note: 'パスワード']
  "create_user_id" bigint(20) [not null, note: '作成者']
  "update_user_id" bigint(20) [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint(2) [not null, default: 0, note: '''削除フラグ:
0: 未削除
1: 削除済
''']
}

Table "groups" {
  "id" serial [pk, note: 'ID']
  "name" varchar(255) [not null, note: 'グループ名']
  "description" text [note: 'グループ詳細']
  "create_user_id" bigint(20) [not null, note: '作成者']
  "update_user_id" bigint(20) [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint(2) [not null, default: 0, note: '''削除フラグ:
0: 未削除
1: 削除済
''']
}

Table "group_user" {
  "id" serial [pk, note: 'ID']
  "group_id" bigint [not null, note: 'グループID']
  "user_id" bigint [not null, note: 'ユーザーID']
  "create_user_id" bigint(20) [not null, note: '作成者']
  "update_user_id" bigint(20) [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint(2) [not null, default: 0, note: '''削除フラグ:
0: 未削除
1: 削除済
''']
}

Table "roles" {
  "id" serial [pk, note: 'ID']
  "name" varchar(255) [not null, note: 'ロール名']
  "description" text [note: 'ロール詳細']
  "create_user_id" bigint(20) [not null, note: '作成者']
  "update_user_id" bigint(20) [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint(2) [not null, default: 0, note: '''削除フラグ:
0: 未削除
1: 削除済
''']
}

Table "group_role" {
  "id" serial [pk, note: 'ID']
  "group_id" bigint [not null, note: 'グループID']
  "role_id" bigint [not null, note: 'ロールID']
  "create_user_id" bigint(20) [not null, note: '作成者']
  "update_user_id" bigint(20) [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint(2) [not null, default: 0, note: '''削除フラグ:
0: 未削除
1: 削除済
''']
}

Ref:"groups"."id" < "group_user"."group_id"

Ref:"users"."id" < "group_user"."user_id"

Ref:"groups"."id" < "group_role"."group_id"

Ref:"roles"."id" < "group_role"."role_id"

次は、先ほどのダンプファイルをDBMLに変換してみます。

sql2dbml using_dbml.dump --mysql -o from_dump.dbml

▼「from_dump.dbml」

Table "group_role" {
  "id" bigint [pk, not null, increment, note: 'ID']
  "group_id" bigint [not null, note: 'グループID']
  "role_id" bigint [not null, note: 'ロールID']
  "create_user_id" bigint [not null, note: '作成者']
  "update_user_id" bigint [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint [not null, default: '0', note: '削除フラグ:\\n0: 未削除\\n1: 削除済\\n']

  Indexes {
    id [unique, name: "id"]
    group_id [name: "group_id"]
    role_id [name: "role_id"]
  }
  Note: 'グループとロールの対応'
}

Table "group_user" {
  "id" bigint [pk, not null, increment, note: 'ID']
  "group_id" bigint [not null, note: 'グループID']
  "user_id" bigint [not null, note: 'ユーザーID']
  "create_user_id" bigint [not null, note: '作成者']
  "update_user_id" bigint [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint [not null, default: '0', note: '削除フラグ:\\n0: 未削除\\n1: 削除済\\n']

  Indexes {
    id [unique, name: "id"]
    group_id [name: "group_id"]
    user_id [name: "user_id"]
  }
  Note: 'グループとユーザーの対応'
}

Table "groups" {
  "id" bigint [pk, not null, increment, note: 'ID']
  "name" varchar(255) [not null, note: 'グループ名']
  "description" text [note: 'グループ詳細']
  "create_user_id" bigint [not null, note: '作成者']
  "update_user_id" bigint [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint [not null, default: '0', note: '削除フラグ:\\n0: 未削除\\n1: 削除済\\n']

  Indexes {
    id [unique, name: "id"]
  }
  Note: 'グループ'
}

Table "roles" {
  "id" bigint [pk, not null, increment, note: 'ID']
  "name" varchar(255) [not null, note: 'ロール名']
  "description" text [note: 'ロール詳細']
  "create_user_id" bigint [not null, note: '作成者']
  "update_user_id" bigint [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint [not null, default: '0', note: '削除フラグ:\\n0: 未削除\\n1: 削除済\\n']

  Indexes {
    id [unique, name: "id"]
  }
  Note: 'ロール'
}

Table "users" {
  "id" bigint [pk, not null, increment, note: 'ID']
  "name" varchar(255) [not null, note: 'ユーザー名']
  "email" varchar(255) [not null, note: 'メールアドレス']
  "password" varchar(255) [not null, note: 'パスワード']
  "create_user_id" bigint [not null, note: '作成者']
  "update_user_id" bigint [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint [not null, default: '0', note: '削除フラグ:\\n0: 未削除\\n1: 削除済\\n']

  Indexes {
    id [unique, name: "id"]
    email [unique, name: "email"]
  }
  Note: 'ユーザー'
}

Ref "group_role_ibfk_1":"groups"."id" < "group_role"."group_id"

Ref "group_role_ibfk_2":"roles"."id" < "group_role"."role_id"

Ref "group_user_ibfk_1":"groups"."id" < "group_user"."group_id"

Ref "group_user_ibfk_2":"users"."id" < "group_user"."user_id"

DBから直接DBML変換してみる

MySQL接続用文字列の書式は次の通りです。

mysq://[DBユーザー名]:[DBパスワード]@[DBホスト名]:[DBポート番号]/[DB名]

DBから直接DBMLに変換してみます。

db2dbml mysql 'mysql://root:pass@mysql:3306/using_dbml' -o from_db.dbml

▼「from_db.dbml」

Table "group_role" {
  "id" "bigint unsigned" [unique, pk, not null, increment, note: 'ID']
  "group_id" "bigint unsigned" [not null, note: 'グループID']
  "role_id" "bigint unsigned" [not null, note: 'ロールID']
  "create_user_id" bigint [not null, note: '作成者']
  "update_user_id" bigint [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint [not null, default: 0, note: '''削除フラグ:
0: 未削除
1: 削除済
''']

  Indexes {
    group_id [type: btree, name: "group_id"]
    role_id [type: btree, name: "role_id"]
  }
  Note: 'グループとロールの対応'
}

Table "group_user" {
  "id" "bigint unsigned" [unique, pk, not null, increment, note: 'ID']
  "group_id" "bigint unsigned" [not null, note: 'グループID']
  "user_id" "bigint unsigned" [not null, note: 'ユーザーID']
  "create_user_id" bigint [not null, note: '作成者']
  "update_user_id" bigint [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint [not null, default: 0, note: '''削除フラグ:
0: 未削除
1: 削除済
''']

  Indexes {
    group_id [type: btree, name: "group_id"]
    user_id [type: btree, name: "user_id"]
  }
  Note: 'グループとユーザーの対応'
}

Table "groups" {
  "id" "bigint unsigned" [unique, pk, not null, increment, note: 'ID']
  "name" varchar(255) [not null, note: 'グループ名']
  "description" text [note: 'グループ詳細']
  "create_user_id" bigint [not null, note: '作成者']
  "update_user_id" bigint [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint [not null, default: 0, note: '''削除フラグ:
0: 未削除
1: 削除済
''']
  Note: 'グループ'
}

Table "roles" {
  "id" "bigint unsigned" [unique, pk, not null, increment, note: 'ID']
  "name" varchar(255) [not null, note: 'ロール名']
  "description" text [note: 'ロール詳細']
  "create_user_id" bigint [not null, note: '作成者']
  "update_user_id" bigint [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint [not null, default: 0, note: '''削除フラグ:
0: 未削除
1: 削除済
''']
  Note: 'ロール'
}

Table "users" {
  "id" "bigint unsigned" [unique, pk, not null, increment, note: 'ID']
  "name" varchar(255) [not null, note: 'ユーザー名']
  "email" varchar(255) [unique, not null, note: 'メールアドレス']
  "password" varchar(255) [not null, note: 'パスワード']
  "create_user_id" bigint [not null, note: '作成者']
  "update_user_id" bigint [not null, note: '更新者']
  "create_date" datetime [not null, note: '作成日時']
  "update_date" datetime [not null, note: '更新日時']
  "delete_flag" tinyint [not null, default: 0, note: '''削除フラグ:
0: 未削除
1: 削除済
''']
  Note: 'ユーザー'
}

Ref "group_role_ibfk_1":"groups"."id" < "group_role"."group_id"

Ref "group_role_ibfk_2":"roles"."id" < "group_role"."role_id"

Ref "group_user_ibfk_1":"groups"."id" < "group_user"."group_id"

Ref "group_user_ibfk_2":"users"."id" < "group_user"."user_id"

DBMLからERDを生成してみる

DBMLからER図を生成する方法は何通りかあります。

1.dbdiagram.io のエディタにDBMLを貼り付けて生成

2.VS Codeの拡張機能「DBML Entity-Relationship Diagrams visualizer」でプレビュー

3.CLIツール「dbml-renderer」をインストールして生成(VS Code拡張機能もあり)

上記1が一番見栄えが良いと思います。

上記2はVS Code上でプレビューできてマウスドラッグで位置調整できるので便利です。

上記3はワンライナーのコマンドでSVGに保存できますが見栄えはちょっと。。

▼1.dbdiagram.io を開きます

「Create your diagram」ボタンを押下します。

画面左側のエディターにDBMLを貼り付けると、右側にリアルタイムでER図が表示されます。

表示されたER図はマウスドラッグで位置調整可能です。

SVGへの出力は、サインアップ後に可能です。

▼2.VS Code拡張機能「DBML ERD Visualizer」を使ってみる

※執筆時点では「TablePartial」には対応していません。

VS Code拡張機能「DBML Entity-Relationship Diagrams visualizer」をインストールします。

「TablePartial」を使っていない「from_sql.dbml」等を開きます。

ファイル名タブの右側に表示される「Show diagram」のアイコンをクリックします。

DBMLの右側にERDのプレビューが表示されます。

エンティティをマウスドラッグして位置調整できます。

難点は次の2点でしょうか・・

1.拡大縮小が不便

2.SVG等、何らかの外部への出力ができない

この辺が解消されれば、かなり使えるツールになると思います。

▼3.「dbml-renderer」をインストールしてみる

作業用コンテナにグローバルインストールします。

sudo npm install -g @softwaretechnik/dbml-renderer

「from_sql.dbml」を基に「erd_from_sql.svg」を出力してみます。

dbml-renderer -i from_sql.dbml -o erd_from_sql.svg

次のようなSVG画像が出力されました。

難点は次の2点でしょうか。

1.見た目がちょっと・・・

2.直接レイアウト調整ができない

レイアウトについては、DOT言語を用いると色々と調整可能ですがメンドイ。。

AIに頑張らせてみましたが、失敗の堂々巡りで今回は諦めました。。

まとめ

▼プロジェクトのモデル定義でDBMLを設置しておくべし

 ⇒メンバー共有、AIへの指示、ER図生成

 ⇒リポジトリに登録、テキストベースでツール連携

▼ツール周りはもう少し充実してても良さそうなものですが・・・

 ⇒試しにAIにERD生成させたら、頑張ってDOTファイルを調整してましたがダメでした。

 ⇒今度、DOT言語を使ってGraphvisで遊んでみようと思います。

 ⇒ dbdiagram.io が一番優れているツールですね。

参考サイト

Home | DBML
Open source
dbdiagram.io - Database Relationship Diagrams Design Tool
Quick and simple free tool to help you draw your database relationship diagrams and flow quickly using simple DSL langua...
DBML Entity-Relationship Diagrams visualizer - Visual Studio Marketplace
Extension for Visual Studio Code - A VS Code extension for viewing the ERD (Entity Relationship Diagram) database schema...
GitHub - softwaretechnik-berlin/dbml-renderer
Contribute to softwaretechnik-berlin/dbml-renderer development by creating an account on GitHub.
Graphvizとdot言語でグラフを描く方法のまとめ - Qiita
概要 Graphvizはdot言語で記述されたグラフ構造を任意のフォーマットの画像ファイルへ出力するツールです。 グラフ構造はdot言語でdotファイルというプレーンテキストに記述します。 この記事はdot言語でグラフを書く方法を簡単にまと...
Graphviz
Please join the Graphviz forum to ask questions and discuss Graphviz.What is Graphviz? Graphviz is open source graph vis...
  • 3
  • 0
  • 0
  • 0

コメント

タイトルとURLをコピーしました