这并不是最干净的解决方案(使用scalaz 7.0.6和shapeless 2.0.1),但现在可以使用它(Slick 2.0.1):
通过上面的
?
投影,可以创建一个 Slick 投影,将
Option
值的元组转换为
Option[TupleN]
,然后转换为
Option[YourClass]
。
添加 option
投影
注意:sequence
用于将
Option
值的元组转换为
Option[TupleN]
。
sequence
的代码定义在本答案的底部。
添加到
Suppliers
。 假设
Supplier
是一个 case class。
import scalaz._, Scalaz._
import SequenceTupleOption._
def option = (id.?, name.?, street.?) <> (optionApply, optionUnapply)
def optionApply(t: (Option[Int], Option[String], Option[String])): Option[Comment] = {
sequence(t).map(Supplier.tupled)
}
def optionUnapply(oc: Option[Supplier]): Option[(Option[Int], Option[String], Option[String])] = None
使用 option
投影
val explicitLeftOuterJoin = for {
(c, s) <- Coffees leftJoin Suppliers on (_.supID === _.id)
} yield (c, s.option)
高级: sequence
,将Option
值的元组转换为Option[TupleN]
这是Travis Brown编写的较难部分(参见此处)。sequence
可以使用scalaz和shapeless从一个Option
值的元组转换为Option[TupleN]
。
import scalaz._, Scalaz._
import shapeless._, ops.hlist.{ RightFolder, Tupler }
object SequenceTupleOption {
object applicativeFolder extends Poly2 {
implicit def caseApplicative[A, B <: HList, F[_]](implicit
app: Applicative[F]
) = at[F[A], F[B]] {
(a, b) => app.ap(a)(app.map(b)(bb => (_: A) :: bb))
}
}
def sequence[T, EL <: HList, L <: HList, OL <: HList, OT](t: T)(implicit
gen: Generic.Aux[T, EL],
eq: EL =:= L,
folder: RightFolder.Aux[L, Option[HNil], applicativeFolder.type, Option[OL]],
tupler: Tupler.Aux[OL, OT]
): Option[OT] =
eq(gen.to(t)).foldRight(some(HNil: HNil))(applicativeFolder).map(tupler(_))
}
sequence
的使用方法:
import scalaz._, Scalaz._
import SequenceTupleOption._
case class Person(id: Int, name: String, age: Int)
val t = (Option(1), Option("Bob"), Option(40))
val person: Option[Person] = sequence(t).map(Person.tupled)
对sequence
的高级概述(不涉及正确类型):
- 将
Option
元组转换为shapeless HList[Option[_]]
。
- 在
HList [Option [_]]
上进行sequence
操作,得到一个Option[HList[_]]
。
- 将
HList
转换回元组。