Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added getAs for QueryParams #2505

Merged
merged 5 commits into from
Nov 6, 2023
Merged

Conversation

BanyMaciej
Copy link
Contributor

@BanyMaciej BanyMaciej commented Nov 1, 2023

Add getAs[A] for QueryParams

Closes #2423

@CLAassistant
Copy link

CLAassistant commented Nov 1, 2023

CLA assistant check
All committers have signed the CLA.

@codecov-commenter
Copy link

codecov-commenter commented Nov 1, 2023

Codecov Report

Attention: 4 lines in your changes are missing coverage. Please review.

Comparison is base (1ee9701) 64.95% compared to head (dbaaac9) 64.95%.
Report is 1 commits behind head on main.

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2505      +/-   ##
==========================================
- Coverage   64.95%   64.95%   -0.01%     
==========================================
  Files         136      137       +1     
  Lines        7197     7211      +14     
  Branches     1296     1312      +16     
==========================================
+ Hits         4675     4684       +9     
- Misses       2522     2527       +5     
Files Coverage Δ
zio-http/src/main/scala/zio/http/QueryParams.scala 84.78% <83.33%> (-0.52%) ⬇️
...ttp/src/main/scala/zio/http/QueryParamsError.scala 0.00% <0.00%> (ø)

... and 1 file with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

/**
* Retrieves the first typed query parameter value having the specified name.
*/
def getAs[A](key: String)(implicit codec: TextCodec[A]): Option[A] = get(key).flatMap(codec.decode)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there could be needs to distinguish between the absence of the parameter and decoding failure. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good point, but I'm afraid that if we have output type like Either[String, Option[A]] or Option[Either[String, A]], it may be even harder to use than separating it to get and decode on the call site. Maybe I should define separate typed error for this, something like DecodingError and NotFoundError and then result would be Either[QueryParamError, A]?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with your concern. Personally I'd prefer the latter.

* Retrieves the first typed query parameter value having the specified name.
*/
def getAs[A](key: String)(implicit codec: TextCodec[A]): Either[QueryParamsError, A] = for {
param <- get(key).toRight(QueryParamsError.MissingQueryParam(key))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! QueryParamsError.Missing seems more readable to me. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems logical :)

@@ -18,9 +18,10 @@ package zio.http

import java.nio.charset.Charset

import zio.Chunk
import zio.{Chunk, NonEmptyChunk}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NonEmptyChunk is unused or?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right - I left some unused imports, I would fix it

/**
* Retrieves the first typed query parameter value having the specified name.
*/
def getAs[A](key: String)(implicit codec: TextCodec[A]): Either[QueryParamsError, A] = for {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering, if a def getAsZIO[A](key: String)(implicit codec: TextCodec[A]): IO[QueryParamsError, A] makes sense too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't wrapping it in ZIO to heavy machinery for this task? I believe calling it like ZIO.fromEither(queryParams.getAs ...) is not much trouble, and current version could be possibly used in some lower level implementations :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe there could be a significant gain in readability at the cost of a minor performance overhead. Keeping getAs as is and adding getAsZIO as a variant seems consistent with existing ZIO functions like ZIO.serviceWith and ZIO.serviceWithZIO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explaining :) You are right, I will add additional functions

@987Nabil 987Nabil merged commit 40c2961 into zio:main Nov 6, 2023
14 checks passed
Copy link
Contributor

@guersam guersam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for late, added my two cents over the error ADT.

def message: String
}
object QueryParamsError {
final case class Missing(queryParamName: String) extends QueryParamsError {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing#queryParamName seems inconsistent with Malformed#name.

def message = s"Unable to decode query parameter with name $name and value $value using $codec"
}

final case class MultiMalformed(chunk: Chunk[Malformed]) extends QueryParamsError {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't name and codec the same across the entire chunk in a MultiMalformed? If so, I'd suggest an another encoding:

final case class MultiMalformed(name: String, codec: `TextCodec[_]`, values: Chunk[String]) extends QueryParamsError

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, then we could get rid of the "single' Malformed - it could be represented as MultiMalformed (then I will rename it to Malformed) with one element chunk. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 NonEmptyChunk could give more guarantee here.

}

final case class Malformed(name: String, value: String, codec: TextCodec[_]) extends QueryParamsError {
def message = s"Unable to decode query parameter with name $name and value $value using $codec"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt that TextCodec always provides stable toString. codec.describe might be more reliable choice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is true.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add getAs[T] to QueryParams for typed query parameter access
5 participants