We have a gigantic table and we need to add a type column to it.
Technically the column suppose to be not nullable, but the migration of updating everything (150M records) is a bit crazy.
So we decided to leave it nullable, and build a converter right into the parser, so the model is always populated with the correct value and when the data is saved, slowly but surely, the data will be backfilled.
This approach works for us in many place for nullable boolean.
My model looks like this:
package models.tasks
import anorm.{Column, _}
import db.ProcessStreetColumn._
import exceptions.ProcessStreetException
import json.ProcessStreetJoda
import models._
import models.checklists.ChecklistRevision
import models.organization.Organization
import models.task_templates.TaskTemplate
import org.joda.time.DateTime
import play.api.libs.json.{Format, Json}
import st.process.util.Muid
case class Task(id: Muid,
audit: AuditMetadata,
completedDate: Option[DateTime],
completedBy: Option[Ref[User]],
organization: Ref[Organization],
taskTemplate: Ref[TaskTemplate],
checklistRevision: Ref[ChecklistRevision],
status: Task.Status.Value,
dueDate: Option[DateTime],
dueDateOverridden: Boolean,
hidden: Boolean,
stopped: Boolean,
taskType: Task.TaskType.Value)
extends Identifiable[Muid]
with Auditable
object Task extends ProcessStreetModel[Task] with ProcessStreetJoda {
object TaskType extends Enumeration with AnormEnumeration with JsonEnumeration {
val Standard, Approval = Value
}
...
For this case I created this converter:
val nullableRowToTaskType: Column[TaskType.Value] = Column[TaskType.Value] {
case (value, MetaDataItem(qualified, _, _)) =>
Option(value) match {
case Some(TaskType.Approval) => Right(TaskType.Approval)
case Some(TaskType.Standard) | None => Right(TaskType.Standard)
case _ =>
Left(TypeDoesNotMatch("Cannot convert " + value + " to TaskType for column " + qualified))
}
}
And I am using it as follows:
...
SqlParser.get[TaskType.Value](qualifiedColumnNameOf(prefix, "task_type"))(nullableRowToTaskType)
...
But, in the converter I am getting the following error:
play.sbt.PlayExceptions$CompilationException: Compilation error[object Column does not take type parameters.]
at play.sbt.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:34)
at play.sbt.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:34)
at scala.Option.map(Option.scala:146)
at play.sbt.run.PlayReload$.$anonfun$taskFailureHandler$1(PlayReload.scala:33)
at scala.Option.map(Option.scala:146)
at play.sbt.run.PlayReload$.taskFailureHandler(PlayReload.scala:28)
at play.sbt.run.PlayReload$.compileFailure(PlayReload.scala:24)
at play.sbt.run.PlayReload$.$anonfun$compile$3(PlayReload.scala:51)
at scala.util.Either$LeftProjection.map(Either.scala:573)
at play.sbt.run.PlayReload$.compile(PlayReload.scala:51)
I am not really sure what to do with it... Not sure what that means. What am I doing wrong?