Total vs partial conflicts

Under normal circumstances when fields or sealed hierarchy subtypes should be converted, Chimney should be able to generate code on its own. If it cannot you could provide it with derivation settings or implicit transformer handling problematic fields/subtypes.

It can use total transformers

import io.scalaland.chimney._
import io.scalaland.chimney.dsl._

case class UserAPI(credits: String)
case class User(credits: Int)

implicit val unsafeStringToInt: Transformer[String, Int] = _.toInt

UserAPI("10").transformIntoPartial[User].asOption // Some(User(10))

or partial transformer

import io.scalaland.chimney._
import io.scalaland.chimney.dsl._

case class UserAPI(credits: String)
case class User(credits: Int)

implicit val parseStringToInt: PartialTransformer[String, Int] =
  PartialTransformer[String, Int](str => partial.Result.fromCatching(str.toInt).map(_ * 2))

UserAPI("10").transformIntoPartial[User].asOption // Some(User(20))

But which implicit should be taken in this situation?

import io.scalaland.chimney._
import io.scalaland.chimney.dsl._

case class UserAPI(credits: String)
case class User(credits: Int)

implicit val unsafeStringToInt: Transformer[String, Int] = _.toInt

implicit val parseStringToInt: PartialTransformer[String, Int] =
  PartialTransformer[String, Int](str => partial.Result.fromCatching(str.toInt).map(_ * 2))

UserAPI("10").transformIntoPartial[User].asOption
// error: Ambiguous implicits while resolving Chimney recursive transformation:
//
//        PartialTransformer[String, Int]: parseStringToInt
//        Transformer[String, Int]: unsafeStringToInt

To avoid the ambiguity, Chimney would fail the derivation in such case and expect you to tell it, which transformer it should prefer: total or partial:

import io.scalaland.chimney._
import io.scalaland.chimney.dsl._

case class UserAPI(credits: String)
case class User(credits: Int)

implicit val unsafeStringToInt: Transformer[String, Int] = _.toInt

implicit val parseStringToInt: PartialTransformer[String, Int] =
  PartialTransformer[String, Int](str => partial.Result.fromCatching(str.toInt).map(_ * 2))

UserAPI("10").intoPartial[User]
  .enableImplicitConflictResolution(PreferTotalTransformer)
  .transform.asOption // Some(User(10))

UserAPI("10").intoPartial[User]
  .enableImplicitConflictResolution(PreferPartialTransformer)
  .transform.asOption // Some(User(20))