diff --git a/README.md b/README.md index 0f456c3..08582b6 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ The tupling of the type parameters works the same way as for path. There are two main built in query parameters that you can use as building blocks for most of yours needs: - `param[T](paramName: String)`: represents the value of the parameter with name `paramName` as a type `T` element +- `param[T](paramName: String).?`: optional param, with value encoded as `Option[T]` - `listParam[T](paramName: Strig)`: same as `param` but for lists. #### Query parameters examples diff --git a/shared/src/main/scala/urldsl/vocabulary/Param.scala b/shared/src/main/scala/urldsl/vocabulary/Param.scala index 50ec5eb..c5a0869 100644 --- a/shared/src/main/scala/urldsl/vocabulary/Param.scala +++ b/shared/src/main/scala/urldsl/vocabulary/Param.scala @@ -14,7 +14,8 @@ object Param { .map(_.split("=").toList) .toList .collect { - case first :: second :: Nil => first -> second + case first :: Nil if first.nonEmpty => first -> "" + case first :: second :: Nil if first.nonEmpty => first -> second } .groupBy(_._1) .map { case (key, value) => key -> value.map(_._2) } diff --git a/shared/src/test/scala/urldsl/examples/QueryParamsExamples.scala b/shared/src/test/scala/urldsl/examples/QueryParamsExamples.scala index d3409b9..1b2748d 100644 --- a/shared/src/test/scala/urldsl/examples/QueryParamsExamples.scala +++ b/shared/src/test/scala/urldsl/examples/QueryParamsExamples.scala @@ -53,6 +53,11 @@ final class QueryParamsExamples extends AnyFlatSpec with Matchers { */ param[String]("does-not-exist").?.matchRawUrl(sampleUrl) should be(Right(None)) param[String]("bar").?.matchRawUrl(sampleUrl) should be(Right(Some("stuff"))) + param[String]("empty").?.matchRawUrl(sampleUrl) should be(Right(Some(""))) + + /** Decoding failures on optional params result in None */ + param[Int]("bar").?.matchRawUrl(sampleUrl) should be(Right(None)) + param[Int]("empty").?.matchRawUrl(sampleUrl) should be(Right(None)) /** * [[urldsl.language.QueryParameters]] have a filter method allowing to restrict the things it matches. diff --git a/shared/src/test/scala/urldsl/examples/package.scala b/shared/src/test/scala/urldsl/examples/package.scala index 290b68e..234a192 100644 --- a/shared/src/test/scala/urldsl/examples/package.scala +++ b/shared/src/test/scala/urldsl/examples/package.scala @@ -10,7 +10,7 @@ package urldsl * url-dsl for generating urls, and not for parsing them. */ package object examples { - val sampleUrl = "http://www.some-domain.be/foo/23/true?bar=stuff&babar=other%20stuff&other=2&other=3&ok=true#the-ref" + val sampleUrl = "http://www.some-domain.be/foo/23/true?bar=stuff&babar=other%20stuff&other=2&other=3&empty=&ok=true#the-ref" val sampleUrlWithoutFragment = "http://www.some-domain.be/foo/23/true?bar=stuff&babar=other%20stuff&other=2&other=3&ok=true" } diff --git a/shared/src/test/scala/urldsl/language/QueryParamsUrlSpec.scala b/shared/src/test/scala/urldsl/language/QueryParamsUrlSpec.scala index 1b525d7..ed7041d 100644 --- a/shared/src/test/scala/urldsl/language/QueryParamsUrlSpec.scala +++ b/shared/src/test/scala/urldsl/language/QueryParamsUrlSpec.scala @@ -24,6 +24,12 @@ final class QueryParamsUrlSpec extends AnyFlatSpec with Matchers { listParam[String]("names").params(List("Alice", "Bob")) should be("names=Alice&names=Bob") + (param[String]("name") & param[Int]("age").?).params("Hello", None) should be("name=Hello") + (param[String]("name") & param[Int]("age").?).params("Hello", Some(0)) should be("name=Hello&age=0") + (param[String]("name") & param[Int]("age").?).params("Hello", Some(1)) should be("name=Hello&age=1") + (param[String]("name") & param[String]("cat").?).params("Hello", Some("")) should be("name=Hello&cat=") + (param[String]("name") & param[String]("cat").?).params("Hello", Some("Fluffy")) should be("name=Hello&cat=Fluffy") + // demonstrates quasi commutativity (listParam[Int]("ages") & param[String]("name")).params(List(32, 23), "Bob") should be( "ages=32&ages=23&name=Bob"