So I have this piece of magic method that should take a case class
as input, get a list of its fields by name, a list of types, zip them all together with a database object, and map with the results
poly
to get a instance of the same case class
back.
Imagine you're parsing acase class
from a DatabaseResult
, and you have a pre-defined set of type classes for that. This method is just automating around the possible combinations of parsers given the fields of the case class are types with available DatabaseResult => ScalaType
type-classes.
object results extends Poly1 {
implicit def extractor[T : Extractor] = at[((T, String), UDTValue)] {
case ((value, fieldName), row) => {
Extractor[T].apply(fieldName, row)
}
}
def extractor[
V1 <: Product,
Out <: HList,
ExOut <: HList,
Fields <: HList,
RowList <: HList,
ZippedPair <: HList,
Result <: HList
](v1: V1, row: Row)(
implicit tag: TypeTag[V1],
gen: Generic.Aux[V1, Out],
fl: FromTraversable[Fields],
fl2: FromTraversable[RowList],
zipper: Zip.Aux[Out :: Fields :: HNil, ExOut],
zipper2: Zip.Aux[ExOut :: RowList :: HNil, ZippedPair],
ext: Mapper.Aux[results.type, ZippedPair, Result],
reifier: Generic.Aux[Result, V1]
): Option[V1] = {
for {
accessors <- Some(classAccessors[V1])
rows <- List.tabulate(accessors.size)(_ => row).toHList[RowList]
fields <- accessors.toHList[Fields]
} yield {
reifier to ((((gen to v1) zip fields) zip rows) map results)
}
}
The bit where it fails is a bit fun. I need to lift a List[String]
and subsequently a List[UDTValue]
to HList
such that they can be zipped together with the out type hlist that comes from Generic.Aux[CaseClassType, Out]
and apply a poly to them.
But the implicits will conflict, since the only bound they will have is Hlist
, so you end up having 2 FromTraversable
definitions required to go from List[T]
to HList[T]
.
Q: Is there an easier way to achieve this without FromTraversable[]
instances?
Q: Is there a way to provide an LUBConstraint
restriction on the input type that is used when FromTraversable[_]
is resolved?
Q: Or better yet, maybe there is a way to cast directly using something like FromTraversable[Input, LUB, Out]
?