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


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

UsersRepo.scala

```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

```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.?にしてあげると解決しました。
*　←　この役割が未だに不明なので調べてみようと思います。

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

```