Created
August 11, 2018 15:45
-
-
Save ahoy-jon/02bc98a03f7484495a68390b61cf69ce to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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