Home > Enterprise >  Scala 3 - tuple from nested case class
Scala 3 - tuple from nested case class

Time:09-17

With scala 3 you can get a tuple from a case class using Tuple.fromProductTyped.

I'd like get all fields of nested case classes, example:

    case class Baz(x: String)
    case class Employee(name: Baz, number: Int, manager: Boolean)

    Tuple.fromProductTyped(Employee(Baz("hello"), 42, false))  // (Baz(hello),42,false) but I need (hello,42,false)

The code below tries to get the tuple of nested case classes but fails on row ***

no implicit argument of type deriving.Mirror.ProductOf[Product] was found for parameter m of method fromProductTyped in object Tuple
              val tuple2 = Tuple.fromProductTyped(x)
    trait RowEncoder[A] {
      def encodeRow(a: A): List[String]
    }

    def tupleToCsv[A <: Tuple: RowEncoder](tuple: A): List[String] = summon[RowEncoder[A]].encodeRow(tuple)

    case class Baz(x: String)
    case class Employee(name: Baz, number: Int, manager: Boolean)


    def flatTuple[A <: Tuple](tuple: A): Tuple = {
      tuple match {
        case x *: xs =>
          x match {
            case x: Product =>
              val tuple2 = Tuple.fromProductTyped(x) // *** 
              flatTuple(tuple2)    flatTuple(xs)
            case x => x *: flatTuple(xs)
          }
        case _ => EmptyTuple
      }
    }

    val tuple = Tuple.fromProductTyped(Employee(Baz("hello"), 42, false))
    println(flatTuple(tuple)) // expected: (hello,42,false)

To test replace x with Baz("hello") at row ***

how can I fix it?

CodePudding user response:

You have to use Tuple.fromProduct(x) instead of Tuple.fromProductTyped(x):

 def flatTuple[A <: Tuple](tuple: A): Tuple = {
  tuple match {
   case x *: xs =>
    x match {
     case x: Product =>
      val tuple2 = Tuple.fromProduct(x) // ***
      flatTuple(tuple2)    flatTuple(xs)
     case x => x *: flatTuple(xs)
    }
   case _ => EmptyTuple
  }
 }

CodePudding user response:

If you do not care the exact type of the return tuple, the following is enough:

scala> def flat(any: Any): Tuple = any match
     |   case p: Product => p.productIterator.map(flat).foldLeft(EmptyTuple: Tuple)(_    _)
     |   case a => Tuple1(a)
     |
def flat(any: Any): Tuple

scala> val flatTuple = flat(Employee(Baz("hello"), 42, false))
val flatTuple: Tuple = (hello,42,false)
  • Related