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

.uniform.common-web_2.13.5.0.0-RC6.source-code.InferWebAsk.scala Maven / Gradle / Ivy

The newest version!
package ltbs.uniform
package common.web

import magnolia._
import scala.language.experimental.macros
import cats.implicits._
import scala.language.higherKinds

trait InferWebAsk[Html] {

  @annotation.implicitAmbiguous("Unable to ask[Traversable[${A}]] - consider using askList[${A}] instead")
  implicit def blockCollections[X[_] <: Traversable[_], A]: WebAsk[Html, X[A]] = ???
  implicit def blockCollections2[X[_] <: Traversable[_], A]: WebAsk[Html, X[A]] = ???  

  def renderAnd[T](
    pageIn: PageIn[Html],
    stepDetails: StepDetails[Html, T],
    members: Seq[(String, Html)]
  ): Html

  def renderOr[T](
    pageIn: PageIn[Html],
    stepDetails: StepDetails[Html, T],
    alternatives: Seq[(String, Option[Html])],
    selected: Option[String]
  ): Html

  type Typeclass[T] = WebAsk[Html, T]

  def combine[T](caseClass: CaseClass[Typeclass, T]) = new WebAsk[Html, T] {
    def decode(out: Input): Either[ErrorTree,T] = {
      caseClass.constructEither {
        p => p.typeclass.decode(out / p.label).leftMap{_.prefixWith(p.label)}
      }.leftMap{_.combineAll}
    }
    def encode(in: T): Input = {
      val members = caseClass.parameters.map { p =>
        p.typeclass.encode(p.dereference(in)).prefixWith(p.label)
      }
      members.toList.combineAll
    }

    def render(
      pageIn: PageIn[Html],
      stepDetails: StepDetails[Html, T]
    ): Option[Html] = {
      import stepDetails._
    if (caseClass.isObject) None else 
    renderAnd(
      pageIn,
      stepDetails,
      caseClass.parameters.map {
        p => p.label -> p.typeclass.render(
          pageIn,
          stepDetails / p.label
        )
      }.collect{ case (k, Some(v)) => (k,v)}
    ).some
    }
  }
  
  def dispatch[T](sealedTrait: SealedTrait[Typeclass, T]): Typeclass[T] = new WebAsk[Html, T] {
    def decode(out: Input): Either[ErrorTree,T] = {
      sealedTrait.subtypes.collectFirst{
        case subtype if List(subtype.typeName.short).some === out.valueAtRoot =>
          subtype.typeclass.decode(out / subtype.typeName.short).leftMap{_.prefixWith(subtype.typeName.short)}
      }.getOrElse(ErrorMsg("required").toTree.asLeft)
    }

    def encode(in: T): Input = {
      sealedTrait.dispatch(in) { subtype =>
        subtype.typeclass.encode(subtype.cast(in)).prefixWith(subtype.typeName.short) |+|
        (Map(Nil -> List(subtype.typeName.short)): Input)
      } 
    }

    def render(
      pageIn: PageIn[Html],
      stepDetails: StepDetails[Html, T],
    ): Option[Html] = {
      import stepDetails._
      renderOr(
        pageIn,
        stepDetails,
        sealedTrait.subtypes.map{ subtype =>
          (
            subtype.typeName.short,
            {
              subtype.typeclass.render(
                pageIn,
                stepDetails / subtype.typeName.short
              )
            }
          )
        },
        sealedTrait.subtypes.collectFirst {
          case subtype if List(subtype.typeName.short).some === data.valueAtRoot =>
            subtype.typeName.short
        }
      )
    }.some
  }

  implicit def gen[T]: WebAsk[Html, T] = macro Magnolia.gen[T]
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy