Skip to main content

chimney module

Import

import refined4s.modules.chimney.derivation.types.all.given
import refined4s.modules.chimney.derivation.*

Use Drived Instances for Pre-defined Types

To use Newtype, Refined and InlinedRefined with Chimney, you need to have type-class instances of Transformer[NewType, RawType] and PartialTransformer[RawType, NewType].

refined4s comes with them already.

import refined4s.modules.chimney.derivation.types.all.given
import refined4s.*
import refined4s.types.all.*

import io.scalaland.chimney
import io.scalaland.chimney.dsl.*

import refined4s.modules.chimney.derivation.types.all.given

final case class Person(name: NonEmptyString)

final case class User(name: NonEmptyString)

val person = Person(NonEmptyString("Wade Wilson"))
// person: Person = Person(name = "Wade Wilson")

person.intoPartial[User].transform
// res1: Result[User] = Value(value = User(name = "Wade Wilson"))

person.transformIntoPartial[User]
// res2: Result[User] = Value(value = User(name = "Wade Wilson"))

With Explicit Pre-defined Chimney Support

There are the following pre-defined traits to support chimney's Transformer and PartialTransformer

  • refined4s.modules.chimney.derivation.ChimneyNewtype
  • refined4s.modules.chimney.derivation.ChimneyRefined
import refined4s.*
import refined4s.modules.chimney.derivation.*

import io.scalaland.chimney.*
import io.scalaland.chimney.dsl.*

final case class Person(name: Person.Name)
object Person {
type Name = Name.Type
object Name extends Newtype[String], ChimneyNewtype[String]
}

final case class User(name: String)

final case class Member(name: Member.Name)
object Member {
type Name = Name.Type
object Name extends Newtype[String], ChimneyNewtype[String]
}

val person = Person(Person.Name("Wade Wilson"))
// person: Person = Person(name = "Wade Wilson")

Person.Name("Wade Wilson").into[String].transform
// res4: String = "Wade Wilson"

val deadpool = person.transformInto[User]
// deadpool: User = User(name = "Wade Wilson")

deadpool.transformInto[Person]
// res5: Person = Person(name = "Wade Wilson")

val member = person.transformInto[Member]
// member: Member = Member(name = "Wade Wilson")

member.transformInto[Person]
// res6: Person = Person(name = "Wade Wilson")
import refined4s.*
import refined4s.modules.chimney.derivation.*

import io.scalaland.chimney.*
import io.scalaland.chimney.dsl.*

final case class XMen(name: XMen.NotEmptyStr)
object XMen {
type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String], ChimneyRefined[String] {
inline def invalidReason(a: String): String = "non-empty String"

inline def predicate(a: String): Boolean = a != ""
}
}

final case class MarvelCharacter(name: String)

import refined4s.types.all.*

final case class Hero(name: Hero.Name)
object Hero {
type Name = Name.Type
object Name extends Newtype[NonEmptyString], ChimneyNewtype[NonEmptyString]
}

val logan = XMen(XMen.NotEmptyStr("James Howlett"))
// logan: XMen = XMen(name = "James Howlett")
val wolverine = logan.transformInto[MarvelCharacter]
// wolverine: MarvelCharacter = MarvelCharacter(name = "James Howlett")

wolverine.transformIntoPartial[XMen]
// res7: Result[XMen] = Value(value = XMen(name = "James Howlett"))

val hero = logan.transformIntoPartial[Hero]
// hero: Result[Hero] = Value(value = Hero(name = "James Howlett"))

With auto derivation

If you want to implicitly have Transformer and PartialTransformer type-class instances for your Newtype or Refined or InlinedRefined, you can use the refined4s.modules.chimney.derivation.generic.auto.

import cats.*

import refined4s.*
import refined4s.modules.chimney.derivation.generic.auto.given

import io.scalaland.chimney.*
import io.scalaland.chimney.dsl.*

type Name = Name.Type
object Name extends Newtype[String]

type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String] {
inline def invalidReason(a: String): String = "NonEmptyStr should be a non-empty String"

inline def predicate(a: String): Boolean = a != ""
}

final case class Person(name: Name)

final case class User(name: String)

final case class AnotherUser(name: NotEmptyStr)

val person = Person(Name("Wade Wilson"))
// person: Person = Person(name = "Wade Wilson")

person.into[User].transform
// res9: User = User(name = "Wade Wilson")

val user = person.transformInto[User]
// user: User = User(name = "Wade Wilson")

user.transformIntoPartial[Person]
// res10: Result[Person] = Value(value = Person(name = "Wade Wilson"))

val anotherUser = person.transformIntoPartial[AnotherUser]
// anotherUser: Result[AnotherUser] = Value(
// value = AnotherUser(name = "Wade Wilson")
// )

anotherUser.flatMap(_.transformIntoPartial[Person])
// res11: Result[Person] = Value(value = Person(name = "Wade Wilson"))

val personWithEmptyName = Person(Name(""))
// personWithEmptyName: Person = Person(name = "")

personWithEmptyName.transformInto[User]
// res12: User = User(name = "")

personWithEmptyName.transformIntoPartial[AnotherUser]
// res13: Result[AnotherUser] = Errors(
// errors = NonEmptyErrorsChain(
// Error(
// message = StringMessage(
// message = "Invalid value: []. NonEmptyStr should be a non-empty String"
// ),
// path = Path(elements = List(Accessor(name = "name")))
// )
// )
// )