Skip to content

Commit

Permalink
Merge pull request #1040 from fatkodima/hrandfield
Browse files Browse the repository at this point in the history
[Redis 6.2] Add HRANDFIELD command
  • Loading branch information
byroot committed Oct 19, 2021
2 parents a7db87c + 851f085 commit 706c9b1
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 1 deletion.
47 changes: 46 additions & 1 deletion lib/redis.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1907,7 +1907,7 @@ def zmscore(key, *members)
# @example Get multiple random members
# redis.zrandmember("zset", 2)
# # => ["a", "b"]
# @example Gem multiple random members with scores
# @example Get multiple random members with scores
# redis.zrandmember("zset", 2, with_scores: true)
# # => [["a", 2.0], ["b", 3.0]]
#
Expand Down Expand Up @@ -2457,6 +2457,43 @@ def mapped_hmget(key, *fields)
end
end

# Get one or more random fields from a hash.
#
# @example Get one random field
# redis.hrandfield("hash")
# # => "f1"
# @example Get multiple random fields
# redis.hrandfield("hash", 2)
# # => ["f1, "f2"]
# @example Get multiple random fields with values
# redis.hrandfield("hash", 2, with_values: true)
# # => [["f1", "s1"], ["f2", "s2"]]
#
# @param [String] key
# @param [Integer] count
# @param [Hash] options
# - `:with_values => true`: include values in output
#
# @return [nil, String, Array<String>, Array<[String, Float]>]
# - when `key` does not exist, `nil`
# - when `count` is not specified, a field name
# - when `count` is specified and `:with_values` is not specified, an array of field names
# - when `:with_values` is specified, an array with `[field, value]` pairs
def hrandfield(key, count = nil, withvalues: false, with_values: withvalues)
if with_values && count.nil?
raise ArgumentError, "count argument must be specified"
end

args = [:hrandfield, key]
args << count if count
args << "WITHVALUES" if with_values

synchronize do |client|
parser = Pairify if with_values
client.call(args, &parser)
end
end

# Delete one or more hash fields.
#
# @param [String] key
Expand Down Expand Up @@ -3652,6 +3689,14 @@ def method_missing(command, *args) # rubocop:disable Style/MissingRespondToMissi
end
}

Pairify = lambda { |value|
if value.respond_to?(:each_slice)
value.each_slice(2).to_a
else
value
end
}

Floatify = lambda { |value|
case value
when "inf"
Expand Down
4 changes: 4 additions & 0 deletions lib/redis/distributed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,10 @@ def mapped_hmget(key, *fields)
Hash[*fields.zip(hmget(key, *fields)).flatten]
end

def hrandfield(key, count = nil, **options)
node_for(key).hrandfield(key, count, **options)
end

# Delete one or more hash fields.
def hdel(key, *fields)
node_for(key).hdel(key, *fields)
Expand Down
24 changes: 24 additions & 0 deletions test/lint/hashes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,30 @@ def test_hkeys
assert_equal ["f1", "f2"], r.hkeys("foo")
end

def test_hrandfield
target_version("6.2") do
assert_nil r.hrandfield("foo")
assert_equal [], r.hrandfield("foo", 1)

error = assert_raises(ArgumentError) do
r.hrandfield("foo", with_values: true)
end
assert_equal "count argument must be specified", error.message

r.hset("foo", "f1", "s1")
r.hset("foo", "f2", "s2")

assert ["f1", "f2"].include?(r.hrandfield("foo"))
assert_equal ["f1", "f2"], r.hrandfield("foo", 2).sort
assert_equal 4, r.hrandfield("foo", -4).size

r.hrandfield("foo", 2, with_values: true) do |(field, value)|
assert ["f1", "f2"].include?(field)
assert ["s1", "s2"].include?(value)
end
end
end

def test_hvals
assert_equal [], r.hvals("foo")

Expand Down

0 comments on commit 706c9b1

Please sign in to comment.