Created
April 26, 2012 20:47
-
-
Save julienrf/2503029 to your computer and use it in GitHub Desktop.
Write a Mapping[A] and get a QueryStringBindable[A] for free
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
// --- 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)) | |
} | |
} |
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
what about mappers using []?