1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
|
# frozen_string_literal: true
class Redis
module Commands
module Lists
# Get the length of a list.
#
# @param [String] key
# @return [Integer]
def llen(key)
send_command([:llen, key])
end
# Remove the first/last element in a list, append/prepend it to another list and return it.
#
# @param [String] source source key
# @param [String] destination destination key
# @param [String, Symbol] where_source from where to remove the element from the source list
# e.g. 'LEFT' - from head, 'RIGHT' - from tail
# @param [String, Symbol] where_destination where to push the element to the source list
# e.g. 'LEFT' - to head, 'RIGHT' - to tail
#
# @return [nil, String] the element, or nil when the source key does not exist
#
# @note This command comes in place of the now deprecated RPOPLPUSH.
# Doing LMOVE RIGHT LEFT is equivalent.
def lmove(source, destination, where_source, where_destination)
where_source, where_destination = _normalize_move_wheres(where_source, where_destination)
send_command([:lmove, source, destination, where_source, where_destination])
end
# Remove the first/last element in a list and append/prepend it
# to another list and return it, or block until one is available.
#
# @example With timeout
# element = redis.blmove("foo", "bar", "LEFT", "RIGHT", timeout: 5)
# # => nil on timeout
# # => "element" on success
# @example Without timeout
# element = redis.blmove("foo", "bar", "LEFT", "RIGHT")
# # => "element"
#
# @param [String] source source key
# @param [String] destination destination key
# @param [String, Symbol] where_source from where to remove the element from the source list
# e.g. 'LEFT' - from head, 'RIGHT' - from tail
# @param [String, Symbol] where_destination where to push the element to the source list
# e.g. 'LEFT' - to head, 'RIGHT' - to tail
# @param [Hash] options
# - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
#
# @return [nil, String] the element, or nil when the source key does not exist or the timeout expired
#
def blmove(source, destination, where_source, where_destination, timeout: 0)
where_source, where_destination = _normalize_move_wheres(where_source, where_destination)
command = [:blmove, source, destination, where_source, where_destination, timeout]
send_blocking_command(command, timeout)
end
# Prepend one or more values to a list, creating the list if it doesn't exist
#
# @param [String] key
# @param [String, Array<String>] value string value, or array of string values to push
# @return [Integer] the length of the list after the push operation
def lpush(key, value)
send_command([:lpush, key, value])
end
# Prepend a value to a list, only if the list exists.
#
# @param [String] key
# @param [String] value
# @return [Integer] the length of the list after the push operation
def lpushx(key, value)
send_command([:lpushx, key, value])
end
# Append one or more values to a list, creating the list if it doesn't exist
#
# @param [String] key
# @param [String, Array<String>] value string value, or array of string values to push
# @return [Integer] the length of the list after the push operation
def rpush(key, value)
send_command([:rpush, key, value])
end
# Append a value to a list, only if the list exists.
#
# @param [String] key
# @param [String] value
# @return [Integer] the length of the list after the push operation
def rpushx(key, value)
send_command([:rpushx, key, value])
end
# Remove and get the first elements in a list.
#
# @param [String] key
# @param [Integer] count number of elements to remove
# @return [nil, String, Array<String>] the values of the first elements
def lpop(key, count = nil)
command = [:lpop, key]
command << Integer(count) if count
send_command(command)
end
# Remove and get the last elements in a list.
#
# @param [String] key
# @param [Integer] count number of elements to remove
# @return [nil, String, Array<String>] the values of the last elements
def rpop(key, count = nil)
command = [:rpop, key]
command << Integer(count) if count
send_command(command)
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)
send_command([:rpoplpush, source, destination])
end
# Remove and get the first element in a list, or block until one is available.
#
# @example With timeout
# list, element = redis.blpop("list", :timeout => 5)
# # => nil on timeout
# # => ["list", "element"] on success
# @example Without timeout
# list, element = redis.blpop("list")
# # => ["list", "element"]
# @example Blocking pop on multiple lists
# list, element = redis.blpop(["list", "another_list"])
# # => ["list", "element"]
#
# @param [String, Array<String>] keys one or more keys to perform the
# blocking pop on
# @param [Hash] options
# - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
#
# @return [nil, [String, String]]
# - `nil` when the operation timed out
# - tuple of the list that was popped from and element was popped otherwise
def blpop(*args)
_bpop(:blpop, args)
end
# Remove and get the last element in a list, or block until one is available.
#
# @param [String, Array<String>] keys one or more keys to perform the
# blocking pop on
# @param [Hash] options
# - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
#
# @return [nil, [String, String]]
# - `nil` when the operation timed out
# - tuple of the list that was popped from and element was popped otherwise
#
# @see #blpop
def brpop(*args)
_bpop(:brpop, args)
end
# Pop a value from a list, push it to another list and return it; or block
# until one is available.
#
# @param [String] source source key
# @param [String] destination destination key
# @param [Hash] options
# - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
#
# @return [nil, String]
# - `nil` when the operation timed out
# - the element was popped and pushed otherwise
def brpoplpush(source, destination, timeout: 0)
command = [:brpoplpush, source, destination, timeout]
send_blocking_command(command, timeout)
end
# Pops one or more elements from the first non-empty list key from the list
# of provided key names. If lists are empty, blocks until timeout has passed.
#
# @example Popping a element
# redis.blmpop(1.0, 'list')
# #=> ['list', ['a']]
# @example With count option
# redis.blmpop(1.0, 'list', count: 2)
# #=> ['list', ['a', 'b']]
#
# @params timeout [Float] a float value specifying the maximum number of seconds to block) elapses.
# A timeout of zero can be used to block indefinitely.
# @params key [String, Array<String>] one or more keys with lists
# @params modifier [String]
# - when `"LEFT"` - the elements popped are those from the left of the list
# - when `"RIGHT"` - the elements popped are those from the right of the list
# @params count [Integer] a number of elements to pop
#
# @return [Array<String, Array<String, Float>>] list of popped elements or nil
def blmpop(timeout, *keys, modifier: "LEFT", count: nil)
raise ArgumentError, "Pick either LEFT or RIGHT" unless modifier == "LEFT" || modifier == "RIGHT"
args = [:lmpop, keys.size, *keys, modifier]
args << "COUNT" << Integer(count) if count
send_blocking_command(args, timeout)
end
# Pops one or more elements from the first non-empty list key from the list
# of provided key names.
#
# @example Popping a element
# redis.lmpop('list')
# #=> ['list', ['a']]
# @example With count option
# redis.lmpop('list', count: 2)
# #=> ['list', ['a', 'b']]
#
# @params key [String, Array<String>] one or more keys with lists
# @params modifier [String]
# - when `"LEFT"` - the elements popped are those from the left of the list
# - when `"RIGHT"` - the elements popped are those from the right of the list
# @params count [Integer] a number of elements to pop
#
# @return [Array<String, Array<String, Float>>] list of popped elements or nil
def lmpop(*keys, modifier: "LEFT", count: nil)
raise ArgumentError, "Pick either LEFT or RIGHT" unless modifier == "LEFT" || modifier == "RIGHT"
args = [:lmpop, keys.size, *keys, modifier]
args << "COUNT" << Integer(count) if count
send_command(args)
end
# Get an element from a list by its index.
#
# @param [String] key
# @param [Integer] index
# @return [String]
def lindex(key, index)
send_command([:lindex, key, Integer(index)])
end
# Insert an element before or after another element in a list.
#
# @param [String] key
# @param [String, Symbol] where `BEFORE` or `AFTER`
# @param [String] pivot reference element
# @param [String] value
# @return [Integer] length of the list after the insert operation, or `-1`
# when the element `pivot` was not found
def linsert(key, where, pivot, value)
send_command([:linsert, key, where, pivot, value])
end
# Get a range of elements from a list.
#
# @param [String] key
# @param [Integer] start start index
# @param [Integer] stop stop index
# @return [Array<String>]
def lrange(key, start, stop)
send_command([:lrange, key, Integer(start), Integer(stop)])
end
# Remove elements from a list.
#
# @param [String] key
# @param [Integer] 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 [Integer] the number of removed elements
def lrem(key, count, value)
send_command([:lrem, key, Integer(count), value])
end
# Set the value of an element in a list by its index.
#
# @param [String] key
# @param [Integer] index
# @param [String] value
# @return [String] `OK`
def lset(key, index, value)
send_command([:lset, key, Integer(index), value])
end
# Trim a list to the specified range.
#
# @param [String] key
# @param [Integer] start start index
# @param [Integer] stop stop index
# @return [String] `OK`
def ltrim(key, start, stop)
send_command([:ltrim, key, Integer(start), Integer(stop)])
end
private
def _bpop(cmd, args, &blk)
timeout = if args.last.is_a?(Hash)
options = args.pop
options[:timeout]
end
timeout ||= 0
unless timeout.is_a?(Integer) || timeout.is_a?(Float)
raise ArgumentError, "timeout must be an Integer or Float, got: #{timeout.class}"
end
args.flatten!(1)
command = [cmd].concat(args)
command << timeout
send_blocking_command(command, timeout, &blk)
end
def _normalize_move_wheres(where_source, where_destination)
where_source = where_source.to_s.upcase
where_destination = where_destination.to_s.upcase
if where_source != "LEFT" && where_source != "RIGHT"
raise ArgumentError, "where_source must be 'LEFT' or 'RIGHT'"
end
if where_destination != "LEFT" && where_destination != "RIGHT"
raise ArgumentError, "where_destination must be 'LEFT' or 'RIGHT'"
end
[where_source, where_destination]
end
end
end
end
|