Last active
February 29, 2020 16:42
-
-
Save ahoy-jon/9b55ede1fb838844319140321d285705 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
sealed trait Path | |
case class Field(name: String, child: Option[Path]) extends Path { | |
override def toString: String = child match { | |
case None => name | |
case Some(path) => s"$name.$path" | |
} | |
} | |
/** | |
* Path for option : Person(name:String, **age:Option[Int]**) | |
* | |
* @param child | |
*/ | |
case class OptPath(child: Path) extends Path { | |
override def toString: String = s"?.$child" | |
} | |
case class SeqPath(child: Path) extends Path { | |
override def toString: String = s"[].$child" | |
} | |
trait Destruct[X] { | |
def fields: Seq[Path] | |
} | |
object Destruct { | |
type Typeclass[X] = Destruct[X] | |
def apply[T: Typeclass]: Typeclass[T] = implicitly | |
private def instance[X](fields: Seq[Path]): Typeclass[X] = { | |
val _f = fields | |
new Typeclass[X] { | |
override def fields: Seq[Path] = _f | |
} | |
} | |
implicit def optDestruct[T: Destruct]: Destruct[Option[T]] = instance(Destruct[T].fields.map(OptPath)) | |
implicit def seqDestruct[T: Destruct]: Destruct[Seq[T]] = instance(Destruct[T].fields.map(SeqPath)) | |
def plop[T]: Typeclass[T] = instance(Nil) | |
implicit val intDestruct: Typeclass[Int] = plop | |
implicit val stringDestruct: Typeclass[String] = plop | |
implicit val booleanDestruct: Typeclass[Boolean] = plop | |
// ... | |
/** 🎶 Les magnolias sont toujours là 🎶 **/ | |
import magnolia._ | |
import scala.language.experimental.macros | |
def combine[A](ctx: CaseClass[Typeclass, A]): Destruct[A] = instance( | |
ctx.parameters.flatMap(param => { | |
param.typeclass.fields match { | |
case fields if fields.isEmpty => Seq(Field(param.label, None)) | |
case fields => fields.map(f => Field(param.label, Some(f))) | |
} | |
}) | |
) | |
implicit def gen[A]: Destruct[A] = macro Magnolia.gen[A] | |
implicit class DestructOps[CC <: Product](cc: CC)(implicit XXX: Destruct[CC]) { | |
def fields: Seq[Path] = XXX.fields | |
} | |
} | |
object Prg { | |
def main(args: Array[String]): Unit = { | |
import Destruct._ | |
case class Foo(i: Int, b: Boolean) | |
//via ops | |
println(Foo(1, true).fields) | |
/* | |
ArrayBuffer(i, b) | |
*/ | |
case class Address(city: String, country: String) | |
case class Person(name: String, address: Option[Address]) | |
println(Destruct[Person].fields) | |
/* | |
ArrayBuffer(name, address.?.city, address.?.country) | |
*/ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment