#Scala
#slick3
#slick-codegen

slick3.1系 slick-codegenのカスタマイズあれこれ

More than 1 year has passed since last update.

いつになってもDBモデルを手で作成するのは単調で面倒くさい作業です

特にテーブルが100も200もあるシステムなんかのローカル環境なんかはmwbで変更しまくってレビューして一気に作る場面も多いハズ...たぶん

こんな時の強い味方 slick-codegenなんですが

デフォだと微妙に使いづらい場面もチラホラ

その1

日付型がデフォでjava.sql.Timestampなのでorg.joda.time.DateTimeにしたい

-> これはtototoshiさんのslick-joda-mapperが解決してくれます

その2

mysqlにある便利な機能の一つで

更新する度に日時を更新してくれたり、作成した時に日時を自動登録してくれたりするカラムオプションがあるんですが

ジェネって作ったmodelだとこいつらにnullぶち込んじゃって機能しないので

毎回こんな感じのことをする必要があるのでなんとかしたい。もう、いるだけでダメな感じ

こんなテーブルの場合

CREATE TABLE people (

id bigint(20) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
age  INT NOT NULL,
addressId   INT NOT NULL,
create_at datetime DEFAULT CURRENT_TIMESTAMP, /*←これとか*/
update_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, /*←これとか*/
PRIMARY KEY (id)
)

毎回mapで項目を絞る必要が....

people.map(p => (p.name, p.age, p.addressId)) += ("M Odersky",12345,1)

その2に対してmodelからそもそもそのカラムを消しちゃう感じで対応してみました

import slick.driver.JdbcProfile

import scala.concurrent.ExecutionContext.Implicits.global
import slick.driver.MySQLDriver.api._
import slick.driver.MySQLDriver
import slick.driver.JdbcProfile
import slick.{model => m}
import slick.codegen.SourceCodeGenerator
import slick.model.Model
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext}

class CustomGenerator(model: m.Model) extends SourceCodeGenerator(model) {

// add some custom imports
override def code = "import com.github.tototoshi.slick.MySQLJodaSupport._\n" + "import org.joda.time.DateTime\n" + super.code
override def Table = new Table(_) {
override def autoIncLastAsOption = true
override def Column = new Column(_) {
override def rawType = model.tpe match {
case "java.sql.Timestamp" => "DateTime" // kill j.s.Timestamp
case "java.sql.Date" => "DateTime" // kill j.s.Timestamp
case _ => {
super.rawType
}
}
}
}
}

object CodeGenWithJodaTime extends App {
val slickDriver = "slick.driver.MySQLDriver"
val jdbcDriver = "com.mysql.jdbc.Driver"
val url = "jdbc:mysql://localhost/myschema"
val outputFolder = "src/main/scala"
val schemas = "myschema"
val pkg = "mypkg"
val user = "username"
val password = "userpassword"
val driver: JdbcProfile = slick.driver.MySQLDriver // TODO: replace this with your Slick driver
val db = { Database.forURL(url, driver = jdbcDriver, user = user, password = password) }

// 非同期をぶった斬って処理する
val model = Await.result(db.run(driver.createModel(None, false)(ExecutionContext.global).withPinnedSession), Duration.Inf)

// 登録日(create_at)と更新日(update_at)はMySql側の設定で対応するのでTablesからは除外する
val ts = (for {
t <- model.tables
c = t.columns.filter(_.name != "create_at").filter(_.name != "update_at")
} yield(slick.model.Table(t.name, c, t.primaryKey, t.foreignKeys, t.indices, t.options)))
val fModel = Model(tables = ts)

val codeGenFuture = new CustomGenerator(fModel).writeToFile(slickDriver, outputFolder , pkg, "Tables", "Tables.scala")
}

以上です、もっと良いやり方あれば教えていただけると嬉しいです。