2
votes

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 polyto 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]?

1

1 Answers

0
votes

Is there a way to provide an LUBConstraint restriction on the input type that is used when FromTraversable[_] is resolved?

It does not look like shapeless has that, but you could create a custom version of FromTraversable where you restrain def apply(l: GenTraversable[_]): Option[Out] for your need.

Or better yet, maybe there is a way to cast directly using something like FromTraversable[Input, LUB, Out]?

Same, it not in shapeless, but it should be straightforward to define a MyFromTraversable such that MyFromTraversable.Aux[LUB, Out] does exactly what you want.