Turning a string into a sealed trait using scala chimney

Viewed 583
sealed trait Mode
object Mode {
  case object On extends Mode
  case object Off extends Mode
}

import io.scalaland.chimney.dsl._
"On".into[Mode].?????

I've tried using withCoproductInstance but i am not finding the right path

2 Answers

What you do is not a type-based, automatic transformation between 2 data models that are ADTs (case class or sealed), java beans, etc or collections of such, generated safely in compile-time

It is a String parsing. (Done on runtime, so it can possibly fail). If you are parsing enums' names into enum's values often, I suggest using enumeratum (it supports many other operations on enums as well)

import enumeratum._

sealed trait Mode extends EnumEntry

object Mode extends Enum[Mode] {
  val values = findValues

  case object On  extends Mode
  case object Off extends Mode
}

Mode.withName("On")

This is simply not Chimney use case - and I say it as one of Chimney's co-authors.

Alternatively, if you don't want to modify your existing code, you can derive a type class for handling all kinds of enums implementations using enumz (disclaimer, I wrote the thing)

io.scalaland.enumz.Enum

Enum[Mode].withName("On")

Out of box Chimney seems to transform case classes to case classes and sealed trait hierarchies to sealed trait hierarchies, not strings to sealed trait hierarchies. You can write a macro or use Shapeless.

"On".transformInto[Mode]

//Error:Chimney can't derive transformation from String to App.Mode
//App.Mode
//  derivation from string: java.lang.String to App.Mode is not supported in Chimney!
//Consult https://scalalandio.github.io/chimney for usage examples.

import shapeless.ops.union.Selector
import shapeless.{Coproduct, LabelledGeneric}

def selectByName[A] = new PartiallyApplied[A]

class PartiallyApplied[A] {
  def apply[C <: Coproduct, S <: Symbol, V](s: S)(implicit
    gen: LabelledGeneric.Aux[A, C],
    sel: Selector.Aux[C, S, V],
    witness: ValueOf[V]
  ): V = witness.value
}

selectByName[Mode](toSymbol("On")) // On

import scala.reflect.macros.whitebox

def toSymbol(s: String): Symbol = macro impl

def impl(c: whitebox.Context)(s: c.Tree): c.Tree = {
  import c.universe._
  q"""
     import _root_.shapeless.syntax.singleton._
     _root_.scala.Symbol.apply($s).narrow
   """
}
Related