lib/redis.rb in redis-3.0.0.rc2 vs lib/redis.rb in redis-3.0.0
- old
+ new
@@ -34,17 +34,22 @@
def synchronize
mon_synchronize { yield(@client) }
end
- # Run code without the client reconnecting
- def without_reconnect(&block)
+ # Run code with the client reconnecting
+ def with_reconnect(val=true, &blk)
synchronize do |client|
- client.without_reconnect(&block)
+ client.with_reconnect(val, &blk)
end
end
+ # Run code without the client reconnecting
+ def without_reconnect(&blk)
+ with_reconnect(false, &blk)
+ end
+
# Authenticate to the server.
#
# @param [String] password must match the password specified in the
# `requirepass` directive in the configuration file
# @return [String] `OK`
@@ -63,35 +68,61 @@
client.db = db
client.call [:select, db]
end
end
- # Get information and statistics about the server.
+ # Ping the server.
#
- # @param [String, Symbol] cmd e.g. "commandstats"
- # @return [Hash<String, String>]
- def info(cmd = nil)
+ # @return [String] `PONG`
+ def ping
synchronize do |client|
- client.call [:info, cmd].compact do |reply|
- if reply.kind_of?(String)
- reply = Hash[reply.split("\r\n").map do |line|
- line.split(":", 2) unless line =~ /^(#|$)/
- end]
+ client.call [:ping]
+ end
+ end
- if cmd && cmd.to_s == "commandstats"
- # Extract nested hashes for INFO COMMANDSTATS
- reply = Hash[reply.map do |k, v|
- [k[/^cmdstat_(.*)$/, 1], Hash[*v.split(/,|=/)]]
- end]
- end
- end
+ # Echo the given string.
+ #
+ # @param [String] value
+ # @return [String]
+ def echo(value)
+ synchronize do |client|
+ client.call [:echo, value]
+ end
+ end
- reply
+ # Close the connection.
+ #
+ # @return [String] `OK`
+ def quit
+ synchronize do |client|
+ begin
+ client.call [:quit]
+ rescue ConnectionError
+ ensure
+ client.disconnect
end
end
end
+ # Asynchronously rewrite the append-only file.
+ #
+ # @return [String] `OK`
+ def bgrewriteaof
+ synchronize do |client|
+ client.call [:bgrewriteaof]
+ end
+ end
+
+ # Asynchronously save the dataset to disk.
+ #
+ # @return [String] `OK`
+ def bgsave
+ synchronize do |client|
+ client.call [:bgsave]
+ end
+ end
+
# Get or set server configuration parameters.
#
# @param [String] action e.g. `get`, `set`, `resetstat`
# @return [String, Hash] string reply, or hash when retrieving more than one
# property with `CONFIG GET`
@@ -105,180 +136,247 @@
end
end
end
end
- # Remove all keys from the current database.
+ # Return the number of keys in the selected database.
#
- # @return [String] `OK`
- def flushdb
+ # @return [Fixnum]
+ def dbsize
synchronize do |client|
- client.call [:flushdb]
+ client.call [:dbsize]
end
end
+ def debug(*args)
+ synchronize do |client|
+ client.call [:debug, *args]
+ end
+ end
+
# Remove all keys from all databases.
#
# @return [String] `OK`
def flushall
synchronize do |client|
client.call [:flushall]
end
end
+ # Remove all keys from the current database.
+ #
+ # @return [String] `OK`
+ def flushdb
+ synchronize do |client|
+ client.call [:flushdb]
+ end
+ end
+
+ # Get information and statistics about the server.
+ #
+ # @param [String, Symbol] cmd e.g. "commandstats"
+ # @return [Hash<String, String>]
+ def info(cmd = nil)
+ synchronize do |client|
+ client.call [:info, cmd].compact do |reply|
+ if reply.kind_of?(String)
+ reply = Hash[reply.split("\r\n").map do |line|
+ line.split(":", 2) unless line =~ /^(#|$)/
+ end]
+
+ if cmd && cmd.to_s == "commandstats"
+ # Extract nested hashes for INFO COMMANDSTATS
+ reply = Hash[reply.map do |k, v|
+ [k[/^cmdstat_(.*)$/, 1], Hash[*v.split(/,|=/)]]
+ end]
+ end
+ end
+
+ reply
+ end
+ end
+ end
+
+ # Get the UNIX time stamp of the last successful save to disk.
+ #
+ # @return [Fixnum]
+ def lastsave
+ synchronize do |client|
+ client.call [:lastsave]
+ end
+ end
+
+ # Listen for all requests received by the server in real time.
+ #
+ # There is no way to interrupt this command.
+ #
+ # @yield a block to be called for every line of output
+ # @yieldparam [String] line timestamp and command that was executed
+ def monitor(&block)
+ synchronize do |client|
+ client.call_loop([:monitor], &block)
+ end
+ end
+
# Synchronously save the dataset to disk.
#
# @return [String]
def save
synchronize do |client|
client.call [:save]
end
end
- # Asynchronously save the dataset to disk.
- #
- # @return [String] `OK`
- def bgsave
+ # Synchronously save the dataset to disk and then shut down the server.
+ def shutdown
synchronize do |client|
- client.call [:bgsave]
+ client.with_reconnect(false) do
+ begin
+ client.call [:shutdown]
+ rescue ConnectionError
+ # This means Redis has probably exited.
+ nil
+ end
+ end
end
end
- # Asynchronously rewrite the append-only file.
- #
- # @return [String] `OK`
- def bgrewriteaof
+ # Make the server a slave of another instance, or promote it as master.
+ def slaveof(host, port)
synchronize do |client|
- client.call [:bgrewriteaof]
+ client.call [:slaveof, host, port]
end
end
- # Get the value of a key.
+ # Interact with the slowlog (get, len, reset)
#
- # @param [String] key
- # @return [String]
- def get(key)
+ # @param [String] subcommand e.g. `get`, `len`, `reset`
+ # @param [Fixnum] length maximum number of entries to return
+ # @return [Array<String>, Fixnum, String] depends on subcommand
+ def slowlog(subcommand, length=nil)
synchronize do |client|
- client.call [:get, key]
+ args = [:slowlog, subcommand]
+ args << length if length
+ client.call args
end
end
- alias :[] :get
+ # Internal command used for replication.
+ def sync
+ synchronize do |client|
+ client.call [:sync]
+ end
+ end
- # Returns the bit value at offset in the string value stored at key.
+ # Return the server time.
#
- # @param [String] key
- # @param [Fixnum] offset bit offset
- # @return [Fixnum] `0` or `1`
- def getbit(key, offset)
+ # @example
+ # r.time # => [ 1333093196, 606806 ]
+ #
+ # @return [Array<Fixnum>] tuple of seconds since UNIX epoch and
+ # microseconds in the current second
+ def time
synchronize do |client|
- client.call [:getbit, key, offset]
+ client.call [:time] do |reply|
+ reply.map(&:to_i) if reply
+ end
end
end
- # Get a substring of the string stored at a key.
+ # Remove the expiration from a key.
#
# @param [String] key
- # @param [Fixnum] start zero-based start offset
- # @param [Fixnum] stop zero-based end offset. Use -1 for representing
- # the end of the string
- # @return [Fixnum] `0` or `1`
- def getrange(key, start, stop)
+ # @return [Boolean] whether the timeout was removed or not
+ def persist(key)
synchronize do |client|
- client.call [:getrange, key, start, stop]
+ client.call [:persist, key], &_boolify
end
end
- # Set the string value of a key and return its old value.
+ # Set a key's time to live in seconds.
#
# @param [String] key
- # @param [String] value value to replace the current value with
- # @return [String] the old value stored in the key, or `nil` if the key
- # did not exist
- def getset(key, value)
+ # @param [Fixnum] seconds time to live
+ # @return [Boolean] whether the timeout was set or not
+ def expire(key, seconds)
synchronize do |client|
- client.call [:getset, key, value]
+ client.call [:expire, key, seconds], &_boolify
end
end
- # Get the values of all the given keys.
+ # Set the expiration for a key as a UNIX timestamp.
#
- # @example
- # redis.mget("key1", "key1")
- # # => ["v1", "v2"]
- #
- # @param [Array<String>] keys
- # @return [Array<String>] an array of values for the specified keys
- #
- # @see #mapped_mget
- def mget(*keys, &blk)
+ # @param [String] key
+ # @param [Fixnum] unix_time expiry time specified as a UNIX timestamp
+ # @return [Boolean] whether the timeout was set or not
+ def expireat(key, unix_time)
synchronize do |client|
- client.call [:mget, *keys], &blk
+ client.call [:expireat, key, unix_time], &_boolify
end
end
- # Append a value to a key.
+ # Get the time to live (in seconds) for a key.
#
# @param [String] key
- # @param [String] value value to append
- # @return [Fixnum] length of the string after appending
- def append(key, value)
+ # @return [Fixnum] remaining time to live in seconds, or -1 if the
+ # key does not exist or does not have a timeout
+ def ttl(key)
synchronize do |client|
- client.call [:append, key, value]
+ client.call [:ttl, key]
end
end
- # Get the length of the value stored in a key.
+ # Set a key's time to live in milliseconds.
#
# @param [String] key
- # @return [Fixnum] the length of the value stored in the key, or 0
- # if the key does not exist
- def strlen(key)
+ # @param [Fixnum] milliseconds time to live
+ # @return [Boolean] whether the timeout was set or not
+ def pexpire(key, milliseconds)
synchronize do |client|
- client.call [:strlen, key]
+ client.call [:pexpire, key, milliseconds], &_boolify
end
end
- # Get all the fields and values in a hash.
+ # Set the expiration for a key as number of milliseconds from UNIX Epoch.
#
# @param [String] key
- # @return [Hash<String, String>]
- def hgetall(key)
+ # @param [Fixnum] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
+ # @return [Boolean] whether the timeout was set or not
+ def pexpireat(key, ms_unix_time)
synchronize do |client|
- client.call [:hgetall, key], &_hashify
+ client.call [:pexpireat, key, ms_unix_time], &_boolify
end
end
- # Get the value of a hash field.
+ # Get the time to live (in milliseconds) for a key.
#
# @param [String] key
- # @param [String] field
- # @return [String]
- def hget(key, field)
+ # @return [Fixnum] remaining time to live in milliseconds, or -1 if the
+ # key does not exist or does not have a timeout
+ def pttl(key)
synchronize do |client|
- client.call [:hget, key, field]
+ client.call [:pttl, key]
end
end
- # Delete one or more hash fields.
+ # Delete one or more keys.
#
- # @param [String] key
- # @param [String, Array<String>] field
- # @return [Fixnum] the number of fields that were removed from the hash
- def hdel(key, field)
+ # @param [String, Array<String>] keys
+ # @return [Fixnum] number of keys that were deleted
+ def del(*keys)
synchronize do |client|
- client.call [:hdel, key, field]
+ client.call [:del, *keys]
end
end
- # Get all the fields in a hash.
+ # Determine if a key exists.
#
# @param [String] key
- # @return [Array<String>]
- def hkeys(key)
+ # @return [Boolean]
+ def exists(key)
synchronize do |client|
- client.call [:hkeys, key]
+ client.call [:exists, key], &_boolify
end
end
# Find all keys matching the given pattern.
#
@@ -294,189 +392,465 @@
end
end
end
end
+ # Move a key to another database.
+ #
+ # @example Move a key to another database
+ # redis.set "foo", "bar"
+ # # => "OK"
+ # redis.move "foo", 2
+ # # => true
+ # redis.exists "foo"
+ # # => false
+ # redis.select 2
+ # # => "OK"
+ # redis.exists "foo"
+ # # => true
+ # resis.get "foo"
+ # # => "bar"
+ #
+ # @param [String] key
+ # @param [Fixnum] db
+ # @return [Boolean] whether the key was moved or not
+ def move(key, db)
+ synchronize do |client|
+ client.call [:move, key, db], &_boolify
+ end
+ end
+
+ def object(*args)
+ synchronize do |client|
+ client.call [:object, *args]
+ end
+ end
+
# Return a random key from the keyspace.
#
# @return [String]
def randomkey
synchronize do |client|
client.call [:randomkey]
end
end
- # Echo the given string.
+ # Rename a key. If the new key already exists it is overwritten.
#
- # @param [String] value
- # @return [String]
- def echo(value)
+ # @param [String] old_name
+ # @param [String] new_name
+ # @return [String] `OK`
+ def rename(old_name, new_name)
synchronize do |client|
- client.call [:echo, value]
+ client.call [:rename, old_name, new_name]
end
end
- # Return the server time.
+ # Rename a key, only if the new key does not exist.
#
- # @example
- # r.time # => [ 1333093196, 606806 ]
+ # @param [String] old_name
+ # @param [String] new_name
+ # @return [Boolean] whether the key was renamed or not
+ def renamenx(old_name, new_name)
+ synchronize do |client|
+ client.call [:renamenx, old_name, new_name], &_boolify
+ end
+ end
+
+ # Sort the elements in a list, set or sorted set.
#
- # @return [Array<Fixnum>] tuple of seconds since UNIX epoch and
- # microseconds in the current second
- def time
+ # @example Retrieve the first 2 elements from an alphabetically sorted "list"
+ # redis.sort("list", :order => "alpha", :limit => [0, 2])
+ # # => ["a", "b"]
+ # @example Store an alphabetically descending list in "target"
+ # redis.sort("list", :order => "desc alpha", :store => "target")
+ # # => 26
+ #
+ # @param [String] key
+ # @param [Hash] options
+ # - `:by => String`: use external key to sort elements by
+ # - `:limit => [offset, count]`: skip `offset` elements, return a maximum
+ # of `count` elements
+ # - `:get => [String, Array<String>]`: single key or array of keys to
+ # retrieve per element in the result
+ # - `:order => String`: combination of `ASC`, `DESC` and optionally `ALPHA`
+ # - `:store => String`: key to store the result at
+ #
+ # @return [Array<String>, Array<Array<String>>, Fixnum]
+ # - when `:get` is not specified, or holds a single element, an array of elements
+ # - when `:get` is specified, and holds more than one element, an array of
+ # elements where every element is an array with the result for every
+ # element specified in `:get`
+ # - when `:store` is specified, the number of elements in the stored result
+ def sort(key, options = {})
+ args = []
+
+ by = options[:by]
+ args.concat ["BY", by] if by
+
+ limit = options[:limit]
+ args.concat ["LIMIT", *limit] if limit
+
+ get = Array(options[:get])
+ args.concat ["GET"].product(get).flatten unless get.empty?
+
+ order = options[:order]
+ args.concat order.split(" ") if order
+
+ store = options[:store]
+ args.concat ["STORE", store] if store
+
synchronize do |client|
- client.call [:time] do |reply|
- reply.map(&:to_i) if reply
+ client.call [:sort, key, *args] do |reply|
+ if get.size > 1
+ if reply
+ reply.each_slice(get.size).to_a
+ end
+ else
+ reply
+ end
end
end
end
- # Ping the server.
+ # Determine the type stored at key.
#
- # @return [String] `PONG`
- def ping
+ # @param [String] key
+ # @return [String] `string`, `list`, `set`, `zset`, `hash` or `none`
+ def type(key)
synchronize do |client|
- client.call [:ping]
+ client.call [:type, key]
end
end
- # Get the UNIX time stamp of the last successful save to disk.
+ # Decrement the integer value of a key by one.
#
- # @return [Fixnum]
- def lastsave
+ # @example
+ # redis.decr("value")
+ # # => 4
+ #
+ # @param [String] key
+ # @return [Fixnum] value after decrementing it
+ def decr(key)
synchronize do |client|
- client.call [:lastsave]
+ client.call [:decr, key]
end
end
- # Return the number of keys in the selected database.
+ # Decrement the integer value of a key by the given number.
#
- # @return [Fixnum]
- def dbsize
+ # @example
+ # redis.decrby("value", 5)
+ # # => 0
+ #
+ # @param [String] key
+ # @param [Fixnum] decrement
+ # @return [Fixnum] value after decrementing it
+ def decrby(key, decrement)
synchronize do |client|
- client.call [:dbsize]
+ client.call [:decrby, key, decrement]
end
end
- # Determine if a key exists.
+ # Increment the integer value of a key by one.
#
+ # @example
+ # redis.incr("value")
+ # # => 6
+ #
# @param [String] key
- # @return [Boolean]
- def exists(key)
+ # @return [Fixnum] value after incrementing it
+ def incr(key)
synchronize do |client|
- client.call [:exists, key], &_boolify
+ client.call [:incr, key]
end
end
- # Get the length of a list.
+ # Increment the integer value of a key by the given integer number.
#
+ # @example
+ # redis.incrby("value", 5)
+ # # => 10
+ #
# @param [String] key
- # @return [Fixnum]
- def llen(key)
+ # @param [Fixnum] increment
+ # @return [Fixnum] value after incrementing it
+ def incrby(key, increment)
synchronize do |client|
- client.call [:llen, key]
+ client.call [:incrby, key, increment]
end
end
- # Get a range of elements from a list.
+ # Increment the numeric value of a key by the given float number.
#
+ # @example
+ # redis.incrbyfloat("value", 1.23)
+ # # => 1.23
+ #
# @param [String] key
- # @param [Fixnum] start start index
- # @param [Fixnum] stop stop index
- # @return [Array<String>]
- def lrange(key, start, stop)
+ # @param [Float] increment
+ # @return [Float] value after incrementing it
+ def incrbyfloat(key, increment)
synchronize do |client|
- client.call [:lrange, key, start, stop]
+ client.call [:incrbyfloat, key, increment] do |reply|
+ Float(reply) if reply
+ end
end
end
- # Trim a list to the specified range.
+ # Set the string value of a key.
#
# @param [String] key
- # @param [Fixnum] start start index
- # @param [Fixnum] stop stop index
- # @return [String] `OK`
- def ltrim(key, start, stop)
+ # @param [String] value
+ # @return `"OK"`
+ def set(key, value)
synchronize do |client|
- client.call [:ltrim, key, start, stop]
+ client.call [:set, key, value]
end
end
- # Get an element from a list by its index.
+ alias :[]= :set
+
+ # Set the time to live in seconds of a key.
#
# @param [String] key
- # @param [Fixnum] index
- # @return [String]
- def lindex(key, index)
+ # @param [Fixnum] ttl
+ # @param [String] value
+ # @return `"OK"`
+ def setex(key, ttl, value)
synchronize do |client|
- client.call [:lindex, key, index]
+ client.call [:setex, key, ttl, value]
end
end
- # Insert an element before or after another element in a list.
+ # Set the time to live in milliseconds of a key.
#
# @param [String] key
- # @param [String, Symbol] where `BEFORE` or `AFTER`
- # @param [String] pivot reference element
+ # @param [Fixnum] ttl
# @param [String] value
- # @return [Fixnum] length of the list after the insert operation, or `-1`
- # when the element `pivot` was not found
- def linsert(key, where, pivot, value)
+ # @return `"OK"`
+ def psetex(key, ttl, value)
synchronize do |client|
- client.call [:linsert, key, where, pivot, value]
+ client.call [:psetex, key, ttl, value]
end
end
- # Set the value of an element in a list by its index.
+ # Set the value of a key, only if the key does not exist.
#
# @param [String] key
- # @param [Fixnum] index
# @param [String] value
- # @return [String] `OK`
- def lset(key, index, value)
+ # @return [Boolean] whether the key was set or not
+ def setnx(key, value)
synchronize do |client|
- client.call [:lset, key, index, value]
+ client.call [:setnx, key, value], &_boolify
end
end
- # Remove elements from a list.
+ # Set one or more values.
#
+ # @example
+ # redis.mset("key1", "v1", "key2", "v2")
+ # # => "OK"
+ #
+ # @param [Array<String>] args array of keys and values
+ # @return `"OK"`
+ #
+ # @see #mapped_mset
+ def mset(*args)
+ synchronize do |client|
+ client.call [:mset, *args]
+ end
+ end
+
+ # Set one or more values.
+ #
+ # @example
+ # redis.mapped_mset({ "f1" => "v1", "f2" => "v2" })
+ # # => "OK"
+ #
+ # @param [Hash] hash keys mapping to values
+ # @return `"OK"`
+ #
+ # @see #mset
+ def mapped_mset(hash)
+ mset(*hash.to_a.flatten)
+ end
+
+ # Set one or more values, only if none of the keys exist.
+ #
+ # @example
+ # redis.msetnx("key1", "v1", "key2", "v2")
+ # # => true
+ #
+ # @param [Array<String>] args array of keys and values
+ # @return [Boolean] whether or not all values were set
+ #
+ # @see #mapped_msetnx
+ def msetnx(*args)
+ synchronize do |client|
+ client.call [:msetnx, *args], &_boolify
+ end
+ end
+
+ # Set one or more values, only if none of the keys exist.
+ #
+ # @example
+ # redis.msetnx({ "key1" => "v1", "key2" => "v2" })
+ # # => true
+ #
+ # @param [Hash] hash keys mapping to values
+ # @return [Boolean] whether or not all values were set
+ #
+ # @see #msetnx
+ def mapped_msetnx(hash)
+ msetnx(*hash.to_a.flatten)
+ end
+
+ # Get the value of a key.
+ #
# @param [String] key
- # @param [Fixnum] count number of elements to remove. Use a positive
- # value to remove the first `count` occurrences of `value`. A negative
- # value to remove the last `count` occurrences of `value`. Or zero, to
- # remove all occurrences of `value` from the list.
- # @param [String] value
- # @return [Fixnum] the number of removed elements
- def lrem(key, count, value)
+ # @return [String]
+ def get(key)
synchronize do |client|
- client.call [:lrem, key, count, value]
+ client.call [:get, key]
end
end
- # Append one or more values to a list, creating the list if it doesn't exist
+ alias :[] :get
+
+ # Get the values of all the given keys.
#
+ # @example
+ # redis.mget("key1", "key1")
+ # # => ["v1", "v2"]
+ #
+ # @param [Array<String>] keys
+ # @return [Array<String>] an array of values for the specified keys
+ #
+ # @see #mapped_mget
+ def mget(*keys, &blk)
+ synchronize do |client|
+ client.call [:mget, *keys], &blk
+ end
+ end
+
+ # Get the values of all the given keys.
+ #
+ # @example
+ # redis.mapped_mget("key1", "key1")
+ # # => { "key1" => "v1", "key2" => "v2" }
+ #
+ # @param [Array<String>] keys array of keys
+ # @return [Hash] a hash mapping the specified keys to their values
+ #
+ # @see #mget
+ def mapped_mget(*keys)
+ mget(*keys) do |reply|
+ if reply.kind_of?(Array)
+ hash = Hash.new
+ keys.zip(reply).each do |field, value|
+ hash[field] = value
+ end
+ hash
+ else
+ reply
+ end
+ end
+ end
+
+ # Overwrite part of a string at key starting at the specified offset.
+ #
# @param [String] key
+ # @param [Fixnum] offset byte offset
# @param [String] value
- # @return [Fixnum] the length of the list after the push operation
- def rpush(key, value)
+ # @return [Fixnum] length of the string after it was modified
+ def setrange(key, offset, value)
synchronize do |client|
- client.call [:rpush, key, value]
+ client.call [:setrange, key, offset, value]
end
end
- # Append a value to a list, only if the list exists.
+ # Get a substring of the string stored at a key.
#
# @param [String] key
- # @param [String] value
- # @return [Fixnum] the length of the list after the push operation
- def rpushx(key, value)
+ # @param [Fixnum] start zero-based start offset
+ # @param [Fixnum] stop zero-based end offset. Use -1 for representing
+ # the end of the string
+ # @return [Fixnum] `0` or `1`
+ def getrange(key, start, stop)
synchronize do |client|
- client.call [:rpushx, key, value]
+ client.call [:getrange, key, start, stop]
end
end
+ # Sets or clears the bit at offset in the string value stored at key.
+ #
+ # @param [String] key
+ # @param [Fixnum] offset bit offset
+ # @param [Fixnum] value bit value `0` or `1`
+ # @return [Fixnum] the original bit value stored at `offset`
+ def setbit(key, offset, value)
+ synchronize do |client|
+ client.call [:setbit, key, offset, value]
+ end
+ end
+
+ # Returns the bit value at offset in the string value stored at key.
+ #
+ # @param [String] key
+ # @param [Fixnum] offset bit offset
+ # @return [Fixnum] `0` or `1`
+ def getbit(key, offset)
+ synchronize do |client|
+ client.call [:getbit, key, offset]
+ end
+ end
+
+ # Append a value to a key.
+ #
+ # @param [String] key
+ # @param [String] value value to append
+ # @return [Fixnum] length of the string after appending
+ def append(key, value)
+ synchronize do |client|
+ client.call [:append, key, value]
+ end
+ end
+
+ # Set the string value of a key and return its old value.
+ #
+ # @param [String] key
+ # @param [String] value value to replace the current value with
+ # @return [String] the old value stored in the key, or `nil` if the key
+ # did not exist
+ def getset(key, value)
+ synchronize do |client|
+ client.call [:getset, key, value]
+ end
+ end
+
+ # Get the length of the value stored in a key.
+ #
+ # @param [String] key
+ # @return [Fixnum] the length of the value stored in the key, or 0
+ # if the key does not exist
+ def strlen(key)
+ synchronize do |client|
+ client.call [:strlen, key]
+ end
+ end
+
+ # Get the length of a list.
+ #
+ # @param [String] key
+ # @return [Fixnum]
+ def llen(key)
+ synchronize do |client|
+ client.call [:llen, key]
+ end
+ end
+
# Prepend one or more values to a list, creating the list if it doesn't exist
#
# @param [String] key
# @param [String] value
# @return [Fixnum] the length of the list after the push operation
@@ -495,20 +869,63 @@
synchronize do |client|
client.call [:lpushx, key, value]
end
end
+ # Append one or more values to a list, creating the list if it doesn't exist
+ #
+ # @param [String] key
+ # @param [String] value
+ # @return [Fixnum] the length of the list after the push operation
+ def rpush(key, value)
+ synchronize do |client|
+ client.call [:rpush, key, value]
+ end
+ end
+
+ # Append a value to a list, only if the list exists.
+ #
+ # @param [String] key
+ # @param [String] value
+ # @return [Fixnum] the length of the list after the push operation
+ def rpushx(key, value)
+ synchronize do |client|
+ client.call [:rpushx, key, value]
+ end
+ end
+
+ # Remove and get the first element in a list.
+ #
+ # @param [String] key
+ # @return [String]
+ def lpop(key)
+ synchronize do |client|
+ client.call [:lpop, key]
+ end
+ end
+
# Remove and get the last element in a list.
#
# @param [String] key
# @return [String]
def rpop(key)
synchronize do |client|
client.call [:rpop, key]
end
end
+ # Remove the last element in a list, append it to another list and return it.
+ #
+ # @param [String] source source key
+ # @param [String] destination destination key
+ # @return [nil, String] the element, or nil when the source key does not exist
+ def rpoplpush(source, destination)
+ synchronize do |client|
+ client.call [:rpoplpush, source, destination]
+ end
+ end
+
def _bpop(cmd, args)
options = {}
case args.last
when Hash
@@ -594,65 +1011,96 @@
synchronize do |client|
client.call_without_timeout [:brpoplpush, source, destination, timeout]
end
end
- # Remove the last element in a list, append it to another list and return it.
+ # Get an element from a list by its index.
#
- # @param [String] source source key
- # @param [String] destination destination key
- # @return [nil, String] the element, or nil when the source key does not exist
- def rpoplpush(source, destination)
+ # @param [String] key
+ # @param [Fixnum] index
+ # @return [String]
+ def lindex(key, index)
synchronize do |client|
- client.call [:rpoplpush, source, destination]
+ client.call [:lindex, key, index]
end
end
- # Remove and get the first element in a list.
+ # Insert an element before or after another element in a list.
#
# @param [String] key
- # @return [String]
- def lpop(key)
+ # @param [String, Symbol] where `BEFORE` or `AFTER`
+ # @param [String] pivot reference element
+ # @param [String] value
+ # @return [Fixnum] length of the list after the insert operation, or `-1`
+ # when the element `pivot` was not found
+ def linsert(key, where, pivot, value)
synchronize do |client|
- client.call [:lpop, key]
+ client.call [:linsert, key, where, pivot, value]
end
end
- # Interact with the slowlog (get, len, reset)
+ # Get a range of elements from a list.
#
- # @param [String] subcommand e.g. `get`, `len`, `reset`
- # @param [Fixnum] length maximum number of entries to return
- # @return [Array<String>, Fixnum, String] depends on subcommand
- def slowlog(subcommand, length=nil)
+ # @param [String] key
+ # @param [Fixnum] start start index
+ # @param [Fixnum] stop stop index
+ # @return [Array<String>]
+ def lrange(key, start, stop)
synchronize do |client|
- args = [:slowlog, subcommand]
- args << length if length
- client.call args
+ client.call [:lrange, key, start, stop]
end
end
- # Get all the members in a set.
+ # Remove elements from a list.
#
# @param [String] key
- # @return [Array<String>]
- def smembers(key)
+ # @param [Fixnum] count number of elements to remove. Use a positive
+ # value to remove the first `count` occurrences of `value`. A negative
+ # value to remove the last `count` occurrences of `value`. Or zero, to
+ # remove all occurrences of `value` from the list.
+ # @param [String] value
+ # @return [Fixnum] the number of removed elements
+ def lrem(key, count, value)
synchronize do |client|
- client.call [:smembers, key]
+ client.call [:lrem, key, count, value]
end
end
- # Determine if a given value is a member of a set.
+ # Set the value of an element in a list by its index.
#
# @param [String] key
- # @param [String] member
- # @return [Boolean]
- def sismember(key, member)
+ # @param [Fixnum] index
+ # @param [String] value
+ # @return [String] `OK`
+ def lset(key, index, value)
synchronize do |client|
- client.call [:sismember, key, member], &_boolify
+ client.call [:lset, key, index, value]
end
end
+ # Trim a list to the specified range.
+ #
+ # @param [String] key
+ # @param [Fixnum] start start index
+ # @param [Fixnum] stop stop index
+ # @return [String] `OK`
+ def ltrim(key, start, stop)
+ synchronize do |client|
+ client.call [:ltrim, key, start, stop]
+ end
+ end
+
+ # Get the number of members in a set.
+ #
+ # @param [String] key
+ # @return [Fixnum]
+ def scard(key)
+ synchronize do |client|
+ client.call [:scard, key]
+ end
+ end
+
# Add one or more members to a set.
#
# @param [String] key
# @param [String, Array<String>] member one member, or array of members
# @return [Boolean, Fixnum] `Boolean` when a single member is specified,
@@ -693,10 +1141,30 @@
end
end
end
end
+ # Remove and return a random member from a set.
+ #
+ # @param [String] key
+ # @return [String]
+ def spop(key)
+ synchronize do |client|
+ client.call [:spop, key]
+ end
+ end
+
+ # Get a random member from a set.
+ #
+ # @param [String] key
+ # @return [String]
+ def srandmember(key)
+ synchronize do |client|
+ client.call [:srandmember, key]
+ end
+ end
+
# Move a member from one set to another.
#
# @param [String] source source key
# @param [String] destination destination key
# @param [String] member member to move from `source` to `destination`
@@ -705,30 +1173,52 @@
synchronize do |client|
client.call [:smove, source, destination, member], &_boolify
end
end
- # Remove and return a random member from a set.
+ # Determine if a given value is a member of a set.
#
# @param [String] key
- # @return [String]
- def spop(key)
+ # @param [String] member
+ # @return [Boolean]
+ def sismember(key, member)
synchronize do |client|
- client.call [:spop, key]
+ client.call [:sismember, key, member], &_boolify
end
end
- # Get the number of members in a set.
+ # Get all the members in a set.
#
# @param [String] key
- # @return [Fixnum]
- def scard(key)
+ # @return [Array<String>]
+ def smembers(key)
synchronize do |client|
- client.call [:scard, key]
+ client.call [:smembers, key]
end
end
+ # Subtract multiple sets.
+ #
+ # @param [String, Array<String>] keys keys pointing to sets to subtract
+ # @return [Array<String>] members in the difference
+ def sdiff(*keys)
+ synchronize do |client|
+ client.call [:sdiff, *keys]
+ end
+ end
+
+ # Subtract multiple sets and store the resulting set in a key.
+ #
+ # @param [String] destination destination key
+ # @param [String, Array<String>] keys keys pointing to sets to subtract
+ # @return [Fixnum] number of elements in the resulting set
+ def sdiffstore(destination, *keys)
+ synchronize do |client|
+ client.call [:sdiffstore, destination, *keys]
+ end
+ end
+
# Intersect multiple sets.
#
# @param [String, Array<String>] keys keys pointing to sets to intersect
# @return [Array<String>] members in the intersection
def sinter(*keys)
@@ -767,38 +1257,21 @@
synchronize do |client|
client.call [:sunionstore, destination, *keys]
end
end
- # Subtract multiple sets.
+ # Get the number of members in a sorted set.
#
- # @param [String, Array<String>] keys keys pointing to sets to subtract
- # @return [Array<String>] members in the difference
- def sdiff(*keys)
- synchronize do |client|
- client.call [:sdiff, *keys]
- end
- end
-
- # Subtract multiple sets and store the resulting set in a key.
+ # @example
+ # redis.zcard("zset")
+ # # => 4
#
- # @param [String] destination destination key
- # @param [String, Array<String>] keys keys pointing to sets to subtract
- # @return [Fixnum] number of elements in the resulting set
- def sdiffstore(destination, *keys)
- synchronize do |client|
- client.call [:sdiffstore, destination, *keys]
- end
- end
-
- # Get a random member from a set.
- #
# @param [String] key
- # @return [String]
- def srandmember(key)
+ # @return [Fixnum]
+ def zcard(key)
synchronize do |client|
- client.call [:srandmember, key]
+ client.call [:zcard, key]
end
end
# Add one or more members to a sorted set, or update the score for members
# that already exist.
@@ -830,10 +1303,28 @@
raise ArgumentError, "wrong number of arguments"
end
end
end
+ # Increment the score of a member in a sorted set.
+ #
+ # @example
+ # redis.zincrby("zset", 32.0, "a")
+ # # => 64.0
+ #
+ # @param [String] key
+ # @param [Float] increment
+ # @param [String] member
+ # @return [Float] score of the member after incrementing it
+ def zincrby(key, increment, member)
+ synchronize do |client|
+ client.call [:zincrby, key, increment, member] do |reply|
+ Float(reply) if reply
+ end
+ end
+ end
+
# Remove one or more members from a sorted set.
#
# @example Remove a single member from a sorted set
# redis.zrem("zset", "a")
# @example Remove an array of members from a sorted set
@@ -861,65 +1352,27 @@
end
end
end
end
- # Determine the index of a member in a sorted set.
+ # Get the score associated with the given member in a sorted set.
#
- # @param [String] key
- # @param [String] member
- # @return [Fixnum]
- def zrank(key, member)
- synchronize do |client|
- client.call [:zrank, key, member]
- end
- end
-
- # Determine the index of a member in a sorted set, with scores ordered from
- # high to low.
+ # @example Get the score for member "a"
+ # redis.zscore("zset", "a")
+ # # => 32.0
#
# @param [String] key
# @param [String] member
- # @return [Fixnum]
- def zrevrank(key, member)
+ # @return [Float] score of the member
+ def zscore(key, member)
synchronize do |client|
- client.call [:zrevrank, key, member]
- end
- end
-
- # Increment the score of a member in a sorted set.
- #
- # @example
- # redis.zincrby("zset", 32.0, "a")
- # # => 64.0
- #
- # @param [String] key
- # @param [Float] increment
- # @param [String] member
- # @return [Float] score of the member after incrementing it
- def zincrby(key, increment, member)
- synchronize do |client|
- client.call [:zincrby, key, increment, member] do |reply|
+ client.call [:zscore, key, member] do |reply|
Float(reply) if reply
end
end
end
- # Get the number of members in a sorted set.
- #
- # @example
- # redis.zcard("zset")
- # # => 4
- #
- # @param [String] key
- # @return [Fixnum]
- def zcard(key)
- synchronize do |client|
- client.call [:zcard, key]
- end
- end
-
# Return a range of members in a sorted set, by index.
#
# @example Retrieve all members from a sorted set
# redis.zrange("zset", 0, -1)
# # => ["a", "b"]
@@ -987,10 +1440,52 @@
end
end
end
end
+ # Determine the index of a member in a sorted set.
+ #
+ # @param [String] key
+ # @param [String] member
+ # @return [Fixnum]
+ def zrank(key, member)
+ synchronize do |client|
+ client.call [:zrank, key, member]
+ end
+ end
+
+ # Determine the index of a member in a sorted set, with scores ordered from
+ # high to low.
+ #
+ # @param [String] key
+ # @param [String] member
+ # @return [Fixnum]
+ def zrevrank(key, member)
+ synchronize do |client|
+ client.call [:zrevrank, key, member]
+ end
+ end
+
+ # Remove all members in a sorted set within the given indexes.
+ #
+ # @example Remove first 5 members
+ # redis.zremrangebyrank("zset", 0, 4)
+ # # => 5
+ # @example Remove last 5 members
+ # redis.zremrangebyrank("zset", -5, -1)
+ # # => 5
+ #
+ # @param [String] key
+ # @param [Fixnum] start start index
+ # @param [Fixnum] stop stop index
+ # @return [Fixnum] number of members that were removed
+ def zremrangebyrank(key, start, stop)
+ synchronize do |client|
+ client.call [:zremrangebyrank, key, start, stop]
+ end
+ end
+
# Return a range of members in a sorted set, by score.
#
# @example Retrieve members with score `>= 5` and `< 100`
# redis.zrangebyscore("zset", "5", "(100")
# # => ["a", "b"]
@@ -1076,92 +1571,56 @@
end
end
end
end
- # Count the members in a sorted set with scores within the given values.
+ # Remove all members in a sorted set within the given scores.
#
- # @example Count members with score `>= 5` and `< 100`
- # redis.zcount("zset", "5", "(100")
+ # @example Remove members with score `>= 5` and `< 100`
+ # redis.zremrangebyscore("zset", "5", "(100")
# # => 2
- # @example Count members with scores `> 5`
- # redis.zcount("zset", "(5", "+inf")
+ # @example Remove members with scores `> 5`
+ # redis.zremrangebyscore("zset", "(5", "+inf")
# # => 2
#
# @param [String] key
# @param [String] min
# - inclusive minimum score is specified verbatim
# - exclusive minimum score is specified by prefixing `(`
# @param [String] max
# - inclusive maximum score is specified verbatim
# - exclusive maximum score is specified by prefixing `(`
- # @return [Fixnum] number of members in within the specified range
- def zcount(key, min, max)
+ # @return [Fixnum] number of members that were removed
+ def zremrangebyscore(key, min, max)
synchronize do |client|
- client.call [:zcount, key, min, max]
+ client.call [:zremrangebyscore, key, min, max]
end
end
- # Remove all members in a sorted set within the given scores.
+ # Count the members in a sorted set with scores within the given values.
#
- # @example Remove members with score `>= 5` and `< 100`
- # redis.zremrangebyscore("zset", "5", "(100")
+ # @example Count members with score `>= 5` and `< 100`
+ # redis.zcount("zset", "5", "(100")
# # => 2
- # @example Remove members with scores `> 5`
- # redis.zremrangebyscore("zset", "(5", "+inf")
+ # @example Count members with scores `> 5`
+ # redis.zcount("zset", "(5", "+inf")
# # => 2
#
# @param [String] key
# @param [String] min
# - inclusive minimum score is specified verbatim
# - exclusive minimum score is specified by prefixing `(`
# @param [String] max
# - inclusive maximum score is specified verbatim
# - exclusive maximum score is specified by prefixing `(`
- # @return [Fixnum] number of members that were removed
- def zremrangebyscore(key, min, max)
+ # @return [Fixnum] number of members in within the specified range
+ def zcount(key, min, max)
synchronize do |client|
- client.call [:zremrangebyscore, key, min, max]
+ client.call [:zcount, key, min, max]
end
end
- # Remove all members in a sorted set within the given indexes.
- #
- # @example Remove first 5 members
- # redis.zremrangebyrank("zset", 0, 4)
- # # => 5
- # @example Remove last 5 members
- # redis.zremrangebyrank("zset", -5, -1)
- # # => 5
- #
- # @param [String] key
- # @param [Fixnum] start start index
- # @param [Fixnum] stop stop index
- # @return [Fixnum] number of members that were removed
- def zremrangebyrank(key, start, stop)
- synchronize do |client|
- client.call [:zremrangebyrank, key, start, stop]
- end
- end
-
- # Get the score associated with the given member in a sorted set.
- #
- # @example Get the score for member "a"
- # redis.zscore("zset", "a")
- # # => 32.0
- #
- # @param [String] key
- # @param [String] member
- # @return [Float] score of the member
- def zscore(key, member)
- synchronize do |client|
- client.call [:zscore, key, member] do |reply|
- Float(reply) if reply
- end
- end
- end
-
# Intersect multiple sorted sets and store the resulting sorted set in a new
# key.
#
# @example Compute the intersection of `2*zsetA` with `1*zsetB`, summing their scores
# redis.zinterstore("zsetC", ["zsetA", "zsetB"], :weights => [2.0, 1.0], :aggregate => "sum")
@@ -1213,153 +1672,20 @@
synchronize do |client|
client.call [:zunionstore, destination, keys.size, *(keys + args)]
end
end
- # Move a key to another database.
+ # Get the number of fields in a hash.
#
- # @example Move a key to another database
- # redis.set "foo", "bar"
- # # => "OK"
- # redis.move "foo", 2
- # # => true
- # redis.exists "foo"
- # # => false
- # redis.select 2
- # # => "OK"
- # redis.exists "foo"
- # # => true
- # resis.get "foo"
- # # => "bar"
- #
# @param [String] key
- # @param [Fixnum] db
- # @return [Boolean] whether the key was moved or not
- def move(key, db)
+ # @return [Fixnum] number of fields in the hash
+ def hlen(key)
synchronize do |client|
- client.call [:move, key, db], &_boolify
+ client.call [:hlen, key]
end
end
- # Set the value of a key, only if the key does not exist.
- #
- # @param [String] key
- # @param [String] value
- # @return [Boolean] whether the key was set or not
- def setnx(key, value)
- synchronize do |client|
- client.call [:setnx, key, value], &_boolify
- end
- end
-
- # Delete one or more keys.
- #
- # @param [String, Array<String>] keys
- # @return [Fixnum] number of keys that were deleted
- def del(*keys)
- synchronize do |client|
- client.call [:del, *keys]
- end
- end
-
- # Rename a key. If the new key already exists it is overwritten.
- #
- # @param [String] old_name
- # @param [String] new_name
- # @return [String] `OK`
- def rename(old_name, new_name)
- synchronize do |client|
- client.call [:rename, old_name, new_name]
- end
- end
-
- # Rename a key, only if the new key does not exist.
- #
- # @param [String] old_name
- # @param [String] new_name
- # @return [Boolean] whether the key was renamed or not
- def renamenx(old_name, new_name)
- synchronize do |client|
- client.call [:renamenx, old_name, new_name], &_boolify
- end
- end
-
- # Set a key's time to live in seconds.
- #
- # @param [String] key
- # @param [Fixnum] seconds time to live
- # @return [Boolean] whether the timeout was set or not
- def expire(key, seconds)
- synchronize do |client|
- client.call [:expire, key, seconds], &_boolify
- end
- end
-
- # Set a key's time to live in milliseconds.
- #
- # @param [String] key
- # @param [Fixnum] milliseconds time to live
- # @return [Boolean] whether the timeout was set or not
- def pexpire(key, milliseconds)
- synchronize do |client|
- client.call [:pexpire, key, milliseconds], &_boolify
- end
- end
-
- # Remove the expiration from a key.
- #
- # @param [String] key
- # @return [Boolean] whether the timeout was removed or not
- def persist(key)
- synchronize do |client|
- client.call [:persist, key], &_boolify
- end
- end
-
- # Get the time to live (in seconds) for a key.
- #
- # @param [String] key
- # @return [Fixnum] remaining time to live in seconds, or -1 if the
- # key does not exist or does not have a timeout
- def ttl(key)
- synchronize do |client|
- client.call [:ttl, key]
- end
- end
-
- # Get the time to live (in milliseconds) for a key.
- #
- # @param [String] key
- # @return [Fixnum] remaining time to live in milliseconds, or -1 if the
- # key does not exist or does not have a timeout
- def pttl(key)
- synchronize do |client|
- client.call [:pttl, key]
- end
- end
-
- # Set the expiration for a key as a UNIX timestamp.
- #
- # @param [String] key
- # @param [Fixnum] unix_time expiry time specified as a UNIX timestamp
- # @return [Boolean] whether the timeout was set or not
- def expireat(key, unix_time)
- synchronize do |client|
- client.call [:expireat, key, unix_time], &_boolify
- end
- end
-
- # Set the expiration for a key as number of milliseconds from UNIX Epoch.
- #
- # @param [String] key
- # @param [Fixnum] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
- # @return [Boolean] whether the timeout was set or not
- def pexpireat(key, ms_unix_time)
- synchronize do |client|
- client.call [:pexpireat, key, ms_unix_time], &_boolify
- end
- end
# Set the string value of a hash field.
#
# @param [String] key
# @param [String] field
# @param [String] value
@@ -1412,10 +1738,21 @@
# @see #hmset
def mapped_hmset(key, hash)
hmset(key, *hash.to_a.flatten)
end
+ # Get the value of a hash field.
+ #
+ # @param [String] key
+ # @param [String] field
+ # @return [String]
+ def hget(key, field)
+ synchronize do |client|
+ client.call [:hget, key, field]
+ end
+ end
+
# Get the values of all the given hash fields.
#
# @example
# redis.hmget("hash", "f1", "f2")
# # => ["v1", "v2"]
@@ -1454,27 +1791,29 @@
reply
end
end
end
- # Get the number of fields in a hash.
+ # Delete one or more hash fields.
#
# @param [String] key
- # @return [Fixnum] number of fields in the hash
- def hlen(key)
+ # @param [String, Array<String>] field
+ # @return [Fixnum] the number of fields that were removed from the hash
+ def hdel(key, field)
synchronize do |client|
- client.call [:hlen, key]
+ client.call [:hdel, key, field]
end
end
- # Get all the values in a hash.
+ # Determine if a hash field exists.
#
# @param [String] key
- # @return [Array<String>]
- def hvals(key)
+ # @param [String] field
+ # @return [Boolean] whether or not the field exists in the hash
+ def hexists(key, field)
synchronize do |client|
- client.call [:hvals, key]
+ client.call [:hexists, key, field], &_boolify
end
end
# Increment the integer value of a hash field by the given integer number.
#
@@ -1500,385 +1839,83 @@
Float(reply) if reply
end
end
end
- # Determine if a hash field exists.
+ # Get all the fields in a hash.
#
# @param [String] key
- # @param [String] field
- # @return [Boolean] whether or not the field exists in the hash
- def hexists(key, field)
+ # @return [Array<String>]
+ def hkeys(key)
synchronize do |client|
- client.call [:hexists, key, field], &_boolify
+ client.call [:hkeys, key]
end
end
- # Listen for all requests received by the server in real time.
+ # Get all the values in a hash.
#
- # There is no way to interrupt this command.
- #
- # @yield a block to be called for every line of output
- # @yieldparam [String] line timestamp and command that was executed
- def monitor(&block)
- synchronize do |client|
- client.call_loop([:monitor], &block)
- end
- end
-
- def debug(*args)
- synchronize do |client|
- client.call [:debug, *args]
- end
- end
-
- def object(*args)
- synchronize do |client|
- client.call [:object, *args]
- end
- end
-
- # Internal command used for replication.
- def sync
- synchronize do |client|
- client.call [:sync]
- end
- end
-
- # Set the string value of a key.
- #
# @param [String] key
- # @param [String] value
- # @return `"OK"`
- def set(key, value)
+ # @return [Array<String>]
+ def hvals(key)
synchronize do |client|
- client.call [:set, key, value]
+ client.call [:hvals, key]
end
end
- alias :[]= :set
-
- # Sets or clears the bit at offset in the string value stored at key.
+ # Get all the fields and values in a hash.
#
# @param [String] key
- # @param [Fixnum] offset bit offset
- # @param [Fixnum] value bit value `0` or `1`
- # @return [Fixnum] the original bit value stored at `offset`
- def setbit(key, offset, value)
+ # @return [Hash<String, String>]
+ def hgetall(key)
synchronize do |client|
- client.call [:setbit, key, offset, value]
+ client.call [:hgetall, key], &_hashify
end
end
- # Set the time to live in seconds of a key.
- #
- # @param [String] key
- # @param [Fixnum] ttl
- # @param [String] value
- # @return `"OK"`
- def setex(key, ttl, value)
+ # Post a message to a channel.
+ def publish(channel, message)
synchronize do |client|
- client.call [:setex, key, ttl, value]
+ client.call [:publish, channel, message]
end
end
- # Set the time to live in milliseconds of a key.
- #
- # @param [String] key
- # @param [Fixnum] ttl
- # @param [String] value
- # @return `"OK"`
- def psetex(key, ttl, value)
+ def subscribed?
synchronize do |client|
- client.call [:psetex, key, ttl, value]
+ client.kind_of? SubscribedClient
end
end
- # Overwrite part of a string at key starting at the specified offset.
- #
- # @param [String] key
- # @param [Fixnum] offset byte offset
- # @param [String] value
- # @return [Fixnum] length of the string after it was modified
- def setrange(key, offset, value)
+ # Listen for messages published to the given channels.
+ def subscribe(*channels, &block)
synchronize do |client|
- client.call [:setrange, key, offset, value]
+ _subscription(:subscribe, channels, block)
end
end
- # Set one or more values.
- #
- # @example
- # redis.mset("key1", "v1", "key2", "v2")
- # # => "OK"
- #
- # @param [Array<String>] args array of keys and values
- # @return `"OK"`
- #
- # @see #mapped_mset
- def mset(*args)
+ # Stop listening for messages posted to the given channels.
+ def unsubscribe(*channels)
synchronize do |client|
- client.call [:mset, *args]
+ raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
+ client.unsubscribe(*channels)
end
end
- # Set one or more values.
- #
- # @example
- # redis.mapped_mset({ "f1" => "v1", "f2" => "v2" })
- # # => "OK"
- #
- # @param [Hash] hash keys mapping to values
- # @return `"OK"`
- #
- # @see #mset
- def mapped_mset(hash)
- mset(*hash.to_a.flatten)
- end
-
- # Set one or more values, only if none of the keys exist.
- #
- # @example
- # redis.msetnx("key1", "v1", "key2", "v2")
- # # => true
- #
- # @param [Array<String>] args array of keys and values
- # @return [Boolean] whether or not all values were set
- #
- # @see #mapped_msetnx
- def msetnx(*args)
+ # Listen for messages published to channels matching the given patterns.
+ def psubscribe(*channels, &block)
synchronize do |client|
- client.call [:msetnx, *args], &_boolify
+ _subscription(:psubscribe, channels, block)
end
end
- # Set one or more values, only if none of the keys exist.
- #
- # @example
- # redis.msetnx({ "key1" => "v1", "key2" => "v2" })
- # # => true
- #
- # @param [Hash] hash keys mapping to values
- # @return [Boolean] whether or not all values were set
- #
- # @see #msetnx
- def mapped_msetnx(hash)
- msetnx(*hash.to_a.flatten)
- end
-
- # Get the values of all the given keys.
- #
- # @example
- # redis.mapped_mget("key1", "key1")
- # # => { "key1" => "v1", "key2" => "v2" }
- #
- # @param [Array<String>] keys array of keys
- # @return [Hash] a hash mapping the specified keys to their values
- #
- # @see #mget
- def mapped_mget(*keys)
- mget(*keys) do |reply|
- if reply.kind_of?(Array)
- hash = Hash.new
- keys.zip(reply).each do |field, value|
- hash[field] = value
- end
- hash
- else
- reply
- end
- end
- end
-
- # Sort the elements in a list, set or sorted set.
- #
- # @example Retrieve the first 2 elements from an alphabetically sorted "list"
- # redis.sort("list", :order => "alpha", :limit => [0, 2])
- # # => ["a", "b"]
- # @example Store an alphabetically descending list in "target"
- # redis.sort("list", :order => "desc alpha", :store => "target")
- # # => 26
- #
- # @param [String] key
- # @param [Hash] options
- # - `:by => String`: use external key to sort elements by
- # - `:limit => [offset, count]`: skip `offset` elements, return a maximum
- # of `count` elements
- # - `:get => [String, Array<String>]`: single key or array of keys to
- # retrieve per element in the result
- # - `:order => String`: combination of `ASC`, `DESC` and optionally `ALPHA`
- # - `:store => String`: key to store the result at
- #
- # @return [Array<String>, Array<Array<String>>, Fixnum]
- # - when `:get` is not specified, or holds a single element, an array of elements
- # - when `:get` is specified, and holds more than one element, an array of
- # elements where every element is an array with the result for every
- # element specified in `:get`
- # - when `:store` is specified, the number of elements in the stored result
- def sort(key, options = {})
- args = []
-
- by = options[:by]
- args.concat ["BY", by] if by
-
- limit = options[:limit]
- args.concat ["LIMIT", *limit] if limit
-
- get = Array(options[:get])
- args.concat ["GET"].product(get).flatten unless get.empty?
-
- order = options[:order]
- args.concat order.split(" ") if order
-
- store = options[:store]
- args.concat ["STORE", store] if store
-
+ # Stop listening for messages posted to channels matching the given patterns.
+ def punsubscribe(*channels)
synchronize do |client|
- client.call [:sort, key, *args] do |reply|
- if get.size > 1
- if reply
- reply.each_slice(get.size).to_a
- end
- else
- reply
- end
- end
+ raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
+ client.punsubscribe(*channels)
end
end
- # Increment the integer value of a key by one.
- #
- # @example
- # redis.incr("value")
- # # => 6
- #
- # @param [String] key
- # @return [Fixnum] value after incrementing it
- def incr(key)
- synchronize do |client|
- client.call [:incr, key]
- end
- end
-
- # Increment the integer value of a key by the given integer number.
- #
- # @example
- # redis.incrby("value", 5)
- # # => 10
- #
- # @param [String] key
- # @param [Fixnum] increment
- # @return [Fixnum] value after incrementing it
- def incrby(key, increment)
- synchronize do |client|
- client.call [:incrby, key, increment]
- end
- end
-
- # Increment the numeric value of a key by the given float number.
- #
- # @example
- # redis.incrbyfloat("value", 1.23)
- # # => 1.23
- #
- # @param [String] key
- # @param [Float] increment
- # @return [Float] value after incrementing it
- def incrbyfloat(key, increment)
- synchronize do |client|
- client.call [:incrbyfloat, key, increment] do |reply|
- Float(reply) if reply
- end
- end
- end
-
- # Decrement the integer value of a key by one.
- #
- # @example
- # redis.decr("value")
- # # => 4
- #
- # @param [String] key
- # @return [Fixnum] value after decrementing it
- def decr(key)
- synchronize do |client|
- client.call [:decr, key]
- end
- end
-
- # Decrement the integer value of a key by the given number.
- #
- # @example
- # redis.decrby("value", 5)
- # # => 0
- #
- # @param [String] key
- # @param [Fixnum] decrement
- # @return [Fixnum] value after decrementing it
- def decrby(key, decrement)
- synchronize do |client|
- client.call [:decrby, key, decrement]
- end
- end
-
- # Determine the type stored at key.
- #
- # @param [String] key
- # @return [String] `string`, `list`, `set`, `zset`, `hash` or `none`
- def type(key)
- synchronize do |client|
- client.call [:type, key]
- end
- end
-
- # Close the connection.
- #
- # @return [String] `OK`
- def quit
- synchronize do |client|
- begin
- client.call [:quit]
- rescue ConnectionError
- ensure
- client.disconnect
- end
- end
- end
-
- # Synchronously save the dataset to disk and then shut down the server.
- def shutdown
- synchronize do |client|
- client.without_reconnect do
- begin
- client.call [:shutdown]
- rescue ConnectionError
- # This means Redis has probably exited.
- nil
- end
- end
- end
- end
-
- # Make the server a slave of another instance, or promote it as master.
- def slaveof(host, port)
- synchronize do |client|
- client.call [:slaveof, host, port]
- end
- end
-
- def pipelined
- synchronize do |client|
- begin
- original, @client = @client, Pipeline.new
- yield(self)
- original.call_pipeline(@client)
- ensure
- @client = original
- end
- end
- end
-
# Watch the given keys to determine execution of the MULTI/EXEC block.
#
# Using a block is optional, but is necessary for thread-safety.
#
# An `#unwatch` is automatically issued if an exception is raised within the
@@ -1934,10 +1971,22 @@
synchronize do |client|
client.call [:unwatch]
end
end
+ def pipelined
+ synchronize do |client|
+ begin
+ original, @client = @client, Pipeline.new
+ yield(self)
+ original.call_pipeline(@client)
+ ensure
+ @client = original
+ end
+ end
+ end
+
# Mark the start of a transaction block.
#
# Passing a block is optional.
#
# @example With a block
@@ -2011,50 +2060,118 @@
synchronize do |client|
client.call [:discard]
end
end
- # Post a message to a channel.
- def publish(channel, message)
- synchronize do |client|
- client.call [:publish, channel, message]
- end
- end
+ # Control remote script registry.
+ #
+ # @example Load a script
+ # sha = redis.script(:load, "return 1")
+ # # => <sha of this script>
+ # @example Check if a script exists
+ # redis.script(:exists, sha)
+ # # => true
+ # @example Check if multiple scripts exist
+ # redis.script(:exists, [sha, other_sha])
+ # # => [true, false]
+ # @example Flush the script registry
+ # redis.script(:flush)
+ # # => "OK"
+ # @example Kill a running script
+ # redis.script(:kill)
+ # # => "OK"
+ #
+ # @param [String] subcommand e.g. `exists`, `flush`, `load`, `kill`
+ # @param [Array<String>] args depends on subcommand
+ # @return [String, Boolean, Array<Boolean>, ...] depends on subcommand
+ #
+ # @see #eval
+ # @see #evalsha
+ def script(subcommand, *args)
+ subcommand = subcommand.to_s.downcase
- def subscribed?
- synchronize do |client|
- client.kind_of? SubscribedClient
- end
- end
+ if subcommand == "exists"
+ synchronize do |client|
+ arg = args.first
- # Stop listening for messages posted to the given channels.
- def unsubscribe(*channels)
- synchronize do |client|
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
- client.unsubscribe(*channels)
+ client.call [:script, :exists, arg] do |reply|
+ reply = reply.map { |r| _boolify.call(r) }
+
+ if arg.is_a?(Array)
+ reply
+ else
+ reply.first
+ end
+ end
+ end
+ else
+ synchronize do |client|
+ client.call [:script, subcommand] + args
+ end
end
end
- # Stop listening for messages posted to channels matching the given patterns.
- def punsubscribe(*channels)
+ def _eval(cmd, args)
+ script = args.shift
+ options = args.pop if args.last.is_a?(Hash)
+ options ||= {}
+
+ keys = args.shift || options[:keys] || []
+ argv = args.shift || options[:argv] || []
+
synchronize do |client|
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
- client.punsubscribe(*channels)
+ client.call [cmd, script, keys.length] + keys + argv
end
end
- # Listen for messages published to the given channels.
- def subscribe(*channels, &block)
- synchronize do |client|
- _subscription(:subscribe, channels, block)
- end
+ # Evaluate Lua script.
+ #
+ # @example EVAL without KEYS nor ARGV
+ # redis.eval("return 1")
+ # # => 1
+ # @example EVAL with KEYS and ARGV as array arguments
+ # redis.eval("return { KEYS, ARGV }", ["k1", "k2"], ["a1", "a2"])
+ # # => [["k1", "k2"], ["a1", "a2"]]
+ # @example EVAL with KEYS and ARGV in a hash argument
+ # redis.eval("return { KEYS, ARGV }", :keys => ["k1", "k2"], :argv => ["a1", "a2"])
+ # # => [["k1", "k2"], ["a1", "a2"]]
+ #
+ # @param [Array<String>] keys optional array with keys to pass to the script
+ # @param [Array<String>] argv optional array with arguments to pass to the script
+ # @param [Hash] options
+ # - `:keys => Array<String>`: optional array with keys to pass to the script
+ # - `:argv => Array<String>`: optional array with arguments to pass to the script
+ # @return depends on the script
+ #
+ # @see #script
+ # @see #evalsha
+ def eval(*args)
+ _eval(:eval, args)
end
- # Listen for messages published to channels matching the given patterns.
- def psubscribe(*channels, &block)
- synchronize do |client|
- _subscription(:psubscribe, channels, block)
- end
+ # Evaluate Lua script by its SHA.
+ #
+ # @example EVALSHA without KEYS nor ARGV
+ # redis.evalsha(sha)
+ # # => <depends on script>
+ # @example EVALSHA with KEYS and ARGV as array arguments
+ # redis.evalsha(sha, ["k1", "k2"], ["a1", "a2"])
+ # # => <depends on script>
+ # @example EVALSHA with KEYS and ARGV in a hash argument
+ # redis.evalsha(sha, :keys => ["k1", "k2"], :argv => ["a1", "a2"])
+ # # => <depends on script>
+ #
+ # @param [Array<String>] keys optional array with keys to pass to the script
+ # @param [Array<String>] argv optional array with arguments to pass to the script
+ # @param [Hash] options
+ # - `:keys => Array<String>`: optional array with keys to pass to the script
+ # - `:argv => Array<String>`: optional array with arguments to pass to the script
+ # @return depends on the script
+ #
+ # @see #script
+ # @see #eval
+ def evalsha(*args)
+ _eval(:evalsha, args)
end
def id
synchronize do |client|
client.id