Skip to content

Commit

Permalink
QueryOps (#2671)
Browse files Browse the repository at this point in the history
Add `QueryOps` to follow the same pattern as `HeaderOps` (#2662)

This enables calling query parameter operators on `Request` directly
  • Loading branch information
987Nabil authored Feb 12, 2024
1 parent 2a24447 commit fb21d14
Show file tree
Hide file tree
Showing 17 changed files with 326 additions and 188 deletions.
5 changes: 5 additions & 0 deletions docs/migration/RC4-to-xx.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@

**QueryParam**
- renamed all methods that return typed params from `as` to `to`
- to align with header and to offer operations for query parameters directly on the `Request`,
the methods are now called `queryParam` instead of `get` and `queryParams` instead of `getAll`

**URL**
- renamed `queryParams` to `setQueryParams`
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class EndpointBenchmark {
val collectHttpApp = Routes(
Method.GET / "users" / int("userId") / "posts" / int("postId") -> handler {
(userIdInt: Int, postIdInt: Int, req: Request) =>
val query = req.url.queryParams.get("query").get
val query = req.url.queryParam("query").get

Response.json(ExampleData(userIdInt, postIdInt, query).toJson)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ private[cli] final case class CliRequest(
self.copy(url = self.url.copy(path = self.url.path / value))

def addQueryParam(key: String, value: String) =
self.copy(url = self.url.queryParams(self.url.queryParams.add(key, value)))
self.copy(url = self.url.setQueryParams(self.url.queryParams.addQueryParam(key, value)))

def method(method: Method): CliRequest =
self.copy(method = method)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,6 @@ object EndpointGenSpec extends ZIOSpecDefault {
val endpoint = Endpoint(Method.POST / "api" / "v1" / "users").in[UserNameArray].out[User]
val openAPI = OpenAPIGen.fromEndpoints("", "", endpoint)
val scala = EndpointGen.fromOpenAPI(openAPI)
println(openAPI.toJsonPretty)
val expected = Code.File(
List("api", "v1", "Users.scala"),
pkgPath = List("api", "v1"),
Expand Down
60 changes: 30 additions & 30 deletions zio-http/jvm/src/test/scala/zio/http/QueryParamsSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ object QueryParamsSpec extends ZIOHttpSpec {
)

checkAll(gens) { case (initialQueryParams, keyToRemove, expectedResult) =>
val actualResult = initialQueryParams.remove(keyToRemove)
val actualResult = initialQueryParams.removeQueryParam(keyToRemove)
assert(actualResult)(equalTo(expectedResult))
}
},
Expand All @@ -71,7 +71,7 @@ object QueryParamsSpec extends ZIOHttpSpec {
)

checkAll(gens) { case (initialQueryParams, key1, key2, otherKeysToRemove, expectedResult) =>
val actualResult = initialQueryParams.removeAll(key1 :: key2 :: (otherKeysToRemove.toList))
val actualResult = initialQueryParams.removeQueryParams(key1 :: key2 :: (otherKeysToRemove.toList))
assert(actualResult)(equalTo(expectedResult))
}
},
Expand Down Expand Up @@ -114,7 +114,7 @@ object QueryParamsSpec extends ZIOHttpSpec {
)

checkAll(gens) { case (initial, key, value, expected) =>
val actual = initial.add(key, value)
val actual = initial.addQueryParam(key, value)
assert(actual)(equalTo(expected))
}
},
Expand All @@ -137,7 +137,7 @@ object QueryParamsSpec extends ZIOHttpSpec {
)

checkAll(gens) { case (initial, key, value, expected) =>
val actual = initial.addAll(key, value)
val actual = initial.addQueryParams(key, value)
assert(actual)(equalTo(expected))
}
},
Expand Down Expand Up @@ -239,14 +239,14 @@ object QueryParamsSpec extends ZIOHttpSpec {
val unknown = "non-existent"
val queryParams = QueryParams(name -> "a", name -> "b")
assertTrue(
queryParams.get(name).get == "a",
queryParams.get(unknown).isEmpty,
queryParams.getOrElse(name, default) == "a",
queryParams.getOrElse(unknown, default) == default,
queryParams.getAll(name).get.length == 2,
queryParams.getAll(unknown).isEmpty,
queryParams.getAllOrElse(name, Chunk(default)).length == 2,
queryParams.getAllOrElse(unknown, Chunk(default)).length == 1,
queryParams.queryParam(name).get == "a",
queryParams.queryParam(unknown).isEmpty,
queryParams.queryParamOrElse(name, default) == "a",
queryParams.queryParamOrElse(unknown, default) == default,
queryParams.queryParams(name).length == 2,
queryParams.queryParams(unknown).isEmpty,
queryParams.queryParamsOrElse(name, Chunk(default)).length == 2,
queryParams.queryParamsOrElse(unknown, Chunk(default)).length == 1,
)
},
),
Expand All @@ -258,25 +258,25 @@ object QueryParamsSpec extends ZIOHttpSpec {
val unknown = "non-existent"
val queryParams = QueryParams(typed -> "1", typed -> "2", invalidTyped -> "str")
assertTrue(
queryParams.getTo[Int](typed) == Right(1),
queryParams.getTo[Int](invalidTyped).isLeft,
queryParams.getTo[Int](unknown).isLeft,
queryParams.getToOrElse[Int](typed, default) == 1,
queryParams.getToOrElse[Int](invalidTyped, default) == default,
queryParams.getToOrElse[Int](unknown, default) == default,
queryParams.getAllTo[Int](typed).map(_.length) == Right(2),
queryParams.getAllTo[Int](invalidTyped).isLeft,
queryParams.getAllTo[Int](unknown).isLeft,
queryParams.getAllToOrElse[Int](typed, Chunk(default)).length == 2,
queryParams.getAllToOrElse[Int](invalidTyped, Chunk(default)).length == 1,
queryParams.getAllToOrElse[Int](unknown, Chunk(default)).length == 1,
queryParams.queryParamTo[Int](typed) == Right(1),
queryParams.queryParamTo[Int](invalidTyped).isLeft,
queryParams.queryParamTo[Int](unknown).isLeft,
queryParams.queryParamToOrElse[Int](typed, default) == 1,
queryParams.queryParamToOrElse[Int](invalidTyped, default) == default,
queryParams.queryParamToOrElse[Int](unknown, default) == default,
queryParams.queryParamsTo[Int](typed).map(_.length) == Right(2),
queryParams.queryParamsTo[Int](invalidTyped).isLeft,
queryParams.queryParamsTo[Int](unknown).isLeft,
queryParams.queryParamsToOrElse[Int](typed, Chunk(default)).length == 2,
queryParams.queryParamsToOrElse[Int](invalidTyped, Chunk(default)).length == 1,
queryParams.queryParamsToOrElse[Int](unknown, Chunk(default)).length == 1,
)
assertZIO(queryParams.getToZIO[Int](typed))(equalTo(1)) &&
assertZIO(queryParams.getToZIO[Int](invalidTyped).exit)(fails(anything)) &&
assertZIO(queryParams.getToZIO[Int](unknown).exit)(fails(anything)) &&
assertZIO(queryParams.getAllToZIO[Int](typed))(hasSize(equalTo(2))) &&
assertZIO(queryParams.getAllToZIO[Int](invalidTyped).exit)(fails(anything)) &&
assertZIO(queryParams.getAllToZIO[Int](unknown).exit)(fails(anything))
assertZIO(queryParams.queryParamToZIO[Int](typed))(equalTo(1)) &&
assertZIO(queryParams.queryParamToZIO[Int](invalidTyped).exit)(fails(anything)) &&
assertZIO(queryParams.queryParamToZIO[Int](unknown).exit)(fails(anything)) &&
assertZIO(queryParams.queryParamsToZIO[Int](typed))(hasSize(equalTo(2))) &&
assertZIO(queryParams.queryParamsToZIO[Int](invalidTyped).exit)(fails(anything)) &&
assertZIO(queryParams.queryParamsToZIO[Int](unknown).exit)(fails(anything))
},
),
suite("encode - decode")(
Expand Down
4 changes: 2 additions & 2 deletions zio-http/jvm/src/test/scala/zio/http/URLSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ object URLSpec extends ZIOHttpSpec {
.path("/list")
.port(8080)
.scheme(Scheme.HTTPS)
.queryParams("?type=builder&query=provided")
.setQueryParams("?type=builder&query=provided")

assertTrue(builderUrl == asURL("https://www.abc.com:8080/list?type=builder&query=provided"))
},
test("returns relative URL if port, host, and scheme are not set") {
val actual = URL.empty
.path(Path.decode("/list"))
.queryParams(QueryParams("query" -> Chunk("provided"), "type" -> Chunk("builder")))
.setQueryParams(QueryParams("query" -> Chunk("provided"), "type" -> Chunk("builder")))
.encode

assertTrue(asURL(actual) == asURL("/list?query=provided&type=builder"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ object HttpCodecSpec extends ZIOHttpSpec {

val isAge = "isAge"
val codecBool = QueryCodec.queryBool(isAge)
def makeRequest(paramValue: String) = Request.get(googleUrl.queryParams(QueryParams(isAge -> paramValue)))
def makeRequest(paramValue: String) = Request.get(googleUrl.setQueryParams(QueryParams(isAge -> paramValue)))

def spec = suite("HttpCodecSpec")(
suite("fallback") {
Expand Down Expand Up @@ -161,8 +161,8 @@ object HttpCodecSpec extends ZIOHttpSpec {
test("paramBool encoding") {
val requestTrue = codecBool.encodeRequest(true)
val requestFalse = codecBool.encodeRequest(false)
assert(requestTrue.url.queryParams.get(isAge).get)(Assertion.equalTo("true")) &&
assert(requestFalse.url.queryParams.get(isAge).get)(Assertion.equalTo("false"))
assert(requestTrue.url.queryParams.queryParam(isAge).get)(Assertion.equalTo("true")) &&
assert(requestFalse.url.queryParams.queryParam(isAge).get)(Assertion.equalTo("false"))
},
) +
suite("Codec with examples") {
Expand Down
4 changes: 2 additions & 2 deletions zio-http/shared/src/main/scala/zio/http/Form.scala
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ final case class Form(formData: Chunk[FormField]) {

def toQueryParams: QueryParams =
formData.foldLeft(QueryParams.empty) {
case (acc, FormField.Text(k, v, _, _)) => acc.add(k, v)
case (acc, FormField.Simple(k, v)) => acc.add(k, v)
case (acc, FormField.Text(k, v, _, _)) => acc.addQueryParam(k, v)
case (acc, FormField.Simple(k, v)) => acc.addQueryParam(k, v)
case (acc, _) => acc
}

Expand Down
Loading

0 comments on commit fb21d14

Please sign in to comment.