2016-05-13 8 views
0

のは、私はBlargは、プリミティブ型とプロパティから成ると呼ばれるケースクラスがあるとしましょう:時々、ので、そのすべての列はオプションです

case class Blarg(
    x: String, 
    y: Int 
) 

Blarg sは、さまざまなクラスで使用されているがOption[Blarg]として、場合によってはList[Blarg]となり、これらのクラスは永続化されます。また、タイプOption[Blarg]のプロパティを含むOptionalComplexThingと呼ばれるケースクラスを持っている:

case class OptionalComplexThing(
    one: String, 
    maybeInt: Option[Int], 
    maybeBlarg: Option[Blarg], 
    id: Option[Long] = None 
) 

問題は、適切なサブ突起部を含むデフォルトMappedProjectionを作成する方法です。下記のblargMappedProjectionに注目してください。私はblargMappedProjectionColumnのすべてが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) 
              ^*/ 
} 

Here is a a GitHub projectこれは質問を示しています。

答えて

0

あなたは/ tupled適用を解除する方法のカスタムバージョンを書くことができます:

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) 
} 

はこれが最短の解決策ではないかもしれませんが、動作するはずです。

+0

これは私が避けたい手作りのアプローチです。このアプローチの問題は、誰かがそれを維持しなければならず、プロジェクトが将来に移るにつれて、人々が退去し、ケースクラスのプロパティが変わるということです。代わりに、コンビネータを使用したいと思います。 Blarg.fromOptionsやcustomUnapplyを手作業で作成することなく、どうすれば同様のことが達成できるでしょうか? –

関連する問題