diff --git a/lib/redis.rb b/lib/redis.rb index ab842b232..4746ec463 100644 --- a/lib/redis.rb +++ b/lib/redis.rb @@ -2279,20 +2279,10 @@ def zinter(*args) # sorted sets # - `:aggregate => String`: aggregate function to use (sum, min, max) # @return [Integer] number of elements in the resulting sorted set - def zinterstore(destination, keys, weights: nil, aggregate: nil) - args = [:zinterstore, destination, keys.size, *keys] - - if weights - args << "WEIGHTS" - args.concat(weights) - end - - args << "AGGREGATE" << aggregate if aggregate - - synchronize do |client| - client.call(args) - end + def zinterstore(*args) + _zsets_operation_store(:zinterstore, *args) end + ruby2_keywords(:zinterstore) if respond_to?(:ruby2_keywords, true) # Return the union of multiple sorted sets # @@ -2331,20 +2321,10 @@ def zunion(*args) # sorted sets # - `:aggregate => String`: aggregate function to use (sum, min, max, ...) # @return [Integer] number of elements in the resulting sorted set - def zunionstore(destination, keys, weights: nil, aggregate: nil) - args = [:zunionstore, destination, keys.size, *keys] - - if weights - args << "WEIGHTS" - args.concat(weights) - end - - args << "AGGREGATE" << aggregate if aggregate - - synchronize do |client| - client.call(args) - end + def zunionstore(*args) + _zsets_operation_store(:zunionstore, *args) end + ruby2_keywords(:zunionstore) if respond_to?(:ruby2_keywords, true) # Return the difference between the first and all successive input sorted sets # @@ -2370,6 +2350,23 @@ def zdiff(*keys, with_scores: false) _zsets_operation(:zdiff, *keys, with_scores: with_scores) end + # Compute the difference between the first and all successive input sorted sets + # and store the resulting sorted set in a new key + # + # @example + # redis.zadd("zsetA", [[1.0, "v1"], [2.0, "v2"]]) + # redis.zadd("zsetB", [[3.0, "v2"], [2.0, "v3"]]) + # redis.zdiffstore("zsetA", "zsetB") + # # => 1 + # + # @param [String] destination destination key + # @param [Array] keys source keys + # @return [Integer] number of elements in the resulting sorted set + def zdiffstore(*args) + _zsets_operation_store(:zdiffstore, *args) + end + ruby2_keywords(:zdiffstore) if respond_to?(:ruby2_keywords, true) + # Get the number of fields in a hash. # # @param [String] key @@ -3924,6 +3921,21 @@ def _zsets_operation(cmd, *keys, weights: nil, aggregate: nil, with_scores: fals client.call(command, &block) end end + + def _zsets_operation_store(cmd, destination, keys, weights: nil, aggregate: nil) + command = [cmd, destination, keys.size, *keys] + + if weights + command << "WEIGHTS" + command.concat(weights) + end + + command << "AGGREGATE" << aggregate if aggregate + + synchronize do |client| + client.call(command) + end + end end require_relative "redis/version" diff --git a/lib/redis/distributed.rb b/lib/redis/distributed.rb index 121679333..4662a136d 100644 --- a/lib/redis/distributed.rb +++ b/lib/redis/distributed.rb @@ -750,6 +750,14 @@ def zdiff(*keys, **options) end end + # Compute the difference between the first and all successive input sorted sets + # and store the resulting sorted set in a new key. + def zdiffstore(destination, keys, **options) + ensure_same_node(:zdiffstore, [destination] + keys) do |node| + node.zdiffstore(destination, keys, **options) + end + end + # Get the number of fields in a hash. def hlen(key) node_for(key).hlen(key) diff --git a/test/cluster_commands_on_sorted_sets_test.rb b/test/cluster_commands_on_sorted_sets_test.rb index 1c49694ab..ae6a1c2e4 100644 --- a/test/cluster_commands_on_sorted_sets_test.rb +++ b/test/cluster_commands_on_sorted_sets_test.rb @@ -60,4 +60,8 @@ def test_zunionstore_with_weights def test_zdiff assert_raises(Redis::CommandError) { super } end + + def test_zdiffstore + assert_raises(Redis::CommandError) { super } + end end diff --git a/test/distributed_commands_on_sorted_sets_test.rb b/test/distributed_commands_on_sorted_sets_test.rb index c1f716726..4e4f02a94 100644 --- a/test/distributed_commands_on_sorted_sets_test.rb +++ b/test/distributed_commands_on_sorted_sets_test.rb @@ -86,4 +86,8 @@ def test_zunionstore_with_weights def test_zdiff assert_raises(Redis::Distributed::CannotDistribute) { super } end + + def test_zdiffstore + assert_raises(Redis::Distributed::CannotDistribute) { super } + end end diff --git a/test/lint/sorted_sets.rb b/test/lint/sorted_sets.rb index 2cd4a0d36..f5cc8e687 100644 --- a/test/lint/sorted_sets.rb +++ b/test/lint/sorted_sets.rb @@ -586,6 +586,22 @@ def test_zdiff end end + def test_zdiffstore + target_version("6.2") do + r.zadd 'foo', 1, 's1' + r.zadd 'foo', 2, 's2' + r.zadd 'bar', 3, 's1' + r.zadd 'bar', 5, 's3' + + assert_equal 0, r.zdiffstore('baz', ['foo', 'foo']) + assert_equal 2, r.zdiffstore('baz', ['foo']) + assert_equal ['s1', 's2'], r.zrange('baz', 0, -1) + + assert_equal 1, r.zdiffstore('baz', ['foo', 'bar']) + assert_equal ['s2'], r.zrange('baz', 0, -1) + end + end + def test_zinter target_version("6.2") do r.zadd 'foo', 1, 's1'