假设我有一个名为Blarg
的案例类,它由具有基本类型的属性组成:
case class Blarg(
x: String,
y: Int
)
Blarg
用于各种类,有时用作Option[Blarg]
,有时用作List[Blarg]
,并且这些类是持久的。我们还有一个名为OptionalComplexThing
的案例类,其中包含Option[Blarg]
类型的属性:
case class OptionalComplexThing(
one: String,
maybeInt: Option[Int],
maybeBlarg: Option[Blarg],
id: Option[Long] = None
)
问题是如何创建包含相应子投影的默认MappedProjection
。请注意下面的blarg
MappedProjection
。我希望能够转换blarg
MappedProjection
,以使其Column
的所有Option
都为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)
^ */
}
。我不想对这个例子进行硬编码 - 使用组合器应该有一种通用的方法。
System.out
Here is a a GitHub project证明了这个问题。
答案 0 :(得分:0)
您可以编写自定义版本的tupled / unapply方法:
case object Blarg {
def fromOptions(maybeX: Option[String], maybeY: Option[Int]): Option[Blarg] = {
(maybeX, maybeY) match {
case (Some(x), Some(y)) => Some(Blarg(x, y))
case _ => None
}
}
def customTupled = (fromOptions _).tupled
def customUnapply(arg: Option[Blarg]): Option[(Option[String], Option[Int])] = arg.map { blarg =>
(Some(blarg.x), Some(blarg.y))
}
}
class _OptionalComplexThings(tag: Tag) extends Table[OptionalComplexThing](tag, "optional_complex_thing") {
def one = column[String]("one")
def maybeInt = column[Option[Int]]("maybe_int")
def id = column[Option[Long]]("id", O.PrimaryKey, O.AutoInc)
def maybeX = column[Option[String]]("x")
def maybeY = column[Option[Int]]("y")
def blarg = (maybeX, maybeY) <> (Blarg.customTupled, Blarg.customUnapply)
def * = (one, maybeInt, blarg, id) <> (OptionalComplexThing.tupled, OptionalComplexThing.unapply)
}
这可能不是最短的解决方案,但应该有效。