はじめに
「プリミティブ型の多用は良くない!」という考え方から、
以下のようにshapelessを使ってモデルにラベルを付与してみました。
case class Horse(
id: Option[Horse.Id],
name: String
)
object Horse {
type Id = Long @@ Horse
}
これで、コードがわかりやすくなり、コンパイル時に不整合があれば検出してくれるので、安全性が向上した感じがします。
しかし、データベースとの入出力の際にどうなるのか...😌
というわけで、今回はPlay FrameworkとSlickを使って、ラベル付きIDを扱う方法を紹介します!
ColumnTypeを定義
マッピングを定義することで、ラベル付きIDの入出力を円滑に行うことができます。
package model
import shapeless.tag
import shapeless.tag.@@
import slick.jdbc.JdbcType
import slick.jdbc.MySQLProfile.api._
case class Horse(
id: Horse.Id,
name: String
)
object Horse {
type Id = Long @@ Horse
implicit val horseColumType: JdbcType[Horse.Id] = MappedColumnType.base[Horse.Id, Long](
id => id,
long => tag[Horse][Long](long)
)
}
リポジトリ
リポジトリでは、通常通りcolumnメソッドの型引数にラベル付きIDを指定することができます。
private class HorseTable(tag: Tag) extends Table[Horse](tag,"horse"){
def id = column[Option[Horse.Id]]("id",O.PrimaryKey)
まとめ
思ったより簡単にラベル付き型を扱うことができました。マッピングさえ定義すれば、ユーザー定義型でも同じように対応できると思います!
ラベル付き型を使うとコードが安全になり、読みやすさも向上するので最高ですね!(少し手間がかかるけど)
ちなみに、TypeScriptでも同様のことができるのかなと調べたら、Branded Typesというものがあるようです🤔
気になります...!