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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +138 -1
- data/README.md +285 -169
- data/lib/redis/client.rb +116 -611
- data/lib/redis/commands/bitmaps.rb +14 -4
- data/lib/redis/commands/cluster.rb +1 -18
- data/lib/redis/commands/connection.rb +5 -10
- data/lib/redis/commands/geo.rb +109 -7
- data/lib/redis/commands/hashes.rb +179 -8
- data/lib/redis/commands/hyper_log_log.rb +1 -1
- data/lib/redis/commands/keys.rb +32 -24
- data/lib/redis/commands/lists.rb +167 -25
- data/lib/redis/commands/modules/json.rb +530 -0
- data/lib/redis/commands/modules/search/aggregation.rb +418 -0
- data/lib/redis/commands/modules/search/dialect.rb +14 -0
- data/lib/redis/commands/modules/search/field.rb +306 -0
- data/lib/redis/commands/modules/search/hybrid.rb +359 -0
- data/lib/redis/commands/modules/search/index.rb +351 -0
- data/lib/redis/commands/modules/search/index_definition.rb +114 -0
- data/lib/redis/commands/modules/search/miscellaneous.rb +607 -0
- data/lib/redis/commands/modules/search/query.rb +738 -0
- data/lib/redis/commands/modules/search/result.rb +488 -0
- data/lib/redis/commands/modules/search/schema.rb +211 -0
- data/lib/redis/commands/modules/search.rb +19 -0
- data/lib/redis/commands/pubsub.rb +34 -25
- data/lib/redis/commands/server.rb +15 -15
- data/lib/redis/commands/sets.rb +76 -40
- data/lib/redis/commands/sorted_sets.rb +128 -19
- data/lib/redis/commands/streams.rb +75 -28
- data/lib/redis/commands/strings.rb +18 -17
- data/lib/redis/commands/transactions.rb +7 -31
- data/lib/redis/commands.rb +39 -20
- data/lib/redis/distributed.rb +407 -73
- data/lib/redis/errors.rb +20 -50
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/lib_identity.rb +105 -0
- data/lib/redis/pipeline.rb +47 -222
- data/lib/redis/subscribe.rb +51 -15
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +213 -188
- metadata +25 -59
- data/lib/redis/cluster/command.rb +0 -79
- data/lib/redis/cluster/command_loader.rb +0 -33
- data/lib/redis/cluster/key_slot_converter.rb +0 -72
- data/lib/redis/cluster/node.rb +0 -120
- data/lib/redis/cluster/node_key.rb +0 -31
- data/lib/redis/cluster/node_loader.rb +0 -34
- data/lib/redis/cluster/option.rb +0 -100
- data/lib/redis/cluster/slot.rb +0 -86
- data/lib/redis/cluster/slot_loader.rb +0 -46
- data/lib/redis/cluster.rb +0 -315
- data/lib/redis/connection/command_helper.rb +0 -41
- data/lib/redis/connection/hiredis.rb +0 -68
- data/lib/redis/connection/registry.rb +0 -13
- data/lib/redis/connection/ruby.rb +0 -437
- data/lib/redis/connection/synchrony.rb +0 -148
- data/lib/redis/connection.rb +0 -11
data/lib/redis/distributed.rb
CHANGED
|
@@ -20,8 +20,12 @@ class Redis
|
|
|
20
20
|
def initialize(node_configs, options = {})
|
|
21
21
|
@tag = options[:tag] || /^\{(.+?)\}/
|
|
22
22
|
@ring = options[:ring] || HashRing.new
|
|
23
|
-
@node_configs = node_configs.dup
|
|
23
|
+
@node_configs = node_configs.map(&:dup)
|
|
24
24
|
@default_options = options.dup
|
|
25
|
+
# Schemas registered via himport_prepare, replayed to nodes that join the ring later (see
|
|
26
|
+
# #add_node) so ring membership changes don't leave nodes without the fieldsets that
|
|
27
|
+
# key-routed himport_set calls expect. Initialized before the add_node loop below.
|
|
28
|
+
@himport_fieldsets = {}
|
|
25
29
|
node_configs.each { |node_config| add_node(node_config) }
|
|
26
30
|
@subscribed_node = nil
|
|
27
31
|
@watch_key = nil
|
|
@@ -41,7 +45,14 @@ class Redis
|
|
|
41
45
|
def add_node(options)
|
|
42
46
|
options = { url: options } if options.is_a?(String)
|
|
43
47
|
options = @default_options.merge(options)
|
|
44
|
-
|
|
48
|
+
options.delete(:tag)
|
|
49
|
+
options.delete(:ring)
|
|
50
|
+
node = Redis.new(options)
|
|
51
|
+
# Replay registered fieldsets before the node can receive key-routed himport_set calls:
|
|
52
|
+
# a node joining after a himport_prepare fan-out has neither the server-side fieldset nor
|
|
53
|
+
# a populated registry to self-recover from "no such fieldset".
|
|
54
|
+
@himport_fieldsets.each { |name, fields| node.himport_prepare(name, fields) }
|
|
55
|
+
@ring.add_node node
|
|
45
56
|
end
|
|
46
57
|
|
|
47
58
|
# Change the selected database for the current connection.
|
|
@@ -64,6 +75,10 @@ class Redis
|
|
|
64
75
|
on_each_node :quit
|
|
65
76
|
end
|
|
66
77
|
|
|
78
|
+
def close
|
|
79
|
+
on_each_node :close
|
|
80
|
+
end
|
|
81
|
+
|
|
67
82
|
# Asynchronously save the dataset to disk.
|
|
68
83
|
def bgsave
|
|
69
84
|
on_each_node :bgsave
|
|
@@ -124,6 +139,11 @@ class Redis
|
|
|
124
139
|
node_for(key).expireat(key, unix_time, **kwargs)
|
|
125
140
|
end
|
|
126
141
|
|
|
142
|
+
# Get the expiration for a key as a UNIX timestamp.
|
|
143
|
+
def expiretime(key)
|
|
144
|
+
node_for(key).expiretime(key)
|
|
145
|
+
end
|
|
146
|
+
|
|
127
147
|
# Get the time to live (in seconds) for a key.
|
|
128
148
|
def ttl(key)
|
|
129
149
|
node_for(key).ttl(key)
|
|
@@ -139,6 +159,11 @@ class Redis
|
|
|
139
159
|
node_for(key).pexpireat(key, ms_unix_time, **kwarg)
|
|
140
160
|
end
|
|
141
161
|
|
|
162
|
+
# Get the expiration for a key as number of milliseconds from UNIX Epoch.
|
|
163
|
+
def pexpiretime(key)
|
|
164
|
+
node_for(key).pexpiretime(key)
|
|
165
|
+
end
|
|
166
|
+
|
|
142
167
|
# Get the time to live (in milliseconds) for a key.
|
|
143
168
|
def pttl(key)
|
|
144
169
|
node_for(key).pttl(key)
|
|
@@ -161,6 +186,7 @@ class Redis
|
|
|
161
186
|
|
|
162
187
|
# Delete a key.
|
|
163
188
|
def del(*args)
|
|
189
|
+
args.flatten!(1)
|
|
164
190
|
keys_per_node = args.group_by { |key| node_for(key) }
|
|
165
191
|
keys_per_node.inject(0) do |sum, (node, keys)|
|
|
166
192
|
sum + node.del(*keys)
|
|
@@ -169,6 +195,7 @@ class Redis
|
|
|
169
195
|
|
|
170
196
|
# Unlink keys.
|
|
171
197
|
def unlink(*args)
|
|
198
|
+
args.flatten!(1)
|
|
172
199
|
keys_per_node = args.group_by { |key| node_for(key) }
|
|
173
200
|
keys_per_node.inject(0) do |sum, (node, keys)|
|
|
174
201
|
sum + node.unlink(*keys)
|
|
@@ -177,23 +204,16 @@ class Redis
|
|
|
177
204
|
|
|
178
205
|
# Determine if a key exists.
|
|
179
206
|
def exists(*args)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
"(#{::Kernel.caller(1, 1).first})\n"
|
|
185
|
-
)
|
|
186
|
-
exists?(*args)
|
|
187
|
-
else
|
|
188
|
-
keys_per_node = args.group_by { |key| node_for(key) }
|
|
189
|
-
keys_per_node.inject(0) do |sum, (node, keys)|
|
|
190
|
-
sum + node._exists(*keys)
|
|
191
|
-
end
|
|
207
|
+
args.flatten!(1)
|
|
208
|
+
keys_per_node = args.group_by { |key| node_for(key) }
|
|
209
|
+
keys_per_node.inject(0) do |sum, (node, keys)|
|
|
210
|
+
sum + node.exists(*keys)
|
|
192
211
|
end
|
|
193
212
|
end
|
|
194
213
|
|
|
195
214
|
# Determine if any of the keys exists.
|
|
196
215
|
def exists?(*args)
|
|
216
|
+
args.flatten!(1)
|
|
197
217
|
keys_per_node = args.group_by { |key| node_for(key) }
|
|
198
218
|
keys_per_node.each do |node, keys|
|
|
199
219
|
return true if node.exists?(*keys)
|
|
@@ -297,7 +317,7 @@ class Redis
|
|
|
297
317
|
end
|
|
298
318
|
|
|
299
319
|
# Set multiple keys to multiple values.
|
|
300
|
-
def mset(*
|
|
320
|
+
def mset(*)
|
|
301
321
|
raise CannotDistribute, :mset
|
|
302
322
|
end
|
|
303
323
|
|
|
@@ -306,7 +326,7 @@ class Redis
|
|
|
306
326
|
end
|
|
307
327
|
|
|
308
328
|
# Set multiple keys to multiple values, only if none of the keys exist.
|
|
309
|
-
def msetnx(*
|
|
329
|
+
def msetnx(*)
|
|
310
330
|
raise CannotDistribute, :msetnx
|
|
311
331
|
end
|
|
312
332
|
|
|
@@ -329,13 +349,133 @@ class Redis
|
|
|
329
349
|
node_for(key).getex(key, **options)
|
|
330
350
|
end
|
|
331
351
|
|
|
352
|
+
# Set the JSON value at a path in the document stored under a key.
|
|
353
|
+
def json_set(key, path, value, **options)
|
|
354
|
+
node_for(key).json_set(key, path, value, **options)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# Get the JSON value(s) at one or more paths in the document stored under a key.
|
|
358
|
+
def json_get(key, *paths, **options)
|
|
359
|
+
node_for(key).json_get(key, *paths, **options)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
# Set one or more JSON values. The keys may live on different nodes and the operation must be
|
|
363
|
+
# atomic, so it cannot be distributed.
|
|
364
|
+
def json_mset(*)
|
|
365
|
+
raise CannotDistribute, :json_mset
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Get the values at a path from several keys. Keys are grouped by node, queried per node, and
|
|
369
|
+
# reassembled in the original key order.
|
|
370
|
+
def json_mget(*keys, path, **options)
|
|
371
|
+
keys.flatten!(1)
|
|
372
|
+
values = keys.group_by { |key| node_for(key) }.each_with_object({}) do |(node, subkeys), acc|
|
|
373
|
+
node.json_mget(*subkeys, path, **options).each_with_index do |value, i|
|
|
374
|
+
acc[subkeys[i]] = value
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
keys.map { |key| values[key] }
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Delete the JSON value(s) at a path in the document stored under a key.
|
|
381
|
+
def json_del(key, path = nil)
|
|
382
|
+
node_for(key).json_del(key, path)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
# Delete the JSON value(s) at a path in the document stored under a key (alias of json_del).
|
|
386
|
+
def json_forget(key, path = nil)
|
|
387
|
+
node_for(key).json_forget(key, path)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# Clear the container and numeric JSON value(s) at a path in the document stored under a key.
|
|
391
|
+
def json_clear(key, path = nil)
|
|
392
|
+
node_for(key).json_clear(key, path)
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Merge a JSON value into the document stored under a key at a path.
|
|
396
|
+
def json_merge(key, path, value, **options)
|
|
397
|
+
node_for(key).json_merge(key, path, value, **options)
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# Append one or more values to the JSON array at a path in the document stored under a key.
|
|
401
|
+
def json_arrappend(key, path, *values, **options)
|
|
402
|
+
node_for(key).json_arrappend(key, path, *values, **options)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# Return the index of the first occurrence of a scalar in the JSON array at a path.
|
|
406
|
+
def json_arrindex(key, path, value, **options)
|
|
407
|
+
node_for(key).json_arrindex(key, path, value, **options)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# Insert one or more values into the JSON array at a path in the document stored under a key.
|
|
411
|
+
def json_arrinsert(key, path, index, *values, **options)
|
|
412
|
+
node_for(key).json_arrinsert(key, path, index, *values, **options)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# Return the length of the JSON array at a path in the document stored under a key.
|
|
416
|
+
def json_arrlen(key, path = nil)
|
|
417
|
+
node_for(key).json_arrlen(key, path)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
# Remove and return an element from the JSON array at a path in the document stored under a key.
|
|
421
|
+
def json_arrpop(key, path = nil, index = nil, **options)
|
|
422
|
+
node_for(key).json_arrpop(key, path, index, **options)
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Trim the JSON array at a path in the document stored under a key to an inclusive range.
|
|
426
|
+
def json_arrtrim(key, path, start, stop)
|
|
427
|
+
node_for(key).json_arrtrim(key, path, start, stop)
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# Increment the numeric JSON value(s) at a path in the document stored under a key.
|
|
431
|
+
def json_numincrby(key, path, number)
|
|
432
|
+
node_for(key).json_numincrby(key, path, number)
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# Return the type name(s) of the JSON value(s) at a path in the document stored under a key.
|
|
436
|
+
def json_type(key, path = nil)
|
|
437
|
+
node_for(key).json_type(key, path)
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
# Return the key names of the JSON object(s) at a path in the document stored under a key.
|
|
441
|
+
def json_objkeys(key, path = nil)
|
|
442
|
+
node_for(key).json_objkeys(key, path)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
# Return the number of keys in the JSON object(s) at a path in the document stored under a key.
|
|
446
|
+
def json_objlen(key, path = nil)
|
|
447
|
+
node_for(key).json_objlen(key, path)
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
# Return the length of the JSON string(s) at a path in the document stored under a key.
|
|
451
|
+
def json_strlen(key, path = nil)
|
|
452
|
+
node_for(key).json_strlen(key, path)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
# Append a string to the JSON string(s) at a path in the document stored under a key.
|
|
456
|
+
def json_strappend(key, path, value, **options)
|
|
457
|
+
node_for(key).json_strappend(key, path, value, **options)
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
# Toggle the boolean JSON value(s) at a path in the document stored under a key.
|
|
461
|
+
def json_toggle(key, path)
|
|
462
|
+
node_for(key).json_toggle(key, path)
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
# Report the size in bytes of the JSON value(s) at a path in the document stored under a key.
|
|
466
|
+
def json_debug_memory(key, path = nil)
|
|
467
|
+
node_for(key).json_debug_memory(key, path)
|
|
468
|
+
end
|
|
469
|
+
|
|
332
470
|
# Get the values of all the given keys as an Array.
|
|
333
471
|
def mget(*keys)
|
|
472
|
+
keys.flatten!(1)
|
|
334
473
|
mapped_mget(*keys).values_at(*keys)
|
|
335
474
|
end
|
|
336
475
|
|
|
337
476
|
# Get the values of all the given keys as a Hash.
|
|
338
477
|
def mapped_mget(*keys)
|
|
478
|
+
keys.flatten!(1)
|
|
339
479
|
keys.group_by { |k| node_for k }.inject({}) do |results, (node, subkeys)|
|
|
340
480
|
results.merge! node.mapped_mget(*subkeys)
|
|
341
481
|
end
|
|
@@ -367,20 +507,21 @@ class Redis
|
|
|
367
507
|
end
|
|
368
508
|
|
|
369
509
|
# Count the number of set bits in a range of the string value stored at key.
|
|
370
|
-
def bitcount(key, start = 0, stop = -1)
|
|
371
|
-
node_for(key).bitcount(key, start, stop)
|
|
510
|
+
def bitcount(key, start = 0, stop = -1, scale: nil)
|
|
511
|
+
node_for(key).bitcount(key, start, stop, scale: scale)
|
|
372
512
|
end
|
|
373
513
|
|
|
374
514
|
# Perform a bitwise operation between strings and store the resulting string in a key.
|
|
375
515
|
def bitop(operation, destkey, *keys)
|
|
516
|
+
keys.flatten!(1)
|
|
376
517
|
ensure_same_node(:bitop, [destkey] + keys) do |node|
|
|
377
|
-
node.bitop(operation, destkey,
|
|
518
|
+
node.bitop(operation, destkey, keys)
|
|
378
519
|
end
|
|
379
520
|
end
|
|
380
521
|
|
|
381
522
|
# Return the position of the first bit set to 1 or 0 in a string.
|
|
382
|
-
def bitpos(key, bit, start = nil, stop = nil)
|
|
383
|
-
node_for(key).bitpos(key, bit, start, stop)
|
|
523
|
+
def bitpos(key, bit, start = nil, stop = nil, scale: nil)
|
|
524
|
+
node_for(key).bitpos(key, bit, start, stop, scale: scale)
|
|
384
525
|
end
|
|
385
526
|
|
|
386
527
|
# Set the string value of a key and return its old value.
|
|
@@ -413,6 +554,15 @@ class Redis
|
|
|
413
554
|
end
|
|
414
555
|
end
|
|
415
556
|
|
|
557
|
+
# Remove multiple elements from the head/tail of a list, append/prepend
|
|
558
|
+
# them to another list and return them.
|
|
559
|
+
def lmovem(source, destination, where_source, where_destination, count: nil, exactly: nil, order: nil)
|
|
560
|
+
ensure_same_node(:lmovem, [source, destination]) do |node|
|
|
561
|
+
node.lmovem(source, destination, where_source, where_destination,
|
|
562
|
+
count: count, exactly: exactly, order: order)
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
|
|
416
566
|
# Remove the first/last element in a list and append/prepend it
|
|
417
567
|
# to another list and return it, or block until one is available.
|
|
418
568
|
def blmove(source, destination, where_source, where_destination, timeout: 0)
|
|
@@ -421,6 +571,17 @@ class Redis
|
|
|
421
571
|
end
|
|
422
572
|
end
|
|
423
573
|
|
|
574
|
+
# Remove multiple elements from the head/tail of a list, append/prepend
|
|
575
|
+
# them to another list and return them; or block until the request can
|
|
576
|
+
# be satisfied or the timeout expires.
|
|
577
|
+
def blmovem(source, destination, where_source, where_destination, timeout: 0, count: nil, exactly: nil,
|
|
578
|
+
order: nil)
|
|
579
|
+
ensure_same_node(:blmovem, [source, destination]) do |node|
|
|
580
|
+
node.blmovem(source, destination, where_source, where_destination,
|
|
581
|
+
timeout: timeout, count: count, exactly: exactly, order: order)
|
|
582
|
+
end
|
|
583
|
+
end
|
|
584
|
+
|
|
424
585
|
# Prepend one or more values to a list.
|
|
425
586
|
def lpush(key, value)
|
|
426
587
|
node_for(key).lpush(key, value)
|
|
@@ -463,23 +624,15 @@ class Redis
|
|
|
463
624
|
timeout = if args.last.is_a?(Hash)
|
|
464
625
|
options = args.pop
|
|
465
626
|
options[:timeout]
|
|
466
|
-
elsif args.last.respond_to?(:to_int)
|
|
467
|
-
last_arg = args.pop
|
|
468
|
-
::Redis.deprecate!(
|
|
469
|
-
"Passing the timeout as a positional argument is deprecated, it should be passed as a keyword argument:\n" \
|
|
470
|
-
" redis.#{cmd}(#{args.map(&:inspect).join(', ')}, timeout: #{last_arg.to_int})" \
|
|
471
|
-
"(called from: #{caller(2, 1).first})"
|
|
472
|
-
)
|
|
473
|
-
last_arg.to_int
|
|
474
627
|
end
|
|
475
628
|
|
|
476
|
-
|
|
629
|
+
args.flatten!(1)
|
|
477
630
|
|
|
478
|
-
ensure_same_node(cmd,
|
|
631
|
+
ensure_same_node(cmd, args) do |node|
|
|
479
632
|
if timeout
|
|
480
|
-
node.__send__(cmd,
|
|
633
|
+
node.__send__(cmd, args, timeout: timeout)
|
|
481
634
|
else
|
|
482
|
-
node.__send__(cmd,
|
|
635
|
+
node.__send__(cmd, args)
|
|
483
636
|
end
|
|
484
637
|
end
|
|
485
638
|
end
|
|
@@ -490,6 +643,18 @@ class Redis
|
|
|
490
643
|
_bpop(:blpop, args)
|
|
491
644
|
end
|
|
492
645
|
|
|
646
|
+
def bzpopmax(*args)
|
|
647
|
+
_bpop(:bzpopmax, args) do |reply|
|
|
648
|
+
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
|
|
649
|
+
end
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
def bzpopmin(*args)
|
|
653
|
+
_bpop(:bzpopmin, args) do |reply|
|
|
654
|
+
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
|
|
493
658
|
# Remove and get the last element in a list, or block until one is
|
|
494
659
|
# available.
|
|
495
660
|
def brpop(*args)
|
|
@@ -498,9 +663,9 @@ class Redis
|
|
|
498
663
|
|
|
499
664
|
# Pop a value from a list, push it to another list and return it; or block
|
|
500
665
|
# until one is available.
|
|
501
|
-
def brpoplpush(source, destination,
|
|
666
|
+
def brpoplpush(source, destination, **options)
|
|
502
667
|
ensure_same_node(:brpoplpush, [source, destination]) do |node|
|
|
503
|
-
node.brpoplpush(source, destination,
|
|
668
|
+
node.brpoplpush(source, destination, **options)
|
|
504
669
|
end
|
|
505
670
|
end
|
|
506
671
|
|
|
@@ -534,29 +699,43 @@ class Redis
|
|
|
534
699
|
node_for(key).ltrim(key, start, stop)
|
|
535
700
|
end
|
|
536
701
|
|
|
702
|
+
# Iterate over keys, blocking and removing elements from the first non empty liist found.
|
|
703
|
+
def blmpop(timeout, *keys, modifier: "LEFT", count: nil)
|
|
704
|
+
ensure_same_node(:blmpop, keys) do |node|
|
|
705
|
+
node.blmpop(timeout, *keys, modifier: modifier, count: count)
|
|
706
|
+
end
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
# Iterate over keys, removing elements from the first non list found.
|
|
710
|
+
def lmpop(*keys, modifier: "LEFT", count: nil)
|
|
711
|
+
ensure_same_node(:lmpop, keys) do |node|
|
|
712
|
+
node.lmpop(*keys, modifier: modifier, count: count)
|
|
713
|
+
end
|
|
714
|
+
end
|
|
715
|
+
|
|
537
716
|
# Get the number of members in a set.
|
|
538
717
|
def scard(key)
|
|
539
718
|
node_for(key).scard(key)
|
|
540
719
|
end
|
|
541
720
|
|
|
542
721
|
# Add one or more members to a set.
|
|
543
|
-
def sadd(key,
|
|
544
|
-
node_for(key).sadd(key,
|
|
722
|
+
def sadd(key, *members)
|
|
723
|
+
node_for(key).sadd(key, *members)
|
|
545
724
|
end
|
|
546
725
|
|
|
547
726
|
# Add one or more members to a set.
|
|
548
|
-
def sadd?(key,
|
|
549
|
-
node_for(key).sadd?(key,
|
|
727
|
+
def sadd?(key, *members)
|
|
728
|
+
node_for(key).sadd?(key, *members)
|
|
550
729
|
end
|
|
551
730
|
|
|
552
731
|
# Remove one or more members from a set.
|
|
553
|
-
def srem(key,
|
|
554
|
-
node_for(key).srem(key,
|
|
732
|
+
def srem(key, *members)
|
|
733
|
+
node_for(key).srem(key, *members)
|
|
555
734
|
end
|
|
556
735
|
|
|
557
736
|
# Remove one or more members from a set.
|
|
558
|
-
def srem?(key,
|
|
559
|
-
node_for(key).srem?(key,
|
|
737
|
+
def srem?(key, *members)
|
|
738
|
+
node_for(key).srem?(key, *members)
|
|
560
739
|
end
|
|
561
740
|
|
|
562
741
|
# Remove and return a random member from a set.
|
|
@@ -603,43 +782,66 @@ class Redis
|
|
|
603
782
|
|
|
604
783
|
# Subtract multiple sets.
|
|
605
784
|
def sdiff(*keys)
|
|
785
|
+
keys.flatten!(1)
|
|
606
786
|
ensure_same_node(:sdiff, keys) do |node|
|
|
607
|
-
node.sdiff(
|
|
787
|
+
node.sdiff(keys)
|
|
608
788
|
end
|
|
609
789
|
end
|
|
610
790
|
|
|
611
791
|
# Subtract multiple sets and store the resulting set in a key.
|
|
612
792
|
def sdiffstore(destination, *keys)
|
|
613
|
-
|
|
614
|
-
|
|
793
|
+
keys.flatten!(1)
|
|
794
|
+
ensure_same_node(:sdiffstore, [destination].concat(keys)) do |node|
|
|
795
|
+
node.sdiffstore(destination, keys)
|
|
796
|
+
end
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
# Get the number of members in the difference between the first set and
|
|
800
|
+
# all successive sets.
|
|
801
|
+
def sdiffcard(*keys, limit: nil)
|
|
802
|
+
keys.flatten!(1)
|
|
803
|
+
ensure_same_node(:sdiffcard, keys) do |node|
|
|
804
|
+
node.sdiffcard(keys, limit: limit)
|
|
615
805
|
end
|
|
616
806
|
end
|
|
617
807
|
|
|
618
808
|
# Intersect multiple sets.
|
|
619
809
|
def sinter(*keys)
|
|
810
|
+
keys.flatten!(1)
|
|
620
811
|
ensure_same_node(:sinter, keys) do |node|
|
|
621
|
-
node.sinter(
|
|
812
|
+
node.sinter(keys)
|
|
622
813
|
end
|
|
623
814
|
end
|
|
624
815
|
|
|
625
816
|
# Intersect multiple sets and store the resulting set in a key.
|
|
626
817
|
def sinterstore(destination, *keys)
|
|
627
|
-
|
|
628
|
-
|
|
818
|
+
keys.flatten!(1)
|
|
819
|
+
ensure_same_node(:sinterstore, [destination].concat(keys)) do |node|
|
|
820
|
+
node.sinterstore(destination, keys)
|
|
629
821
|
end
|
|
630
822
|
end
|
|
631
823
|
|
|
632
824
|
# Add multiple sets.
|
|
633
825
|
def sunion(*keys)
|
|
826
|
+
keys.flatten!(1)
|
|
634
827
|
ensure_same_node(:sunion, keys) do |node|
|
|
635
|
-
node.sunion(
|
|
828
|
+
node.sunion(keys)
|
|
636
829
|
end
|
|
637
830
|
end
|
|
638
831
|
|
|
639
832
|
# Add multiple sets and store the resulting set in a key.
|
|
640
833
|
def sunionstore(destination, *keys)
|
|
641
|
-
|
|
642
|
-
|
|
834
|
+
keys.flatten!(1)
|
|
835
|
+
ensure_same_node(:sunionstore, [destination].concat(keys)) do |node|
|
|
836
|
+
node.sunionstore(destination, keys)
|
|
837
|
+
end
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
# Get the number of distinct members in the union of multiple sets.
|
|
841
|
+
def sunioncard(*keys, approx: false, limit: nil)
|
|
842
|
+
keys.flatten!(1)
|
|
843
|
+
ensure_same_node(:sunioncard, keys) do |node|
|
|
844
|
+
node.sunioncard(keys, approx: approx, limit: limit)
|
|
643
845
|
end
|
|
644
846
|
end
|
|
645
847
|
|
|
@@ -680,6 +882,20 @@ class Redis
|
|
|
680
882
|
node_for(key).zmscore(key, *members)
|
|
681
883
|
end
|
|
682
884
|
|
|
885
|
+
# Iterate over keys, blocking and removing members from the first non empty sorted set found.
|
|
886
|
+
def bzmpop(timeout, *keys, modifier: "MIN", count: nil)
|
|
887
|
+
ensure_same_node(:bzmpop, keys) do |node|
|
|
888
|
+
node.bzmpop(timeout, *keys, modifier: modifier, count: count)
|
|
889
|
+
end
|
|
890
|
+
end
|
|
891
|
+
|
|
892
|
+
# Iterate over keys, removing members from the first non empty sorted set found.
|
|
893
|
+
def zmpop(*keys, modifier: "MIN", count: nil)
|
|
894
|
+
ensure_same_node(:zmpop, keys) do |node|
|
|
895
|
+
node.zmpop(*keys, modifier: modifier, count: count)
|
|
896
|
+
end
|
|
897
|
+
end
|
|
898
|
+
|
|
683
899
|
# Return a range of members in a sorted set, by index, score or lexicographical ordering.
|
|
684
900
|
def zrange(key, start, stop, **options)
|
|
685
901
|
node_for(key).zrange(key, start, stop, **options)
|
|
@@ -700,14 +916,14 @@ class Redis
|
|
|
700
916
|
end
|
|
701
917
|
|
|
702
918
|
# Determine the index of a member in a sorted set.
|
|
703
|
-
def zrank(key, member)
|
|
704
|
-
node_for(key).zrank(key, member)
|
|
919
|
+
def zrank(key, member, **options)
|
|
920
|
+
node_for(key).zrank(key, member, **options)
|
|
705
921
|
end
|
|
706
922
|
|
|
707
923
|
# Determine the index of a member in a sorted set, with scores ordered from
|
|
708
924
|
# high to low.
|
|
709
|
-
def zrevrank(key, member)
|
|
710
|
-
node_for(key).zrevrank(key, member)
|
|
925
|
+
def zrevrank(key, member, **options)
|
|
926
|
+
node_for(key).zrevrank(key, member, **options)
|
|
711
927
|
end
|
|
712
928
|
|
|
713
929
|
# Remove all members in a sorted set within the given indexes.
|
|
@@ -738,43 +954,49 @@ class Redis
|
|
|
738
954
|
|
|
739
955
|
# Get the intersection of multiple sorted sets
|
|
740
956
|
def zinter(*keys, **options)
|
|
957
|
+
keys.flatten!(1)
|
|
741
958
|
ensure_same_node(:zinter, keys) do |node|
|
|
742
|
-
node.zinter(
|
|
959
|
+
node.zinter(keys, **options)
|
|
743
960
|
end
|
|
744
961
|
end
|
|
745
962
|
|
|
746
963
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
|
747
964
|
# key.
|
|
748
|
-
def zinterstore(destination, keys, **options)
|
|
749
|
-
|
|
965
|
+
def zinterstore(destination, *keys, **options)
|
|
966
|
+
keys.flatten!(1)
|
|
967
|
+
ensure_same_node(:zinterstore, [destination].concat(keys)) do |node|
|
|
750
968
|
node.zinterstore(destination, keys, **options)
|
|
751
969
|
end
|
|
752
970
|
end
|
|
753
971
|
|
|
754
972
|
# Return the union of multiple sorted sets.
|
|
755
973
|
def zunion(*keys, **options)
|
|
974
|
+
keys.flatten!(1)
|
|
756
975
|
ensure_same_node(:zunion, keys) do |node|
|
|
757
|
-
node.zunion(
|
|
976
|
+
node.zunion(keys, **options)
|
|
758
977
|
end
|
|
759
978
|
end
|
|
760
979
|
|
|
761
980
|
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
|
762
|
-
def zunionstore(destination, keys, **options)
|
|
763
|
-
|
|
981
|
+
def zunionstore(destination, *keys, **options)
|
|
982
|
+
keys.flatten!(1)
|
|
983
|
+
ensure_same_node(:zunionstore, [destination].concat(keys)) do |node|
|
|
764
984
|
node.zunionstore(destination, keys, **options)
|
|
765
985
|
end
|
|
766
986
|
end
|
|
767
987
|
|
|
768
988
|
# Return the difference between the first and all successive input sorted sets.
|
|
769
989
|
def zdiff(*keys, **options)
|
|
990
|
+
keys.flatten!(1)
|
|
770
991
|
ensure_same_node(:zdiff, keys) do |node|
|
|
771
|
-
node.zdiff(
|
|
992
|
+
node.zdiff(keys, **options)
|
|
772
993
|
end
|
|
773
994
|
end
|
|
774
995
|
|
|
775
996
|
# Compute the difference between the first and all successive input sorted sets
|
|
776
997
|
# and store the resulting sorted set in a new key.
|
|
777
|
-
def zdiffstore(destination, keys, **options)
|
|
998
|
+
def zdiffstore(destination, *keys, **options)
|
|
999
|
+
keys.flatten!(1)
|
|
778
1000
|
ensure_same_node(:zdiffstore, [destination] + keys) do |node|
|
|
779
1001
|
node.zdiffstore(destination, keys, **options)
|
|
780
1002
|
end
|
|
@@ -801,7 +1023,7 @@ class Redis
|
|
|
801
1023
|
end
|
|
802
1024
|
|
|
803
1025
|
def mapped_hmset(key, hash)
|
|
804
|
-
node_for(key).hmset(key,
|
|
1026
|
+
node_for(key).hmset(key, hash)
|
|
805
1027
|
end
|
|
806
1028
|
|
|
807
1029
|
# Get the value of a hash field.
|
|
@@ -811,11 +1033,13 @@ class Redis
|
|
|
811
1033
|
|
|
812
1034
|
# Get the values of all the given hash fields.
|
|
813
1035
|
def hmget(key, *fields)
|
|
814
|
-
|
|
1036
|
+
fields.flatten!(1)
|
|
1037
|
+
node_for(key).hmget(key, fields)
|
|
815
1038
|
end
|
|
816
1039
|
|
|
817
1040
|
def mapped_hmget(key, *fields)
|
|
818
|
-
|
|
1041
|
+
fields.flatten!(1)
|
|
1042
|
+
node_for(key).mapped_hmget(key, fields)
|
|
819
1043
|
end
|
|
820
1044
|
|
|
821
1045
|
def hrandfield(key, count = nil, **options)
|
|
@@ -824,7 +1048,8 @@ class Redis
|
|
|
824
1048
|
|
|
825
1049
|
# Delete one or more hash fields.
|
|
826
1050
|
def hdel(key, *fields)
|
|
827
|
-
|
|
1051
|
+
fields.flatten!(1)
|
|
1052
|
+
node_for(key).hdel(key, fields)
|
|
828
1053
|
end
|
|
829
1054
|
|
|
830
1055
|
# Determine if a hash field exists.
|
|
@@ -857,6 +1082,112 @@ class Redis
|
|
|
857
1082
|
node_for(key).hgetall(key)
|
|
858
1083
|
end
|
|
859
1084
|
|
|
1085
|
+
def hexpire(key, ttl, *fields)
|
|
1086
|
+
node_for(key).hexpire(key, ttl, *fields)
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
def httl(key, *fields)
|
|
1090
|
+
node_for(key).httl(key, *fields)
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
# Scan a hash
|
|
1094
|
+
def hscan(key, cursor, **options)
|
|
1095
|
+
node_for(key).hscan(key, cursor, **options)
|
|
1096
|
+
end
|
|
1097
|
+
|
|
1098
|
+
# Scan a hash and return an enumerator
|
|
1099
|
+
def hscan_each(key, **options, &block)
|
|
1100
|
+
node_for(key).hscan_each(key, **options, &block)
|
|
1101
|
+
end
|
|
1102
|
+
|
|
1103
|
+
# Get the length of the value stored in a hash field
|
|
1104
|
+
def hstrlen(key, field)
|
|
1105
|
+
node_for(key).hstrlen(key, field)
|
|
1106
|
+
end
|
|
1107
|
+
|
|
1108
|
+
def hpexpire(key, ttl, *fields, nx: nil, xx: nil, gt: nil, lt: nil)
|
|
1109
|
+
node_for(key).hpexpire(key, ttl, *fields, nx: nx, xx: xx, gt: gt, lt: lt)
|
|
1110
|
+
end
|
|
1111
|
+
|
|
1112
|
+
def hpttl(key, *fields)
|
|
1113
|
+
node_for(key).hpttl(key, *fields)
|
|
1114
|
+
end
|
|
1115
|
+
|
|
1116
|
+
# Register a fieldset on every ring node. Fieldsets are scoped to a physical
|
|
1117
|
+
# connection, so every node that may receive an `himport_set` for a key it
|
|
1118
|
+
# owns needs the fieldset on its own connection.
|
|
1119
|
+
def himport_prepare(fieldset_name, *fields)
|
|
1120
|
+
fields.flatten!(1)
|
|
1121
|
+
results = on_each_node(:himport_prepare, fieldset_name, fields)
|
|
1122
|
+
@himport_fieldsets[fieldset_name.to_s] = fields.dup.freeze
|
|
1123
|
+
results
|
|
1124
|
+
end
|
|
1125
|
+
|
|
1126
|
+
# Create or fully replace a hash from a fieldset prepared on the key's node.
|
|
1127
|
+
def himport_set(key, fieldset_name, *values)
|
|
1128
|
+
values.flatten!(1)
|
|
1129
|
+
node_for(key).himport_set(key, fieldset_name, values)
|
|
1130
|
+
end
|
|
1131
|
+
|
|
1132
|
+
# Remove a fieldset from every ring node.
|
|
1133
|
+
def himport_discard(fieldset_name)
|
|
1134
|
+
results = on_each_node(:himport_discard, fieldset_name)
|
|
1135
|
+
@himport_fieldsets.delete(fieldset_name.to_s)
|
|
1136
|
+
results
|
|
1137
|
+
end
|
|
1138
|
+
|
|
1139
|
+
# Remove all fieldsets from every ring node.
|
|
1140
|
+
def himport_discard_all
|
|
1141
|
+
results = on_each_node(:himport_discard_all)
|
|
1142
|
+
@himport_fieldsets.clear
|
|
1143
|
+
results
|
|
1144
|
+
end
|
|
1145
|
+
|
|
1146
|
+
# Add one or more geospatial items to a sorted set.
|
|
1147
|
+
def geoadd(key, *member, **options)
|
|
1148
|
+
node_for(key).geoadd(key, *member, **options)
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
# Get geohash strings representing the position of one or more members.
|
|
1152
|
+
def geohash(key, member)
|
|
1153
|
+
node_for(key).geohash(key, member)
|
|
1154
|
+
end
|
|
1155
|
+
|
|
1156
|
+
# Get longitude and latitude of one or more members of a geospatial index.
|
|
1157
|
+
def geopos(key, member)
|
|
1158
|
+
node_for(key).geopos(key, member)
|
|
1159
|
+
end
|
|
1160
|
+
|
|
1161
|
+
# Get the distance between two members of a geospatial index.
|
|
1162
|
+
def geodist(key, member1, member2, unit = 'm')
|
|
1163
|
+
node_for(key).geodist(key, member1, member2, unit)
|
|
1164
|
+
end
|
|
1165
|
+
|
|
1166
|
+
# Query a geospatial index for members within a given radius from a point.
|
|
1167
|
+
def georadius(*args, **geoptions)
|
|
1168
|
+
key = args.first
|
|
1169
|
+
node_for(key).georadius(*args, **geoptions)
|
|
1170
|
+
end
|
|
1171
|
+
|
|
1172
|
+
# Query a geospatial index for members within a given radius from an existing member.
|
|
1173
|
+
def georadiusbymember(*args, **geoptions)
|
|
1174
|
+
key = args.first
|
|
1175
|
+
node_for(key).georadiusbymember(*args, **geoptions)
|
|
1176
|
+
end
|
|
1177
|
+
|
|
1178
|
+
# Search a geospatial index for members within a given shape from a center point.
|
|
1179
|
+
def geosearch(key, **options)
|
|
1180
|
+
node_for(key).geosearch(key, **options)
|
|
1181
|
+
end
|
|
1182
|
+
|
|
1183
|
+
# Like #geosearch, but stores the result in a destination key.
|
|
1184
|
+
# Destination and source must hash to the same node; use a key tag to ensure that.
|
|
1185
|
+
def geosearchstore(destination, source, **options)
|
|
1186
|
+
ensure_same_node(:geosearchstore, [destination, source]) do |node|
|
|
1187
|
+
node.geosearchstore(destination, source, **options)
|
|
1188
|
+
end
|
|
1189
|
+
end
|
|
1190
|
+
|
|
860
1191
|
# Post a message to a channel.
|
|
861
1192
|
def publish(channel, message)
|
|
862
1193
|
node_for(channel).publish(channel, message)
|
|
@@ -881,18 +1212,22 @@ class Redis
|
|
|
881
1212
|
|
|
882
1213
|
# Stop listening for messages posted to the given channels.
|
|
883
1214
|
def unsubscribe(*channels)
|
|
884
|
-
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
|
1215
|
+
raise SubscriptionError, "Can't unsubscribe if not subscribed." unless subscribed?
|
|
885
1216
|
|
|
886
1217
|
@subscribed_node.unsubscribe(*channels)
|
|
887
1218
|
end
|
|
888
1219
|
|
|
889
1220
|
# Listen for messages published to channels matching the given patterns.
|
|
1221
|
+
# See the [Redis Server PSUBSCRIBE documentation](https://redis.io/docs/latest/commands/psubscribe/)
|
|
1222
|
+
# for further details
|
|
890
1223
|
def psubscribe(*channels, &block)
|
|
891
1224
|
raise NotImplementedError
|
|
892
1225
|
end
|
|
893
1226
|
|
|
894
1227
|
# Stop listening for messages posted to channels matching the given
|
|
895
1228
|
# patterns.
|
|
1229
|
+
# See the [Redis Server PUNSUBSCRIBE documentation](https://redis.io/docs/latest/commands/punsubscribe/)
|
|
1230
|
+
# for further details
|
|
896
1231
|
def punsubscribe(*channels)
|
|
897
1232
|
raise NotImplementedError
|
|
898
1233
|
end
|
|
@@ -928,9 +1263,7 @@ class Redis
|
|
|
928
1263
|
def multi(&block)
|
|
929
1264
|
raise CannotDistribute, :multi unless @watch_key
|
|
930
1265
|
|
|
931
|
-
|
|
932
|
-
@watch_key = nil if block_given?
|
|
933
|
-
result
|
|
1266
|
+
node_for(@watch_key).multi(&block)
|
|
934
1267
|
end
|
|
935
1268
|
|
|
936
1269
|
# Execute all commands issued after MULTI.
|
|
@@ -1020,7 +1353,8 @@ class Redis
|
|
|
1020
1353
|
end
|
|
1021
1354
|
|
|
1022
1355
|
def key_tag(key)
|
|
1023
|
-
key.to_s
|
|
1356
|
+
key = key.to_s
|
|
1357
|
+
key[@tag, 1] if key.match?(@tag)
|
|
1024
1358
|
end
|
|
1025
1359
|
|
|
1026
1360
|
def ensure_same_node(command, keys)
|