LoginSignup
1
0

More than 3 years have passed since last update.

slickでカラムをnullableにしたいとき

Posted at

SlickでNullableを表現するには

ちょっと詰まったときがあったのを思い出して備忘録としてQiitaに綴ろうと思います。
下記が今回のサンプルのSlickで定義したスキーマです。

UsersRepo.scala

class UsersTable(tag: Tag) extends Table[User](tag,"USERS") {
    def id = column[UUID]("ID", O.PrimaryKey)
    def email = column[String]("EMAIL")
    def hashedPassword = column[String]("HASHED_PASSWORD")
    def totp = column[Option[String]]("TOTP")
    def firstName = column[String]("FIRST_NAME")
    def lastName = column[String]("LAST_NAME")
    def birthday = column[java.sql.Date]("BIRTHDAY")
    def major = column[String]("MAJOR")
    def year = column[Int]("YEAR")
    def profile = column[String]("PROFILE")
    def adminFlag = column[Boolean]("ADMIN_FLAG")

    def * = (
      id,
      email,
      hashedPassword,
      totp,
      firstName,
      lastName,
      birthday,
      major,
      year,
      profile,
      adminFlag) <> (User.tupled, User.unapply)

    def idxEmail = index("IDX_EMAIL", email.toUpperCase, unique = true)
  }

またこのスキーマのドメインがこちら

User.scala

case class User(
    id: java.util.UUID,
    email: String,
    hashedPassword: String,
    totp: Option[String],
    firstName: String,
    lastName: String,
    birthday: java.sql.Date,
    major: String,
    year: Int,
    profile: Option[String],
    adminFlag: Boolean) 

object User {
  val tupled = (apply _).tupled

  def fromForm(
      params: (String, String, String, java.sql.Date, String, Int),
      email: String
      ) = apply(
          UUID.randomUUID(),
          email,
          PasswordHasher.generate(params._1),
          None,
          params._2,
          params._3,
          params._4,
          params._5,
          params._6,
          None,
          false
        )
}

今回、profileカラムをnullableにする場合の話です。UserコンパニオンオブジェクトでfromFormメソッドを定義しています。このメソッドは、DBにインサートする値を引数に渡した状態でapplyしてくれるメソッドです。
今回、この機能ではprofileカラムはNULLで保存したいと考え、Noneで渡しています。
NoneでインサートすることでSQLでは、NULLが発行されるようになっています。

1.つまり、NoneはOption型なので、あるカラムをNullableで設定したい場合は、そのカラムとなるドメインのフィールドの型をOption型にして上げる必要があります。

このままNoneにのみするとこのようなエラーが出ます。

[info] Compiling 1 Scala source to /Users/fujisawaryouhei/Development/Scala/msains/target/scala-2.12/classes ...
[error] /Users/fujisawaryouhei/Development/Scala/msains/app/models/repo/UsersRepo.scala:52:27: type mismatch;
[error]  found   : ((java.util.UUID, String, String, Option[String], String, String, java.sql.Date, String, Int, Option[String], Boolean)) => models.domain.User
[error]  required: ((java.util.UUID, String, String, Option[String], String, String, java.sql.Date, String, Int, String, Boolean)) => ?
[error]       adminFlag) <> (User.tupled, User.unapply)
[error]                           ^
[error] /Users/fujisawaryouhei/Development/Scala/msains/app/models/repo/UsersRepo.scala:52:40: type mismatch;
[error]  found   : Option[(java.util.UUID, String, String, Option[String], String, String, java.sql.Date, String, Int, Option[String], Boolean)]
[error]  required: Option[(java.util.UUID, String, String, Option[String], String, String, java.sql.Date, String, Int, String, Boolean)]
[error]       adminFlag) <> (User.tupled, User.unapply)
[error]                                        ^
[error] two errors found

Optionとして認識してくれないようです。なぜでしょうか。。。

2.調べてみたところ、def * = 部分のprofile.?にしてあげると解決しました。
* ← この役割が未だに不明なので調べてみようと思います。

def * = (
      id,
      email,
      hashedPassword,
      totp,
      firstName,
      lastName,
      birthday,
      major,
      year,
      profile.?, //.?を追加すると解決する。
      adminFlag) <> (User.tupled, User.unapply)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0