Slick 3.0.0 documentation - 08 Schema Code Generation

Permalink to Schema Code Generation — Slick 3.0.0 documentation

スキーマコードの生成 

データベーススキーマが既に存在している場合、Slickのコードジェネレータは非常に便利なツールとなる。これはジェネレータ単独で利用する事もできるし、sbtのbuildと組み合わせて必要な全てのSlickのコードを生成する事が出来る。

Overview 

デフォルトでは、コードジェネレータは全てのテーブルに対するTableクラスと、対応するTableQueryの値を生成する。列に対応するものは、各カラムを引数に取るケースクラスとして生成される。22より多くのカラムを持つテーブルについては、コードジェネレータは自動的にSlickの実験的な機能であるHListを用いた実装に変更する。これはScalaのタプルサイズ問題を解決する1つの方法である。(Scalaのバージョンが2.10.3以下である場合、コンパイル時間に対する問題を解決するためにHCons::の代わりに用いられるが、これはScala2.10.4以上では解決されている話だ)

ジェネレータについては、talk at Scala eXchange 2013にも説明があるから、是非見て欲しい。

Standalone use 

SlickのコードジェネレータはそのライブラリがSlick本体とは独立して公開されている。sbtプロジェクトにおいては、以下のような記述をビルド定義(build.sbtproject/Build.scalaなど)に加える事で利用可能となる。

libraryDependencies += "com.typesafe.slick" %% "slick-codegen" % "3.0.0"

Mavenプロジェクトには、以下のような<dependency>を加えて欲しい。

<dependency>
  <groupId>com.typesafe.slick</groupId>
  <artifactId>slick-codegen_2.10</artifactId>
  <version>3.0.0</version>
</dependency>

Slickのコードジェネレータはコマンドラインから、もしくはJavaやScalaからAPIを利用して使う事が出来る。単純な例だと、以下のように実行すれば良い。

slick.codegen.SourceCodeGenerator.main(
  Array(slickDriver, jdbcDriver, url, outputFolder, pkg)
)

もしくは、こんな感じに。

slick.codegen.SourceCodeGenerator.main(
  Array(slickDriver, jdbcDriver, url, outputFolder, pkg, user, password)
)

引数は、以下のようなものを取る。

Integrated into sbt 

コードジェネレータはsbtで手で実行したり、コンパイル前に毎度実行したりも出来る。slick-codegen-exampleに例があるから参考にして欲しい。

(訳注: tototoshi/sbt-slick-codegenも参考までに)

Generated Code 

デフォルトでは、生成されたコードは指定されたフォルダ以下にTables.scalaという名前のファイルで保存される。このファイルは、良い感じにインポート出来るコードを持つobject Tablesを含んでいる。Slickドライバが適切なものになっているかも確認出来る。このファイルにはtrait Tablesも含まれていて、Cakeパターンを用いたい場合にはこちらを利用すると良い。

Warning

生成されたコードを用いる際には、異なるデータベースドライバを誤って混ぜてしまわないように注意して欲しい。デフォルトのobject Tablesはコード生成の際にドライバを用いる。異なるドライバを一緒に使ってしまうと、ランタイムエラーを引き起こす。生成されたtrait Tablesは異なるドライバにより用いられるが、これは現在テストされておらず非公式な使い方となっている。あなたの環境では上手く動かないかもしれない。将来的にこれらについては公式でサポートする予定だ。

Customization 

ジェネレータはデータモデルに対しどんなコードも生成出来るよう、様々なメソッドをオーバライドして自由にカスタマイズすることが出来る。簡単なカスタマイズから非常に大きなカスタマイズまで、様々なカスタマイズに対応出来る。Playに対応するフレームワークバインディングを行うだとか、そのような例がある。

This exampleでは、どのようにしてコードジェネレータをカスタマイズするのか、sbtのmulti-projectに対しどのようにセットアップするのか、メインとなるソースに対して、コンパイル前に毎度コードジェネレータをどのようにして実行させるのかを見ることが出来る。

コードジェネレータは、異なるフラグメントに対して最適化された小さなサブジェネレータの階層を構造化して実装されている。サブジェネレータの実装は、個々のファクトリメソッドをオーバーライドすることで、カスタマイズしたものに取り替える事ができる。SourceCodeGeneratorは各々のテーブルのためのサブジェネレータを生成するファクトリメソッドを含んでいる。サブジェネレータはTableクラス自体、エンティティとなるケースクラス、カラム、キー、インデックスなど、様々なものを生成するサブジェネレータを含んでいる。カスタマイズされたサブジェネレータも簡単に同様に扱う事ができる。

様々なサブジェネレータにおいて、Slickのデータモデルに関連する部分はコード生成を実行させる際にアクセスされる。

カスタマイズ可能なオーバーライド出来るメソッド一覧については、api documentationを見て欲しい。

以下にジェネレータをカスタマイズするサンプルを載せる。

import slick.codegen.SourceCodeGenerator
// データモデルを取得する
val modelAction = H2Driver.createModel(Some(H2Driver.defaultTables)) // テーブルのフィルタリングはここで行う
val modelFuture = db.run(modelAction)
// コードジェネレータをカスタマイズする
val codegenFuture = modelFuture.map(model => new SourceCodeGenerator(model) {
  // マッピングするテーブルとクラス名をオーバーライド
  override def entityName =
    dbTableName => dbTableName.dropRight(1).toLowerCase.toCamelCase
  override def tableName =
    dbTableName => dbTableName.toLowerCase.toCamelCase
  // いくつか追加のimportを加える
  override def code = "import foo.{MyCustomType,MyCustomTypeMapper}" + "\n" + super.code
  // テーブルジェネレータをカスタマイズ
  override def Table = new Table(_){
    // エンティティクラスの生成を抑制する
    override def EntityType = new EntityType{
      override def classEnabled = false
    }
    // カラムジェネレータをカスタマイズ
    override def Column = new Column(_){
      // 特定のカラムに対して、Scalaの型を変更するようカスタマイズ
      // e.g. to a custom enum or anything else
      override def rawType =
        if(model.name == "SOME_SPECIAL_COLUMN_NAME") "MyCustomType" else super.rawType
    }
  }
})
codegenFuture.onSuccess { case codegen =>
  codegen.writeToFile(
    "slick.driver.H2Driver","some/folder/","some.packag","Tables","Tables.scala"
  )
}
Fork me on GitHub