Skip to content

Commit

Permalink
Make exists variadic.
Browse files Browse the repository at this point in the history
`exists` now return an Integer if passed multiple keys.

If passed a single key it will still return a Boolean, but print a deprecation warning.

To get a Boolean use `exists?` instead.

To opt-in to the new behavior, set `Redis.exists_returns_integer = true`.
  • Loading branch information
byroot committed Jun 9, 2020
1 parent bf42fc9 commit 3257527
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 7 deletions.
31 changes: 26 additions & 5 deletions lib/redis.rb
Expand Up @@ -4,6 +4,10 @@
require_relative "redis/errors"

class Redis
class << self
attr_accessor :exists_returns_integer
end

def self.current
@current ||= Redis.new
end
Expand Down Expand Up @@ -550,13 +554,30 @@ def unlink(*keys)
end
end

# Determine if a key exists.
# Determine how many of the keys exists.
#
# @param [String] key
# @return [Boolean]
def exists(key)
# @param [String, Array<String>] keys
# @return [Integer]
def exists(*keys)
if !Redis.exists_returns_integer && keys.size == 1
message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3, if you want to keep the old behavior, " \
"use `exists?` instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = true. " \
"(#{::Kernel.caller(1, 1).first})\n"

if defined?(::Warning)
::Warning.warn(message)
else
$stderr.puts(message)
end
exists?(*keys)
else
_exists(*keys)
end
end

def _exists(*keys)
synchronize do |client|
client.call([:exists, key], &Boolify)
client.call([:exists, *keys])
end
end

Expand Down
20 changes: 18 additions & 2 deletions lib/redis/distributed.rb
Expand Up @@ -171,8 +171,24 @@ def unlink(*args)
end

# Determine if a key exists.
def exists(key)
node_for(key).exists(key)
def exists(*args)
if !Redis.exists_returns_integer && args.size == 1
message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3, if you want to keep the old behavior, " \
"use `exists?` instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = true. " \
"(#{::Kernel.caller(1, 1).first})\n"

if defined?(::Warning)
::Warning.warn(message)
else
$stderr.puts(message)
end
exists?(*args)
else
keys_per_node = args.group_by { |key| node_for(key) }
keys_per_node.inject(0) do |sum, (node, keys)|
sum + node._exists(*keys)
end
end
end

# Determine if any of the keys exists.
Expand Down
24 changes: 24 additions & 0 deletions test/lint/value_types.rb
Expand Up @@ -11,6 +11,30 @@ def test_exists
assert_equal true, r.exists("foo")
end

def test_exists_integer
previous_exists_returns_integer = Redis.exists_returns_integer
Redis.exists_returns_integer = true
assert_equal 0, r.exists("foo")

r.set("foo", "s1")

assert_equal 1, r.exists("foo")
ensure
Redis.exists_returns_integer = previous_exists_returns_integer
end

def test_variadic_exists
assert_equal 0, r.exists("{1}foo", "{1}bar")

r.set("{1}foo", "s1")

assert_equal 1, r.exists("{1}foo", "{1}bar")

r.set("{1}bar", "s2")

assert_equal 2, r.exists("{1}foo", "{1}bar")
end

def test_exists?
assert_equal false, r.exists?("{1}foo", "{1}bar")

Expand Down

0 comments on commit 3257527

Please sign in to comment.