Skip to content

Instantly share code, notes, and snippets.

@julienrf
Created April 26, 2012 20:47
Show Gist options
  • Save julienrf/2503029 to your computer and use it in GitHub Desktop.
Save julienrf/2503029 to your computer and use it in GitHub Desktop.
Write a Mapping[A] and get a QueryStringBindable[A] for free
// --- Definition of a query string binder for type A using a Mapping[A]
object Binders {
implicit def mappingBinder[A](implicit mapping: Mapping[A]) = new QueryStringBindable[A] {
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, A]] = {
val data = for {
(k, ps) <- params
if k startsWith key
p <- ps.headOption
} yield (k.drop(key.length + 1), p)
if (data.isEmpty) {
None
} else {
Some(mapping.bind(data.toMap).left.map(_ => "Unable to bind object for key '%s'".format(key)))
}
}
override def unbind(key: String, value: A): String = {
val (map, _) = mapping.unbind(value)
map.map { case (k, v) => key + "." + k + "=" + URLEncoder.encode(v, "utf-8") }.mkString("&")
}
}
}
// --- Usage
case class User(name: String, age: Int)
object User {
implicit val userMapping: Mapping[User] =
mapping(
"name"->nonEmptyText,
"age"->number.verifying(min(0))
)(User.apply)(User.unapply)
}
case class Pager(index: Int, size: Int)
object Pager {
implicit val pagerMapping: Mapping[Pager] =
mapping(
"index"->number,
"size"->number
)(Pager.apply)(Pager.unapply)
}
object Application extends Controller {
/* Example of request for the following action:
* http://foo.com/?user.name=Julien&user.age=26&pager.index=1&pager.size=42
*/
def index(user: User, pager: Pager) = Action {
Ok(views.html.index(user, pager))
}
}
@sadache
Copy link

sadache commented Apr 27, 2012

what about mappers using []?

@julienrf
Copy link
Author

Mappings containing inner repeated mappings should work (though I didn’t tested). E.g.:

/?foo.xs[0]=1&foo.xs[1]=2&foo.xs[2]=3

On the other hand, if you define a Mapping[Foo] and want to bind a List[Foo] on your controller action, your code will compile but the binding will always fail (I guess, I didn’t tested either).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment