はじめに
Slick 3.2.3のコードジェネレータを使ってMySQLのスキーマをコード化する方法をご紹介します.Slickはバージョンアップする度に渡すパラメータや必要な依存が変わり,意外にすんなり使えないので,記事にすることにしました.
Slickとは
SlickはFRM(Functional Relational Mapping)と呼ばれるライブラリのことで,主にScalaで利用されています.JDBCやORMと同様にデータベースへの接続を楽にするためのライブラリです.
Slickの特徴はSQLを一切書かないでデータベースへのCRUD操作(読み書き)を実現できる点です.そのため,テーブルスキーマをクラスとして記述する必要があります.そこで,わざわざテーブルスキーマをクラス化するのは面倒だ,ということでコードジェネレータが同梱されています.
コード生成までの流れ
Slickのコードジェネレータを使ってコードを自動生成するためのざっくりとした流れは下記のようになります.
1. 生成するスキーマの準備
2. sbtプロジェクトを作る
3. コードジェネレータ用の設定ファイルを書く
4. コードジェネレータを実行するMainクラスを書く
5. 実行する.以上!
準備
MySQLをセットアップし,自動生成したいスキーマを用意します.今回は下記のsqlをコード化します.DBはtest_db
としました.また,ここではMySQL 5.7.17を使います.
CREATE TABLE IF NOT EXISTS test_db.`user`(
`id` INT UNSIGNED NOT NULL,
`name` VARCHAR(255) NOT NULL,
`age` TINYINT UNSIGNED,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
MySQLにデータベースとテーブルが作成ができたら準備完了です.
手順
MySQLにテーブルを準備できたら,続いてコード自動生成用のプログラムを書いていきます.
sbtでプロジェクトを作る
sbtプロジェクトの全体像は下記のようになります.プロジェクト名はslick-codegen-sample
にしました.
.
├── build.sbt
├── project
│ └── build.properties
└── src
└── main
├── resources
│ └── codegen.conf
└── scala
└── Main.scala
プロジェクトの雛形に合わせてbuild.properties
やbuild.sbt
を記述していきます.
sbt.version = 1.1.6
name := "slick-codegen-sample"
scalaVersion := "2.12.6" // 2.11系のScalaを指定してもOKです
libraryDependencies ++= Seq(
"com.typesafe.slick" %% "slick" % "3.2.3" ,
"mysql" % "mysql-connector-java" % "5.1.38", // 利用しているMySQLのver.によって適宜変更して下さい
"com.typesafe.slick" %% "slick-codegen" % "3.2.3",
"com.typesafe.slick" %% "slick-hikaricp" % "3.2.3",
"org.slf4j" % "slf4j-nop" % "1.6.4"
)
コードジェネレータ用の設定ファイルを書く
次のような設定ファイルを書きます.DBの接続情報は環境によって適宜変更して下さい.下記の設定ファイルだと,./src/main/scala/jp/mattsu
以下にコードが生成されます.
codegen {
test_db {
profile = "slick.jdbc.MySQLProfile$" // 末尾に$が必要なので注意!
db {
dataSourceClass = "slick.jdbc.DatabaseUrlDataSource"
properties {
driver = com.mysql.jdbc.Driver
user = "root" // 環境によって変更して下さい
url = "jdbc:mysql://localhost/test_db?useSSL=false"
password = "root" // 環境によって(ry
}
}
codegen.package = "jp.mattsu" // 出力先のパッケージを指定します
codegen.outputDir = "./src/main/scala" // 出力先のディレクトリを指定します
}
}
コードジェネレータを実行するMainクラスを書く
Mainのコードを書いてきます.slick.codegen.SourceCodeGenerator
に引数で各種設定値を渡すこともできますが,ここでは設定ファイルを渡す方法を使います.コード自体は,設定ファイルのURIを取得して,コードジェネレータに渡しているだけなので非常にシンプルです.
object Main {
def main(args: Array[String]): Unit = {
// クラスパスからリソースファイルを取得します
// file:/省略/slick-codegen-sample/target/scala-2.12/classes/codegen.conf のように取得されます.
val uri = getClass.getClassLoader.getResource("codegen.conf")
// スキーマコードを自動生成します.#以降で該当ファイル内のキーを辿っていけます
// ここではcodegen.conf内のcodegen.test_db以下の設定値を指定しています.
slick.codegen.SourceCodeGenerator.main(Array(uri.toString + "#codegen.test_db")
)
}
}
実行する
プロジェクトルートで下記コマンドを叩くと,Tables.scala
というコードが生成されます.
$ sbt run
生成されたコードを見てみる
...
/** Entity class storing rows of table User
* @param id Database column id SqlType(INT UNSIGNED), PrimaryKey
* @param name Database column name SqlType(VARCHAR), Length(255,true)
* @param age Database column age SqlType(TINYINT UNSIGNED), Default(None)
* @param createdAt Database column created_at SqlType(TIMESTAMP) */
case class UserRow(id: Long, name: String, age: Option[Byte] = None, createdAt: java.sql.Timestamp)
...
コードからuserテーブルを触る際はUserRow
クラスを使ってCRUD操作を行うことになります.UserRow
を見てみると,テーブルスキーマをいい感じに反映してくれていることがわかります.NULL可な項目はOptionに置換えてくれたりしていますね.
ただ残念なことにcreatedAt
にはデフォルト値を設定してくれていません.それに関しては,slick-codegenの基本使用例、DEFAULT値の付いたTIMESTAMPをOption型として出力するに説明が載っていました.
おわりに
以上でSlick 3.2.3でMySQLのスキーマコードを自動生成できるようになりました!尚,本記事で紹介したコードはhttps://github.com/mattsu6/slick-codegen-sample に上がっています.
何かあればご指摘等頂ければと思います.