Let's say I have a case class called Blarg consisting of properties with primitive types:
case class Blarg(
x: String,
y: Int
)
Blargs are used in various classes, sometimes as Option[Blarg], sometimes as List[Blarg], and those classes are persisted. We also have a case class called OptionalComplexThing containing a property of type Option[Blarg]:
case class OptionalComplexThing(
one: String,
maybeInt: Option[Int],
maybeBlarg: Option[Blarg],
id: Option[Long] = None
)
The problem is how to create a default MappedProjection containing the appropriate sub-projection. Notice the blarg MappedProjection below. I want to be able to transform the blarg MappedProjection so all its Columns are Options. I don't want to hard-code this example - there should be a generic way to do this using combinators.
class _OptionalComplexThings(tag: Tag) extends Table[OptionalComplexThing](tag, "optional_complex_thing") {
def one = column[String]("one")
def maybeInt = column[Option[Int]]("maybe_int") // specifying O.Nullable makes no difference
def id = column[Option[Long]]("id", O.PrimaryKey, O.AutoInc)
// Blarg fields need to have their lifted types remapped according to MappedProjection usage.
// Notice OptionalComplexThing's maybeBlarg property is an Option[Blarg].
def x = column[String]("x") // want to map to column[Option[String]]("x")
def y = column[Int]("y") // want to map to column[Option[String]]("y")
def blarg = (x, y) <> (Blarg.tupled, Blarg.unapply)
def * = (one, maybeInt, Option(blarg), id) <> (OptionalComplexThing.tupled, OptionalComplexThing.unapply)
/* Error:(23, 46) No matching Shape found.
Slick does not know how to map the given types.
Possible causes: T in Table[T] does not match your * projection. Or you use an unsupported type in a Query (e.g. scala List).
Required level: scala.slick.lifted.FlatShapeLevel
Source type: (scala.slick.lifted.Column[String], scala.slick.lifted.Column[Option[Int]], Option[scala.slick.lifted.MappedProjection[Blarg,(String, Int)]], scala.slick.lifted.Column[Option[Long]])
Unpacked type: (String, Option[Int], Option[Blarg], Option[Long])
Packed type: Any
def * = (one, maybeInt, Option(blarg), id) <> (OptionalComplexThing.tupled, OptionalComplexThing.unapply)
^ */
}
Here is a a GitHub project that demonstrates the question.
You could write your custom versions of tupled/unapply methods:
This might not be the shortest possible solution, but should work.