Not the cleanest solution (uses scalaz 7.0.6 and shapeless 2.0.1), but this works for now (Slick 2.0.1):
Using the ?
projection above, it's possible to create a Slick projection that converts the tuple of Option
values => Option[TupleN]
=> Option[YourClass]
.
Add option
Projection
Note: sequence
is used to convert a tuple of Option
values to Option[TupleN]
. Code for sequence
is defined at the bottom of this answer.
Add to Suppliers
. Assumes Supplier
is a 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
Using the option
Projection
val explicitLeftOuterJoin = for {
(c, s) <- Coffees leftJoin Suppliers on (_.supID === _.id)
} yield (c, s.option)
Advanced: sequence
, Converts Tuple of Option
Values to Option[TupleN]
This is the hard part that Travis Brown wrote. sequence
converts from a tuple of Option
values to a Option[TupleN]
(using scalaz and shapeless).
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(_))
}
Usage for 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) // Some(Person(1,Bob,40))
High-level overview of what sequence
does (not proper types):
- Converts a tuple of
Option
to an shapeless HList[Option[_]]
.
sequence
over the HList[Option[_]]
to a Option[HList[_]]
- Convert the
HList
back to a tuple.