Created
April 12, 2019 12:03
-
-
Save stsatlantis/0ceef15f46136989cc351838f6c5fced to your computer and use it in GitHub Desktop.
Circe Parent encoder
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
package object parent { | |
final def deriveEncoderWithParentFields[A](implicit encode: Lazy[ParentObjectEncoder[A]]): ObjectEncoder[A] = encode.value | |
} |
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 shapeless.HList | |
trait ParentEncoder[-T] { | |
type Repr <: HList | |
def to(t: T): Repr | |
} | |
object ParentEncoder { | |
type Aux[T, Repr0] = ParentEncoder[T] {type Repr = Repr0} | |
} |
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 io.circe.{JsonObject, ObjectEncoder} | |
import io.circe.generic.encoding.ReprObjectEncoder | |
import shapeless.{HList, LabelledGeneric, Lazy} | |
import shapeless.ops.record.{Merger, Remover} | |
abstract class ParentObjectEncoder[A] extends ObjectEncoder[A] | |
object ParentObjectEncoder { | |
implicit def materializeProduct[ | |
P, | |
K, | |
EL <: HList, | |
T <: P, | |
V <: HList, | |
RO <: HList]( | |
implicit | |
gen: LabelledGeneric.Aux[T, V], | |
evGen: ParentEncoder.Aux[P, EL], | |
merger: Merger.Aux[EL, V, RO], | |
remover: Remover.Aux[RO, K, V] | |
): LabelledGeneric.Aux[T, RO] = | |
new LabelledGeneric[T] { | |
type Repr = RO | |
def to(t: T): Repr = merger(evGen.to(t), gen.to(t)) | |
override def from(r: RO): T = gen.from(remover(r)) | |
} | |
implicit def deriveEncoder[A <: P, R <: HList, P, PR <: HList, Out <: HList](implicit | |
gen: LabelledGeneric.Aux[A, R], | |
pgen: ParentEncoder.Aux[P, PR], | |
merger: Merger.Aux[PR, R, Out], | |
encode: Lazy[ReprObjectEncoder[Out]] | |
): ParentObjectEncoder[A] = new ParentObjectEncoder[A] { | |
final def encodeObject(a: A): JsonObject = encode.value.encodeObject(merger(pgen.to(a), gen.to(a))) | |
} | |
} |
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 io.circe.{Decoder, Encoder} | |
import io.circe.generic.semiauto._ | |
import io.inrab.circe.generic.extras.parent._ | |
import shapeless._ | |
import labelled.FieldType | |
import syntax.singleton._ | |
import tag.@@ | |
sealed abstract class Event(override val `type`: String) extends Evnt | |
sealed trait Evnt extends Product with Serializable { | |
val `type`: String | |
} | |
final case class NameEvent(name: String) extends Event("name") | |
implicit val eventLGen = new ParentEncoder[Event] { | |
override type Repr = FieldType[Symbol @@ Witness.`"type"`.T, String] :: HNil | |
override def to(t: Event): Repr = ('type ->> t.`type`) :: HNil | |
} | |
implicit val nameEventEncoder: Encoder[NameEvent] = deriveEncoderWithParentFields[NameEvent] | |
implicit val nameEventDecoder: Decoder[NameEvent] = deriveDecoder[NameEvent] | |
val name = "Bobby" | |
val bobby = NameEvent(name) | |
val bobbyJson = Json.obj( | |
"name" -> Json.fromString(name), | |
"type" -> Json.fromString("name") | |
) | |
bobby.asJson shouldBe bobbyJson | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment