Skip to content

Instantly share code, notes, and snippets.

@ovechkin-dm
Created February 24, 2015 09:40
Show Gist options
  • Save ovechkin-dm/7b566ae66dca6f8832e9 to your computer and use it in GitHub Desktop.
Save ovechkin-dm/7b566ae66dca6f8832e9 to your computer and use it in GitHub Desktop.
Request get required parameters with shapeless
import scala.util.Try
import shapeless._
object ReqOps extends App {
trait ParamMapper[A <: HList, R <: HList] {
def map(hl: A): R
}
trait ParamChecker[A <: HList] {
def check(all: List[String], failed: Boolean, rest: A): Unit
}
implicit def nilChecker = new ParamChecker[HNil] {
def check(all: List[String], failed: Boolean, rest: HNil): Unit = if (failed) throw new Exception( s"""required params are: ${all.mkString(",")}""")
}
implicit def consChecker[P, A <: HList](implicit tChecker: ParamChecker[A]) = new ParamChecker[ReqParam[P] :: A] {
def check(all: List[String], failed: Boolean, rest: ReqParam[P] :: A): Unit = {
val empty = rest.head.value.isEmpty
tChecker.check(rest.head.name :: all, empty || failed, rest.tail)
}
}
implicit def nilParamMapper = new ParamMapper[HNil, HNil] {
def map(hl: HNil): HNil = HNil
}
implicit def consParamMapper[H, T <: HList, TOUT <: HList](implicit tmap: ParamMapper[T, TOUT]): ParamMapper[ReqParam[H] :: T, H :: TOUT] =
new ParamMapper[ReqParam[H] :: T, H :: TOUT] {
def map(hl: ReqParam[H] :: T): H :: TOUT = hl.head.value.get :: tmap.map(hl.tail)
}
trait ParamParser[A] {
def parse(s: String): A
}
implicit def intParser: ParamParser[Int] = new ParamParser[Int] {
def parse(s: String): Int = s.toInt
}
implicit def stringParser: ParamParser[String] = new ParamParser[String] {
def parse(s: String): String = s
}
case class ReqParam[T](name: String, value: Option[T])
case class Request(params: Map[String, String]) {
def getRequiredParams[A <: HList, R <: HList](a: A)(implicit checker: ParamChecker[A], mapper: ParamMapper[A, R]): R = {
checker.check(Nil, false, a)
mapper.map(a)
}
def asParam[A](s: String)(implicit p: ParamParser[A]): ReqParam[A] = {
ReqParam(s, Try(p.parse(params(s))).toOption)
}
}
val rawParams = Map(("1" -> "123"), ("2" -> "test"))
val req = Request(rawParams)
val h = req.asParam[Int]("1") :: req.asParam[String]("2") :: HNil
req.getRequiredParams(h) match {
case first :: second :: _ =>
println(first) // 123, type Int at compile
println(second) // test, type String at compile
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment