Skip to content

Instantly share code, notes, and snippets.

@ahoy-jon
Created August 11, 2018 15:45
Show Gist options
  • Save ahoy-jon/02bc98a03f7484495a68390b61cf69ce to your computer and use it in GitHub Desktop.
Save ahoy-jon/02bc98a03f7484495a68390b61cf69ce to your computer and use it in GitHub Desktop.
import estrapade.{TestApp, test}
import magnolia._
import magnolia.tests.{Destination, Item, OffRoad, Path}
import scala.language.experimental.macros
sealed trait TC[A] {
def mapWithPrefix(prefix: String, value: A): Map[String, String] = {
this match {
case tcl: TCLeaf[A] => tcl.tl(value).fold(Map.empty[String, String])(x => Map(prefix -> x))
case tco: TCObject[A] => tco.tx(value).map({ case (k, v) => s"$prefix.$k" -> v })
}
}
}
trait TCObject[O] extends TC[O] {
def tx(obj: O): Map[String, String]
}
trait TCLeaf[L] extends TC[L] {
def tl(value: L): Option[String]
}
object TCMagnolia {
type Typeclass[T] = TC[T]
def combine[T](ctx: CaseClass[Typeclass, T]): TCObject[T] = (obj: T) => {
ctx.parameters
.flatMap(param => {
param.typeclass.mapWithPrefix(param.label, param.dereference(obj))
})
.toMap
}
def dispatch[T](ctx: SealedTrait[Typeclass, T]): TCObject[T] =
(obj: T) =>
ctx.dispatch(obj) { sub =>
sub.typeclass match {
case tco: TCObject[sub.SType] => tco.tx(sub.cast(obj))
case _ => ??? //illegal
}
}
implicit def gen[T]: TCObject[T] = macro Magnolia.gen[T]
}
object TestSubTypeclass extends TestApp {
def tests(): Unit = {
implicit val str: TCLeaf[String] = t => Some(t)
implicit val int: TCLeaf[Int] = t => Some(t.toString)
val path = OffRoad(Some(Destination(1)))
test("construct a TC product instance with coproduit of typeclass on a sealed trait") {
TCMagnolia.gen[Path[Int]].tx(path)
}.assert(_ == Map("path.value.value" -> "1"))
test("derived type classe") {
//Impl for option
def opt1[T](T: TCObject[T]): TCObject[Option[T]] = _.fold(Map.empty[String, String])(T.tx)
def opt2[T](T: TCLeaf[T]): TCLeaf[Option[T]] = _.flatMap(T.tl)
implicit def opt3[T](implicit T: TC[T]): TC[Option[T]] = {
T match {
case tcl: TCLeaf[T] => opt2[T](tcl)
case tco: TCObject[T] => opt1[T](tco)
}
}
implicit def destination[T: TC]: TCObject[Destination[T]] = (obj: Destination[T]) => {
implicitly[TC[T]].mapWithPrefix("destination", obj.value)
}
TCMagnolia.gen[Path[Int]].tx(path)
}.assert(_ == Map("path.destination" -> "1"))
test("construct a TC product instance with coproduct of typeclass") {
TCMagnolia.gen[Item].tx(Item("a", 1, 1))
}.assert(_ == Map("name" -> "a", "quantity" -> "1", "price" -> "1"))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment