redis 4.8.1 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +138 -1
  3. data/README.md +285 -169
  4. data/lib/redis/client.rb +116 -611
  5. data/lib/redis/commands/bitmaps.rb +14 -4
  6. data/lib/redis/commands/cluster.rb +1 -18
  7. data/lib/redis/commands/connection.rb +5 -10
  8. data/lib/redis/commands/geo.rb +109 -7
  9. data/lib/redis/commands/hashes.rb +179 -8
  10. data/lib/redis/commands/hyper_log_log.rb +1 -1
  11. data/lib/redis/commands/keys.rb +32 -24
  12. data/lib/redis/commands/lists.rb +167 -25
  13. data/lib/redis/commands/modules/json.rb +530 -0
  14. data/lib/redis/commands/modules/search/aggregation.rb +418 -0
  15. data/lib/redis/commands/modules/search/dialect.rb +14 -0
  16. data/lib/redis/commands/modules/search/field.rb +306 -0
  17. data/lib/redis/commands/modules/search/hybrid.rb +359 -0
  18. data/lib/redis/commands/modules/search/index.rb +351 -0
  19. data/lib/redis/commands/modules/search/index_definition.rb +114 -0
  20. data/lib/redis/commands/modules/search/miscellaneous.rb +607 -0
  21. data/lib/redis/commands/modules/search/query.rb +738 -0
  22. data/lib/redis/commands/modules/search/result.rb +488 -0
  23. data/lib/redis/commands/modules/search/schema.rb +211 -0
  24. data/lib/redis/commands/modules/search.rb +19 -0
  25. data/lib/redis/commands/pubsub.rb +34 -25
  26. data/lib/redis/commands/server.rb +15 -15
  27. data/lib/redis/commands/sets.rb +76 -40
  28. data/lib/redis/commands/sorted_sets.rb +128 -19
  29. data/lib/redis/commands/streams.rb +75 -28
  30. data/lib/redis/commands/strings.rb +18 -17
  31. data/lib/redis/commands/transactions.rb +7 -31
  32. data/lib/redis/commands.rb +39 -20
  33. data/lib/redis/distributed.rb +407 -73
  34. data/lib/redis/errors.rb +20 -50
  35. data/lib/redis/hash_ring.rb +26 -26
  36. data/lib/redis/lib_identity.rb +105 -0
  37. data/lib/redis/pipeline.rb +47 -222
  38. data/lib/redis/subscribe.rb +51 -15
  39. data/lib/redis/version.rb +1 -1
  40. data/lib/redis.rb +213 -188
  41. metadata +25 -59
  42. data/lib/redis/cluster/command.rb +0 -79
  43. data/lib/redis/cluster/command_loader.rb +0 -33
  44. data/lib/redis/cluster/key_slot_converter.rb +0 -72
  45. data/lib/redis/cluster/node.rb +0 -120
  46. data/lib/redis/cluster/node_key.rb +0 -31
  47. data/lib/redis/cluster/node_loader.rb +0 -34
  48. data/lib/redis/cluster/option.rb +0 -100
  49. data/lib/redis/cluster/slot.rb +0 -86
  50. data/lib/redis/cluster/slot_loader.rb +0 -46
  51. data/lib/redis/cluster.rb +0 -315
  52. data/lib/redis/connection/command_helper.rb +0 -41
  53. data/lib/redis/connection/hiredis.rb +0 -68
  54. data/lib/redis/connection/registry.rb +0 -13
  55. data/lib/redis/connection/ruby.rb +0 -437
  56. data/lib/redis/connection/synchrony.rb +0 -148
  57. data/lib/redis/connection.rb +0 -11
@@ -30,6 +30,84 @@ class Redis
30
30
  send_command([:lmove, source, destination, where_source, where_destination])
31
31
  end
32
32
 
33
+ # Remove multiple elements from the head/tail of a list, append/prepend
34
+ # them to another list and return them.
35
+ #
36
+ # @example Move a single element (still an array reply)
37
+ # redis.lmovem("foo", "bar", "LEFT", "LEFT")
38
+ # # => ["s1"]
39
+ # @example Move up to 3 elements, pushed one-by-one (block order reversed)
40
+ # redis.lmovem("foo", "bar", "LEFT", "LEFT", count: 3, order: "OBO")
41
+ # # => ["s3", "s2", "s1"]
42
+ # @example Move exactly 2 elements, preserving their relative order
43
+ # redis.lmovem("foo", "bar", "LEFT", "RIGHT", exactly: 2, order: "BULK")
44
+ # # => ["s1", "s2"]
45
+ #
46
+ # @param [String] source source key
47
+ # @param [String] destination destination key
48
+ # @param [String, Symbol] where_source from where to remove elements from the source list
49
+ # e.g. 'LEFT' - from head, 'RIGHT' - from tail
50
+ # @param [String, Symbol] where_destination where to push elements to the destination list
51
+ # e.g. 'LEFT' - to head, 'RIGHT' - to tail
52
+ # @param [Integer] count move up to `count` elements, fewer when the source holds fewer
53
+ # @param [Integer] exactly move exactly `exactly` elements; when the source holds fewer,
54
+ # nothing is moved
55
+ # @param [String, Symbol] order ordering at the destination, required together with
56
+ # `count` or `exactly`:
57
+ # - when `'OBO'` - push each element as popped, so the moved block order is reversed
58
+ # - when `'BULK'` - preserve the original relative order of the moved elements
59
+ #
60
+ # @return [nil, Array<String>] the moved elements in destination order, or nil when
61
+ # nothing was moved
62
+ def lmovem(source, destination, where_source, where_destination, count: nil, exactly: nil, order: nil)
63
+ where_source, where_destination = _normalize_move_wheres(where_source, where_destination)
64
+
65
+ args = [:lmovem, source, destination, where_source, where_destination]
66
+ args.concat(_movem_amount_args(count, exactly, order))
67
+
68
+ send_command(args)
69
+ end
70
+
71
+ # Remove multiple elements from the head/tail of a list, append/prepend
72
+ # them to another list and return them; or block until the request can
73
+ # be satisfied or the timeout expires.
74
+ #
75
+ # @example Move up to 3 elements as soon as any are available
76
+ # redis.blmovem("foo", "bar", "LEFT", "LEFT", timeout: 1, count: 3, order: "BULK")
77
+ # # => ["s1", "s2", "s3"]
78
+ # @example Block until the source holds at least 2 elements
79
+ # redis.blmovem("foo", "bar", "LEFT", "RIGHT", timeout: 1, exactly: 2, order: "OBO")
80
+ # # => nil on timeout
81
+ #
82
+ # @param [String] source source key
83
+ # @param [String] destination destination key
84
+ # @param [String, Symbol] where_source from where to remove elements from the source list
85
+ # e.g. 'LEFT' - from head, 'RIGHT' - from tail
86
+ # @param [String, Symbol] where_destination where to push elements to the destination list
87
+ # e.g. 'LEFT' - to head, 'RIGHT' - to tail
88
+ # @param [Float, Integer] timeout seconds to block, 0 blocks indefinitely
89
+ # @param [Integer] count move up to `count` elements as soon as at least one is available
90
+ # @param [Integer] exactly move exactly `exactly` elements, blocking until the source
91
+ # holds that many
92
+ # @param [String, Symbol] order ordering at the destination, required together with
93
+ # `count` or `exactly`:
94
+ # - when `'OBO'` - push each element as popped, so the moved block order is reversed
95
+ # - when `'BULK'` - preserve the original relative order of the moved elements
96
+ #
97
+ # @return [nil, Array<String>] the moved elements in destination order, or nil when the
98
+ # timeout expired and nothing was moved
99
+ #
100
+ # @see #lmovem
101
+ def blmovem(source, destination, where_source, where_destination, timeout: 0, count: nil, exactly: nil,
102
+ order: nil)
103
+ where_source, where_destination = _normalize_move_wheres(where_source, where_destination)
104
+
105
+ command = [:blmovem, source, destination, where_source, where_destination, timeout]
106
+ command.concat(_movem_amount_args(count, exactly, order))
107
+
108
+ send_blocking_command(command, timeout)
109
+ end
110
+
33
111
  # Remove the first/last element in a list and append/prepend it
34
112
  # to another list and return it, or block until one is available.
35
113
  #
@@ -48,7 +126,7 @@ class Redis
48
126
  # @param [String, Symbol] where_destination where to push the element to the source list
49
127
  # e.g. 'LEFT' - to head, 'RIGHT' - to tail
50
128
  # @param [Hash] options
51
- # - `:timeout => Numeric`: timeout in seconds, defaults to no timeout
129
+ # - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
52
130
  #
53
131
  # @return [nil, String] the element, or nil when the source key does not exist or the timeout expired
54
132
  #
@@ -99,10 +177,10 @@ class Redis
99
177
  #
100
178
  # @param [String] key
101
179
  # @param [Integer] count number of elements to remove
102
- # @return [String, Array<String>] the values of the first elements
180
+ # @return [nil, String, Array<String>] the values of the first elements
103
181
  def lpop(key, count = nil)
104
182
  command = [:lpop, key]
105
- command << count if count
183
+ command << Integer(count) if count
106
184
  send_command(command)
107
185
  end
108
186
 
@@ -110,10 +188,10 @@ class Redis
110
188
  #
111
189
  # @param [String] key
112
190
  # @param [Integer] count number of elements to remove
113
- # @return [String, Array<String>] the values of the last elements
191
+ # @return [nil, String, Array<String>] the values of the last elements
114
192
  def rpop(key, count = nil)
115
193
  command = [:rpop, key]
116
- command << count if count
194
+ command << Integer(count) if count
117
195
  send_command(command)
118
196
  end
119
197
 
@@ -142,7 +220,7 @@ class Redis
142
220
  # @param [String, Array<String>] keys one or more keys to perform the
143
221
  # blocking pop on
144
222
  # @param [Hash] options
145
- # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
223
+ # - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
146
224
  #
147
225
  # @return [nil, [String, String]]
148
226
  # - `nil` when the operation timed out
@@ -156,7 +234,7 @@ class Redis
156
234
  # @param [String, Array<String>] keys one or more keys to perform the
157
235
  # blocking pop on
158
236
  # @param [Hash] options
159
- # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
237
+ # - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
160
238
  #
161
239
  # @return [nil, [String, String]]
162
240
  # - `nil` when the operation timed out
@@ -173,23 +251,77 @@ class Redis
173
251
  # @param [String] source source key
174
252
  # @param [String] destination destination key
175
253
  # @param [Hash] options
176
- # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
254
+ # - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
177
255
  #
178
256
  # @return [nil, String]
179
257
  # - `nil` when the operation timed out
180
258
  # - the element was popped and pushed otherwise
181
- def brpoplpush(source, destination, deprecated_timeout = 0, timeout: deprecated_timeout)
259
+ def brpoplpush(source, destination, timeout: 0)
182
260
  command = [:brpoplpush, source, destination, timeout]
183
261
  send_blocking_command(command, timeout)
184
262
  end
185
263
 
264
+ # Pops one or more elements from the first non-empty list key from the list
265
+ # of provided key names. If lists are empty, blocks until timeout has passed.
266
+ #
267
+ # @example Popping a element
268
+ # redis.blmpop(1.0, 'list')
269
+ # #=> ['list', ['a']]
270
+ # @example With count option
271
+ # redis.blmpop(1.0, 'list', count: 2)
272
+ # #=> ['list', ['a', 'b']]
273
+ #
274
+ # @params timeout [Float] a float value specifying the maximum number of seconds to block) elapses.
275
+ # A timeout of zero can be used to block indefinitely.
276
+ # @params key [String, Array<String>] one or more keys with lists
277
+ # @params modifier [String]
278
+ # - when `"LEFT"` - the elements popped are those from the left of the list
279
+ # - when `"RIGHT"` - the elements popped are those from the right of the list
280
+ # @params count [Integer] a number of elements to pop
281
+ #
282
+ # @return [Array<String, Array<String, Float>>] list of popped elements or nil
283
+ def blmpop(timeout, *keys, modifier: "LEFT", count: nil)
284
+ raise ArgumentError, "Pick either LEFT or RIGHT" unless modifier == "LEFT" || modifier == "RIGHT"
285
+
286
+ args = [:blmpop, timeout, keys.size, *keys, modifier]
287
+ args << "COUNT" << Integer(count) if count
288
+
289
+ send_blocking_command(args, timeout)
290
+ end
291
+
292
+ # Pops one or more elements from the first non-empty list key from the list
293
+ # of provided key names.
294
+ #
295
+ # @example Popping a element
296
+ # redis.lmpop('list')
297
+ # #=> ['list', ['a']]
298
+ # @example With count option
299
+ # redis.lmpop('list', count: 2)
300
+ # #=> ['list', ['a', 'b']]
301
+ #
302
+ # @params key [String, Array<String>] one or more keys with lists
303
+ # @params modifier [String]
304
+ # - when `"LEFT"` - the elements popped are those from the left of the list
305
+ # - when `"RIGHT"` - the elements popped are those from the right of the list
306
+ # @params count [Integer] a number of elements to pop
307
+ #
308
+ # @return [Array<String, Array<String, Float>>] list of popped elements or nil
309
+ def lmpop(*keys, modifier: "LEFT", count: nil)
310
+ raise ArgumentError, "Pick either LEFT or RIGHT" unless modifier == "LEFT" || modifier == "RIGHT"
311
+
312
+ args = [:lmpop, keys.size, *keys, modifier]
313
+ args << "COUNT" << Integer(count) if count
314
+
315
+ send_command(args)
316
+ end
317
+
186
318
  # Get an element from a list by its index.
187
319
  #
188
320
  # @param [String] key
189
321
  # @param [Integer] index
190
322
  # @return [String]
191
323
  def lindex(key, index)
192
- send_command([:lindex, key, index])
324
+ send_command([:lindex, key, Integer(index)])
193
325
  end
194
326
 
195
327
  # Insert an element before or after another element in a list.
@@ -211,7 +343,7 @@ class Redis
211
343
  # @param [Integer] stop stop index
212
344
  # @return [Array<String>]
213
345
  def lrange(key, start, stop)
214
- send_command([:lrange, key, start, stop])
346
+ send_command([:lrange, key, Integer(start), Integer(stop)])
215
347
  end
216
348
 
217
349
  # Remove elements from a list.
@@ -224,7 +356,7 @@ class Redis
224
356
  # @param [String] value
225
357
  # @return [Integer] the number of removed elements
226
358
  def lrem(key, count, value)
227
- send_command([:lrem, key, count, value])
359
+ send_command([:lrem, key, Integer(count), value])
228
360
  end
229
361
 
230
362
  # Set the value of an element in a list by its index.
@@ -234,7 +366,7 @@ class Redis
234
366
  # @param [String] value
235
367
  # @return [String] `OK`
236
368
  def lset(key, index, value)
237
- send_command([:lset, key, index, value])
369
+ send_command([:lset, key, Integer(index), value])
238
370
  end
239
371
 
240
372
  # Trim a list to the specified range.
@@ -244,7 +376,7 @@ class Redis
244
376
  # @param [Integer] stop stop index
245
377
  # @return [String] `OK`
246
378
  def ltrim(key, start, stop)
247
- send_command([:ltrim, key, start, stop])
379
+ send_command([:ltrim, key, Integer(start), Integer(stop)])
248
380
  end
249
381
 
250
382
  private
@@ -253,24 +385,34 @@ class Redis
253
385
  timeout = if args.last.is_a?(Hash)
254
386
  options = args.pop
255
387
  options[:timeout]
256
- elsif args.last.respond_to?(:to_int)
257
- last_arg = args.pop
258
- ::Redis.deprecate!(
259
- "Passing the timeout as a positional argument is deprecated, it should be passed as a keyword argument:\n" \
260
- " redis.#{cmd}(#{args.map(&:inspect).join(', ')}, timeout: #{last_arg.to_int})" \
261
- "(called from: #{caller(2, 1).first})"
262
- )
263
- last_arg.to_int
264
388
  end
265
389
 
266
390
  timeout ||= 0
391
+ unless timeout.is_a?(Integer) || timeout.is_a?(Float)
392
+ raise ArgumentError, "timeout must be an Integer or Float, got: #{timeout.class}"
393
+ end
267
394
 
268
- keys = args.flatten
269
-
270
- command = [cmd, keys, timeout]
395
+ args.flatten!(1)
396
+ command = [cmd].concat(args)
397
+ command << timeout
271
398
  send_blocking_command(command, timeout, &blk)
272
399
  end
273
400
 
401
+ def _movem_amount_args(count, exactly, order)
402
+ raise ArgumentError, "Pick either count or exactly, not both" if count && exactly
403
+
404
+ if count || exactly
405
+ order = order.to_s.upcase
406
+ raise ArgumentError, "order must be 'OBO' or 'BULK'" if order != "OBO" && order != "BULK"
407
+
408
+ [count ? "COUNT" : "EXACTLY", Integer(count || exactly), order]
409
+ elsif order
410
+ raise ArgumentError, "order requires count or exactly"
411
+ else
412
+ []
413
+ end
414
+ end
415
+
274
416
  def _normalize_move_wheres(where_source, where_destination)
275
417
  where_source = where_source.to_s.upcase
276
418
  where_destination = where_destination.to_s.upcase