-
Notifications
You must be signed in to change notification settings - Fork 66
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
Go: ZRANGE #2925
Merged
Merged
Go: ZRANGE #2925
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
e260ce7
ZRANGE
Yury-Fridlyand 780967b
Merge remote-tracking branch 'upstream/main' into go/zrange
Yury-Fridlyand 0d940e3
refactor
Yury-Fridlyand 49a1b3f
Merge branch 'main' into go/zrange
Yury-Fridlyand 065c3f1
Address PR comments.
Yury-Fridlyand File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 | ||
|
||
package options | ||
|
||
import ( | ||
"github.com/valkey-io/valkey-glide/go/glide/utils" | ||
) | ||
|
||
// Query for `ZRange` in [SortedSetCommands] | ||
// - For range queries by index (rank), use `RangeByIndex`. | ||
// - For range queries by lexicographical order, use `RangeByLex`. | ||
// - For range queries by score, use `RangeByScore`. | ||
type ZRangeQuery interface { | ||
ToArgs() []string | ||
} | ||
|
||
// Queries a range of elements from a sorted set by theirs index. | ||
type RangeByIndex struct { | ||
start, end int64 | ||
reverse bool | ||
} | ||
|
||
// Queries a range of elements from a sorted set by theirs score. | ||
type RangeByScore struct { | ||
start, end scoreBoundary | ||
reverse bool | ||
Limit *Limit | ||
} | ||
|
||
// Queries a range of elements from a sorted set by theirs lexicographical order. | ||
type RangeByLex struct { | ||
start, end lexBoundary | ||
reverse bool | ||
Limit *Limit | ||
} | ||
|
||
type ( | ||
InfBoundary string | ||
scoreBoundary string | ||
lexBoundary string | ||
) | ||
|
||
const ( | ||
// The highest bound in the sorted set | ||
PositiveInfinity InfBoundary = "+" | ||
// The lowest bound in the sorted set | ||
NegativeInfinity InfBoundary = "-" | ||
) | ||
|
||
// Create a new inclusive score boundary. | ||
func NewInclusiveScoreBoundary(bound float64) scoreBoundary { | ||
return scoreBoundary(utils.FloatToString(bound)) | ||
} | ||
|
||
// Create a new score boundary. | ||
func NewScoreBoundary(bound float64, isInclusive bool) scoreBoundary { | ||
if !isInclusive { | ||
return scoreBoundary("(" + utils.FloatToString(bound)) | ||
} | ||
return scoreBoundary(utils.FloatToString(bound)) | ||
} | ||
|
||
// Create a new score boundary defined by an infinity. | ||
func NewInfiniteScoreBoundary(bound InfBoundary) scoreBoundary { | ||
return scoreBoundary(string(bound) + "inf") | ||
} | ||
|
||
// Create a new lex boundary. | ||
func NewLexBoundary(bound string, isInclusive bool) lexBoundary { | ||
if !isInclusive { | ||
return lexBoundary("(" + bound) | ||
} | ||
return lexBoundary("[" + bound) | ||
} | ||
|
||
// Create a new lex boundary defined by an infinity. | ||
func NewInfiniteLexBoundary(bound InfBoundary) lexBoundary { | ||
return lexBoundary(string(bound)) | ||
} | ||
|
||
// TODO re-use limit from `SORT` https://github.com/valkey-io/valkey-glide/pull/2888 | ||
// Limit struct represents the range of elements to retrieve | ||
// The LIMIT argument is commonly used to specify a subset of results from the matching elements, similar to the | ||
// LIMIT clause in SQL (e.g., `SELECT LIMIT offset, count`). | ||
type Limit struct { | ||
// The starting position of the range, zero based. | ||
offset int64 | ||
// The maximum number of elements to include in the range. A negative count returns all elementsnfrom the offset. | ||
count int64 | ||
} | ||
|
||
func (limit *Limit) toArgs() []string { | ||
return []string{"LIMIT", utils.IntToString(limit.offset), utils.IntToString(limit.count)} | ||
} | ||
|
||
// Queries a range of elements from a sorted set by theirs index. | ||
// | ||
// Parameters: | ||
// | ||
// start - The start index of the range. | ||
// end - The end index of the range. | ||
func NewRangeByIndexQuery(start int64, end int64) *RangeByIndex { | ||
return &RangeByIndex{start, end, false} | ||
} | ||
|
||
// Reverses the sorted set, with index `0` as the element with the highest score. | ||
func (rbi *RangeByIndex) SetReverse() *RangeByIndex { | ||
rbi.reverse = true | ||
return rbi | ||
} | ||
|
||
func (rbi *RangeByIndex) ToArgs() []string { | ||
args := make([]string, 0, 3) | ||
args = append(args, utils.IntToString(rbi.start), utils.IntToString(rbi.end)) | ||
if rbi.reverse { | ||
args = append(args, "REV") | ||
} | ||
return args | ||
} | ||
|
||
// Queries a range of elements from a sorted set by theirs score. | ||
// | ||
// Parameters: | ||
// | ||
// start - The start score of the range. | ||
// end - The end score of the range. | ||
func NewRangeByScoreQuery(start scoreBoundary, end scoreBoundary) *RangeByScore { | ||
return &RangeByScore{start, end, false, nil} | ||
} | ||
|
||
// Reverses the sorted set, with index `0` as the element with the highest score. | ||
func (rbs *RangeByScore) SetReverse() *RangeByScore { | ||
rbs.reverse = true | ||
return rbs | ||
} | ||
|
||
// The limit argument for a range query, unset by default. See [Limit] for more information. | ||
func (rbs *RangeByScore) SetLimit(offset, count int64) *RangeByScore { | ||
rbs.Limit = &Limit{offset, count} | ||
return rbs | ||
} | ||
|
||
func (rbs *RangeByScore) ToArgs() []string { | ||
args := make([]string, 0, 7) | ||
args = append(args, string(rbs.start), string(rbs.end), "BYSCORE") | ||
if rbs.reverse { | ||
args = append(args, "REV") | ||
} | ||
if rbs.Limit != nil { | ||
args = append(args, rbs.Limit.toArgs()...) | ||
} | ||
return args | ||
} | ||
|
||
// Queries a range of elements from a sorted set by theirs lexicographical order. | ||
// | ||
// Parameters: | ||
// | ||
// start - The start lex of the range. | ||
// end - The end lex of the range. | ||
func NewRangeByLexQuery(start lexBoundary, end lexBoundary) *RangeByLex { | ||
return &RangeByLex{start, end, false, nil} | ||
} | ||
|
||
// Reverses the sorted set, with index `0` as the element with the highest score. | ||
func (rbl *RangeByLex) SetReverse() *RangeByLex { | ||
rbl.reverse = true | ||
return rbl | ||
} | ||
|
||
// The limit argument for a range query, unset by default. See [Limit] for more information. | ||
func (rbl *RangeByLex) SetLimit(offset, count int64) *RangeByLex { | ||
rbl.Limit = &Limit{offset, count} | ||
return rbl | ||
} | ||
|
||
func (rbl *RangeByLex) ToArgs() []string { | ||
args := make([]string, 0, 7) | ||
args = append(args, string(rbl.start), string(rbl.end), "BYLEX") | ||
if rbl.reverse { | ||
args = append(args, "REV") | ||
} | ||
if rbl.Limit != nil { | ||
args = append(args, rbl.Limit.toArgs()...) | ||
} | ||
return args | ||
} | ||
|
||
// Query for `ZRangeWithScores` in [SortedSetCommands] | ||
// - For range queries by index (rank), use `RangeByIndex`. | ||
// - For range queries by score, use `RangeByScore`. | ||
type ZRangeQueryWithScores interface { | ||
// A dummy interface to distinguish queries for `ZRange` and `ZRangeWithScores` | ||
// `ZRangeWithScores` does not support BYLEX | ||
dummy() | ||
ToArgs() []string | ||
} | ||
|
||
func (q *RangeByIndex) dummy() {} | ||
func (q *RangeByScore) dummy() {} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -253,7 +253,7 @@ type SortedSetCommands interface { | |
// A `KeyWithMemberAndScore` struct containing the key where the member was popped out, the member | ||
// itself, and the member score. If no member could be popped and the `timeout` expired, returns `nil`. | ||
// | ||
// example | ||
// Example: | ||
// zaddResult1, err := client.ZAdd(key1, map[string]float64{"a": 1.0, "b": 1.5}) | ||
// zaddResult2, err := client.ZAdd(key2, map[string]float64{"c": 2.0}) | ||
// result, err := client.BZPopMin([]string{key1, key2}, float64(.5)) | ||
|
@@ -263,6 +263,66 @@ type SortedSetCommands interface { | |
// [blocking commands]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#blocking-commands | ||
BZPopMin(keys []string, timeoutSecs float64) (Result[KeyWithMemberAndScore], error) | ||
|
||
// Returns the specified range of elements in the sorted set stored at `key`. | ||
Yury-Fridlyand marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// `ZRANGE` can perform different types of range queries: by index (rank), by the score, or by lexicographical order. | ||
// | ||
// To get the elements with their scores, see [ZRangeWithScores]. | ||
// | ||
// See [valkey.io] for more details. | ||
// | ||
// Parameters: | ||
// key - The key of the sorted set. | ||
// rangeQuery - The range query object representing the type of range query to perform. | ||
// - For range queries by index (rank), use [RangeByIndex]. | ||
// - For range queries by lexicographical order, use [RangeByLex]. | ||
// - For range queries by score, use [RangeByScore]. | ||
// | ||
// Return value: | ||
// An array of elements within the specified range. | ||
// If `key` does not exist, it is treated as an empty sorted set, and the command returns an empty array. | ||
// | ||
// Example: | ||
// // Retrieve all members of a sorted set in ascending order | ||
// result, err := client.ZRange("my_sorted_set", options.NewRangeByIndexQuery(0, -1)) | ||
// | ||
// // Retrieve members within a score range in descending order | ||
// query := options.NewRangeByScoreQuery(options.NewScoreBoundary(3, false), | ||
// options.NewInfiniteScoreBoundary(options.NegativeInfinity)). | ||
// .SetReverse() | ||
// result, err := client.ZRange("my_sorted_set", query) | ||
// // `result` contains members which have scores within the range of negative infinity to 3, in descending order | ||
// | ||
// [valkey.io]: https://valkey.io/commands/zrange/ | ||
ZRange(key string, rangeQuery options.ZRangeQuery) ([]Result[string], error) | ||
|
||
// Returns the specified range of elements with their scores in the sorted set stored at `key`. | ||
// `ZRANGE` can perform different types of range queries: by index (rank), by the score, or by lexicographical order. | ||
// | ||
// See [valkey.io] for more details. | ||
// | ||
// Parameters: | ||
// key - The key of the sorted set. | ||
// rangeQuery - The range query object representing the type of range query to perform. | ||
// - For range queries by index (rank), use [RangeByIndex]. | ||
// - For range queries by score, use [RangeByScore]. | ||
// | ||
// Return value: | ||
// A map of elements and their scores within the specified range. | ||
// If `key` does not exist, it is treated as an empty sorted set, and the command returns an empty map. | ||
// | ||
// Example: | ||
// // Retrieve all members of a sorted set in ascending order | ||
// result, err := client.ZRangeWithScores("my_sorted_set", options.NewRangeByIndexQuery(0, -1)) | ||
// | ||
// // Retrieve members within a score range in descending order | ||
// query := options.NewRangeByScoreQuery(options.NewScoreBoundary(3, false), | ||
// options.NewInfiniteScoreBoundary(options.NegativeInfinity)). | ||
// SetReverse() | ||
// result, err := client.ZRangeWithScores("my_sorted_set", query) | ||
// // `result` contains members with scores within the range of negative infinity to 3, in descending order | ||
// | ||
// [valkey.io]: https://valkey.io/commands/zrange/ | ||
ZRangeWithScores(key string, rangeQuery options.ZRangeQueryWithScores) (map[Result[string]]Result[float64], error) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can the map key be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Never. This will be updated in another PR for all commands. |
||
// Returns the rank of `member` in the sorted set stored at `key`, with | ||
// scores ordered from low to high, starting from `0`. | ||
// To get the rank of `member` with its score, see [ZRankWithScore]. | ||
|
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
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In most places, we have passed options as a pointer. Is there any difference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rangeQuery
is a mandatory argument for that command