chimney icon indicating copy to clipboard operation
chimney copied to clipboard

bug: failed to transform coproduct with implicit transformer

Open andyczerwonka opened this issue 3 years ago • 3 comments

I get an error with what looks to be a pedestrian case.

import io.scalaland.chimney.Transformer
import io.scalaland.chimney.dsl._
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

sealed trait A extends Product with Serializable
object A {
  case class Foo(s: String) extends A
  case class Bar(kvs: Map[String, Int]) extends A
}

sealed trait B extends Product with Serializable // same structure as A
object B {
  case class Foo(s: String) extends B
  case class Bar(kvs: Map[String, Int]) extends B
}

sealed trait C extends Product with Serializable
object C {
  case class Foo(s: String) extends C
  case class Bar(keys: Seq[String], values: Seq[Int]) extends C
}

class TransformationTest extends AnyFunSuite with Matchers {

  implicit val barTransformer: Transformer[A.Bar, C.Bar] = aBar => {
    val (keys, values) = aBar.kvs.seq.unzip
    C.Bar(keys = keys.toSeq, values = values.toSeq)
  }

  case class Bag[T](xs: Seq[T])

  test("transforming a coproduct with identical structure") {
    val bagA = Bag(Seq(A.Foo("foo"), A.Bar(Map("bar" -> 1))))
    val bagB = bagA.transformInto[Bag[B]]
    succeed
  }

  test("transforming a coproduct with different structure") {
    val bagA = Bag(Seq(A.Foo("foo"), A.Bar(Map("bar" -> 1))))
    val bagC = bagA
      .into[Bag[C]]
      .withFieldComputed(_.xs, _.xs.transformInto[Seq[C]])
      .transform
    succeed
  }

}

A -> B works, but A -> C does not, even if I have a implicit transformer in scope. I get a Chimney can't derive transformation from Seq[A] to Seq[C]

image

andyczerwonka avatar Dec 15 '20 19:12 andyczerwonka

I think this is a fairly pedestrian case. I've added a Scastie if anyone want to have a look. https://scastie.scala-lang.org/andyczerwonka/NOfA4NXoTzuk5k4VQtjszA/10

andyczerwonka avatar Dec 15 '20 20:12 andyczerwonka

If I write a transformer manually, it works.

  implicit lazy val aToC: Transformer[A, C] = {
    case A.Foo(s) => C.Foo(s)
    case A.Bar(kvs) =>
      val (keys, values) = kvs.seq.unzip
      C.Bar(keys = keys.toSeq, values = values.toSeq)
  }

Feels like a defect.

andyczerwonka avatar Dec 15 '20 21:12 andyczerwonka

@krzemin just wondering if this issue is validated? Will this be part of an update?

andyczerwonka avatar Jan 08 '21 00:01 andyczerwonka

@andyczerwonka thank you for reproduction example :pray:

It was resolved in #261

krzemin avatar Mar 01 '23 17:03 krzemin