2016-05-13 32 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,如何实现类似的功能? –