All Downloads are FREE. Search and download functionalities are using the official Maven repository.

julienrf.json.derived.DerivedOWrites.scala Maven / Gradle / Ivy

There is a newer version: 6.0.0
Show newest version
package julienrf.json.derived

import play.api.libs.json.{JsValue, JsObject, Json, OWrites, Writes}
import shapeless.labelled.FieldType
import shapeless.{:+:, ::, CNil, Coproduct, HList, HNil, Inl, Inr, LabelledGeneric, Lazy, Witness}

trait DerivedOWrites[-A] {
  def owrites(tagOwrites: TypeTagOWrites): OWrites[A]
}

object DerivedOWrites extends DerivedOWritesInstances

trait DerivedOWritesInstances extends DerivedOWritesInstances1 {

  implicit val owritesHNil: DerivedOWrites[HNil] =
    new DerivedOWrites[HNil] {
      def owrites(tagOwrites: TypeTagOWrites) = OWrites[HNil] { _ => Json.obj() }
    }

  implicit def owritesLabelledHListOpt[A, K <: Symbol, H, T <: HList](implicit
    fieldName: Witness.Aux[K],
    owritesH: Lazy[Writes[H]],
    owritesT: Lazy[DerivedOWrites[T]]
  ): DerivedOWrites[FieldType[K, Option[H]] :: T] =
    new DerivedOWrites[FieldType[K, Option[H]] :: T] {
      def owrites(tagOwrites: TypeTagOWrites) =
        OWrites[FieldType[K, Option[H]] :: T] { case maybeH :: t =>
          val maybeField: Map[String, JsValue] =
            (maybeH: Option[H]) match {
              case Some(h) => Map(fieldName.value.name -> owritesH.value.writes(h))
              case None => Map.empty
            }
          JsObject(maybeField ++ owritesT.value.owrites(tagOwrites).writes(t).value)
        }
    }

  implicit val owritesCNil: DerivedOWrites[CNil] =
    new DerivedOWrites[CNil] {
      def owrites(tagOwrites: TypeTagOWrites): OWrites[CNil] = sys.error("No JSON representation of CNil")
    }

  implicit def owritesCoproduct[K <: Symbol, L, R <: Coproduct](implicit
    typeName: Witness.Aux[K],
    owritesL: Lazy[DerivedOWrites[L]],
    owritesR: Lazy[DerivedOWrites[R]]
  ): DerivedOWrites[FieldType[K, L] :+: R] =
    new DerivedOWrites[FieldType[K, L] :+: R] {
      def owrites(tagOwrites: TypeTagOWrites) = OWrites[FieldType[K, L] :+: R] {
        case Inl(l) => tagOwrites.owrites(typeName.value.name, owritesL.value.owrites(tagOwrites)).writes(l)
        case Inr(r) => owritesR.value.owrites(tagOwrites).writes(r)
      }
    }


}

trait DerivedOWritesInstances1 extends DerivedOWritesInstances2 {

  implicit def owritesLabelledHList[A, K <: Symbol, H, T <: HList](implicit
    fieldName: Witness.Aux[K],
    owritesH: Lazy[Writes[H]],
    owritesT: Lazy[DerivedOWrites[T]]
  ): DerivedOWrites[FieldType[K, H] :: T] =
    new DerivedOWrites[FieldType[K, H] :: T] {
      def owrites(tagOwrites: TypeTagOWrites) =
        OWrites[FieldType[K, H] :: T] { case h :: t =>
          JsObject(Map(fieldName.value.name -> owritesH.value.writes(h)) ++ owritesT.value.owrites(tagOwrites).writes(t).value)
        }
    }

}

trait DerivedOWritesInstances2 {

  implicit def owritesGeneric[A, R](implicit
    gen: LabelledGeneric.Aux[A, R],
    derivedOWrites: Lazy[DerivedOWrites[R]]
  ): DerivedOWrites[A] =
    new DerivedOWrites[A] {
      def owrites(tagOwrites: TypeTagOWrites) =
        OWrites.contravariantfunctorOWrites.contramap(derivedOWrites.value.owrites(tagOwrites), gen.to)
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy