2016-05-13 60 views
0

比方說,我有一個名爲Blarg由屬性與基本類型的情況下類:如何變換油滑2.1.0 MappedProjection所以它的所有列選項

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

Blarg S IN各種類使用,有時如Option[Blarg],有時爲List[Blarg],並且這些類是持久的。我們也有一個名爲OptionalComplexThingOption[Blarg]類型的屬性的情況下類:

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

的問題是如何創建一個包含適當的子投影默認MappedProjection。請注意下面的blargMappedProjection。我希望能夠改造blargMappedProjection,所以它的所有Column s是Option s。我不想硬編碼這個例子 - 應該有一個通用的方法來使用組合器來做到這一點。

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,如何實現類似的功能? –