Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

shapeless case class conversion

i use shapeless for case class conversion, i have a 2 case class:

import shapeless._

case class Foo(id: Int, name: String)
case class Bar(id: Int, name: String, price: Double)

val fooGen = Generic[Foo]
val barGen = Generic[Bar]

val foo = Foo(1, "foo")
val fooRepr = fooGen.to(foo)
val additional = fooRepr :+ 1.0
val bar = barGen.from(additional)

This works fine, but when i try convert Bar to Foo

fooGen.from(barGen.to(bar))

i get an error:

found   : main.barGen.Repr
[error]     (which expands to)  shapeless.::[Int,shapeless.::    [String,shapeless.::[Double,shapeless.HNil]]]
[error]  required: main.fooGen.Repr
[error]     (which expands to)  shapeless.::[Int,shapeless.::[String,shapeless.HNil]]
[error]   println(fooGen.from(barGen.to(bar)))    

Is it possible convert one case class where more fields than in another?

like image 998
mike Avatar asked Mar 17 '16 20:03

mike


2 Answers

Similar to how you adjust the HList representation of Foo, by adding an element, you'd have to adjust the HList representation of Bar as well, by removing the extra element:

fooGen.from(barGen.to(bar).take(2))

take takes a Nat argument, and this line of code uses the implicit conversion from an Int literal to a Nat type-level natural number.

You can find other methods available on HLists in shapeless.syntax.hlists.scala.

like image 117
Kolmar Avatar answered Nov 15 '22 08:11

Kolmar


My answer is based on a previous answer by Travis Brown, for a somewhat similar question.

import shapeless._, ops.hlist._, ops.record._

class SameFieldConverter[T] {
    def apply[S, SR <: HList, TR <: HList, MR <: HList, IR <: HList](s: S)(implicit
      genS: LabelledGeneric.Aux[S, SR],
      genT: LabelledGeneric.Aux[T, TR],
      merger: Merger.Aux[SR, HNil, MR],
      intersection: Intersection.Aux[MR, TR, IR],
      align: Align[IR, TR]) = genT.from(intersection(merger(genS.to(s), HNil)))
  }
// defined class SameFieldConverter

def convertTo[T] = new SameFieldConverter[T]
//defined function convertTo

case class Foo(one: String, two: Int, three: Boolean)
// defined class Foo

case class Bar(three: Boolean, one: String)
// defined class Bar

convertTo[Bar](Foo("One", 2, false))
// res26: Bar = Bar(false, "One")
like image 28
Abel Terefe Avatar answered Nov 15 '22 07:11

Abel Terefe