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

Support SORT command in Keys API #302

Merged
merged 11 commits into from
Mar 9, 2021
Merged

Support SORT command in Keys API #302

merged 11 commits into from
Mar 9, 2021

Conversation

sloanesturz
Copy link
Contributor

Fixes #218.

SORT has two different response types:

SORT myKey # -> returns the sorted values in the list stored at myKey
SORT myKey STORE resultKey # -> returns the number of elements sorted, writes values to resultKey

This is not easily expressible in Scala, so I created two separate functions, one for SORT ... STORE ... and one for SORT ...

This is my first commit to zio-redis, please let me know if I am not following any important functional or stylistic guidelines!

@sloanesturz sloanesturz requested a review from a team as a code owner March 4, 2021 04:27
@CLAassistant
Copy link

CLAassistant commented Mar 4, 2021

CLA assistant check
All committers have signed the CLA.

Copy link
Member

@mijicd mijicd left a comment

Choose a reason for hiding this comment

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

@sloanesturz thank you for taking care of this! I left some general remarks, but more specifically, I don't think we should expose two separate commands. I would propose to:

  • apply the proposed fixes
  • represent missing terms (e.g. alpha)
  • unify commands into single sort

Please take a look at geo API, as there's quite a few options defined there, and it might serve as an "inspiration" here :).

final def sort(
key: String,
by: Option[String] = None,
limitOffset: Option[(Int, Int)] = None,
Copy link
Member

Choose a reason for hiding this comment

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

We have this defined among sorted sets (see here). I propose that you reuse it and move the option itself to shared options.

key: String,
by: Option[String] = None,
limitOffset: Option[(Int, Int)] = None,
desc: Boolean = false,
Copy link
Member

Choose a reason for hiding this comment

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

Order is defined as geo options here. Please do the same approach:

  • move to shared
  • use it instead of plain boolean

@sloanesturz
Copy link
Contributor Author

OK, thanks for the pointers to those options fields -- definitely more clean to use those instead of my approach. The pattern in the Geo package has a lot of overlap and is clearly the right way to go.

unify commands into single sort

What should the return type of this method be? If we SORT ... STORE ..., Redis will return a number. If we SORT ..., Redis will return a list of values. To unify these two I could always return a Chunk[String] and if you had happened to SORT ... STORE ... you just "have to know" that the Chunk[String] will have one entry, the number of values. To me, that seems pretty kludgy but I suppose it does sorta replicate what Redis is doing.

@mijicd
Copy link
Member

mijicd commented Mar 5, 2021

One option might be to define a custom response type (ADT of possible responses), but let's play around with this, perhaps something better pops up.

@sloanesturz
Copy link
Contributor Author

OK, let me take a crack at your first suggestions before taking on the second one. In my experience, returning an Either[Long, Seq[String]] that is fully is defined by the kinds of arguments to the function is probably not what we want here because you end up writing code like

redis.sort(key, storeAt = None).map {
  case _: Right => ??? // as a developer, I know this can't happen, annoying the compiler makes me handle this
  case _: Left =>  doMyImplementation() // the actual implementation I want to do
}

Comment on lines 316 to 329
def sortArguments(
by: Option[String],
limitOffset: Option[(Int, Int)],
desc: Boolean,
get: List[String],
alpha: Boolean
): List[String] =
by.map(sortBy => List("BY", sortBy)).getOrElse(List.empty) ++
limitOffset.map { case (count, offset) => List("LIMIT", offset.toString, count.toString) }
.getOrElse(List.empty) ++
get.flatMap(getAt => List("GET", getAt)) ++
List(if (desc) "DESC" else "ASC") ++
(if (alpha) List("ALPHA") else List.empty)

Copy link
Member

Choose a reason for hiding this comment

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

Should this be deleted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

Copy link
Member

@mijicd mijicd left a comment

Choose a reason for hiding this comment

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

Almost there! Since we opted for this approach of command per output (with a good reason, as you elaborated), do you mind doing a quick scan of the similar commands and filing them in an issue so that we can align the API? 🙏

@@ -126,6 +138,11 @@ object Input {
Chunk(encodeString("LIMIT"), encodeString(data.offset.toString), encodeString(data.count.toString))
}

final case class ListInput[-A](input: Input[A]) extends Input[List[A]] {
override private[redis] def encode(data: List[A]): Chunk[RespValue.BulkString] =
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
override private[redis] def encode(data: List[A]): Chunk[RespValue.BulkString] =
def encode(data: List[A]): Chunk[RespValue.BulkString] =

However, see the comment below, this might be unnecessary.

StringInput,
OptionalInput(ByInput),
OptionalInput(LimitInput),
ListInput(GetInput),
Copy link
Member

Choose a reason for hiding this comment

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

This can actually be changed to OptionalInput(NonEmptyList[GetInput]).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

clever!

@sloanesturz
Copy link
Contributor Author

Filed #306 for the GEO functions.

Copy link
Member

@mijicd mijicd left a comment

Choose a reason for hiding this comment

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

Nice work! 🚀

@mijicd mijicd merged commit a390a8b into zio:master Mar 9, 2021
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 sort command to the Keys api
3 participants