From 60079e44ae4d71a378ea248055fd37ca29118e59 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Mon, 10 Dec 2018 16:55:58 +0100 Subject: [PATCH] Use `start` and `end` params in stream commands for consistency with the server doc --- lib/redis.rb | 83 +++++++++----- test/cluster_commands_on_streams_test.rb | 22 ++-- test/lint/streams.rb | 134 ++++++++++------------- 3 files changed, 123 insertions(+), 116 deletions(-) diff --git a/lib/redis.rb b/lib/redis.rb index 1b455f904..1ac8ab9f2 100644 --- a/lib/redis.rb +++ b/lib/redis.rb @@ -2990,13 +2990,31 @@ def xdel(key, *ids) # redis.xrange('mystream', count: 10) # # @param key [String] the stream key - # @param first [String] first entry id of range, default value is `-` - # @param last [String] last entry id of range, default value is `+` + # @param start [String] first entry id of range, default value is `+` + # @param end [String] last entry id of range, default value is `-` # @param count [Integer] the number of entries as limit # # @return [Hash{String => Hash}] the entries - def xrange(key, first: '-', last: '+', count: nil) - args = [:xrange, key, first, last] + + # Fetches entries of the stream in ascending order. + # + # @example Without options + # redis.xrange('mystream') + # @example With a specific start + # redis.xrange('mystream', '0-1') + # @example With a specific start and end + # redis.xrange('mystream', '0-1', '0-3') + # @example With count options + # redis.xrange('mystream', count: 10) + # + # @param key [String] the stream key + # @param start [String] first entry id of range, default value is `-` + # @param end [String] last entry id of range, default value is `+` + # @param count [Integer] the number of entries as limit + # + # @return [Array>] the ids and entries pairs + def xrange(key, start = '-', _end = '+', count: nil) + args = [:xrange, key, start, _end] args.concat(['COUNT', count]) if count synchronize { |client| client.call(args, &HashifyStreamEntries) } end @@ -3005,21 +3023,21 @@ def xrange(key, first: '-', last: '+', count: nil) # # @example Without options # redis.xrevrange('mystream') - # @example With first entry id option - # redis.xrevrange('mystream', first: '0-1') - # @example With first and last entry id options - # redis.xrevrange('mystream', first: '0-1', last: '0-3') + # @example With a specific end + # redis.xrevrange('mystream', '0-3') + # @example With a specific end and start + # redis.xrevrange('mystream', '0-3', '0-1') # @example With count options # redis.xrevrange('mystream', count: 10) # - # @param key [String] the stream key - # @param first [String] first entry id of range, default value is `-` - # @param last [String] last entry id of range, default value is `+` - # @param count [Integer] the number of entries as limit + # @param key [String] the stream key + # @param end [String] first entry id of range, default value is `+` + # @param start [String] last entry id of range, default value is `-` + # @params count [Integer] the number of entries as limit # - # @return [Hash{String => Hash}] the entries - def xrevrange(key, first: '-', last: '+', count: nil) - args = [:xrevrange, key, last, first] + # @return [Array>] the ids and entries pairs + def xrevrange(key, _end = '+', start = '-', count: nil) + args = [:xrevrange, key, _end, start] args.concat(['COUNT', count]) if count synchronize { |client| client.call(args, &HashifyStreamEntries) } end @@ -3186,26 +3204,31 @@ def xclaim(key, group, consumer, min_idle_time, *ids, **opts) # @example With key and group # redis.xpending('mystream', 'mygroup') # @example With range options - # redis.xpending('mystream', 'mygroup', first: '-', last: '+', count: 10) + # redis.xpending('mystream', 'mygroup', '-', '+', 10) # @example With range and consumer options - # redis.xpending('mystream', 'mygroup', 'consumer1', first: '-', last: '+', count: 10) + # redis.xpending('mystream', 'mygroup', '-', '+', 10, 'consumer1') # - # @param key [String] the stream key - # @param group [String] the consumer group name - # @param consumer [String] the consumer name - # @param opts [Hash] several options for `XPENDING` command - # - # @option opts [String] :first first entry id of range - # @option opts [String] :last last entry id of range - # @option opts [Integer] :count the number of entries as limit + # @param key [String] the stream key + # @param group [String] the consumer group name + # @param start [String] start first entry id of range + # @param end [String] end last entry id of range + # @param count [Integer] count the number of entries as limit + # @param consumer [String] the consumer name # # @return [Hash] the summary of pending entries # @return [Array] the pending entries details if options were specified - def xpending(key, group, consumer = nil, **opts) - args = [:xpending, key, group, opts[:first], opts[:last], opts[:count], consumer].compact - summary_needed = consumer.nil? && opts.empty? + def xpending(key, group, *args) + command_args = [:xpending, key, group] + case args.size + when 0, 3, 4 + command_args.concat(args) + else + raise ArgumentError, "wrong number of arguments (given #{args.size + 2}, expected 2, 5 or 6)" + end + + summary_needed = args.empty? blk = summary_needed ? HashifyStreamPendings : HashifyStreamPendingDetails - synchronize { |client| client.call(args, &blk) } + synchronize { |client| client.call(command_args, &blk) } end # Interact with the sentinel command (masters, master, slaves, failover) @@ -3365,7 +3388,7 @@ def method_missing(command, *args) lambda { |reply| reply.map do |entry_id, values| [entry_id, values.each_slice(2).to_h] - end.to_h + end } HashifyStreamPendings = diff --git a/test/cluster_commands_on_streams_test.rb b/test/cluster_commands_on_streams_test.rb index a384b9786..b96cf84c2 100644 --- a/test/cluster_commands_on_streams_test.rb +++ b/test/cluster_commands_on_streams_test.rb @@ -19,11 +19,14 @@ def test_xread_with_multiple_keys_and_hash_tags redis.xadd('{s}1', { f: 'v02' }, id: '0-2') redis.xadd('{s}2', { f: 'v11' }, id: '1-1') redis.xadd('{s}2', { f: 'v12' }, id: '1-2') + actual = redis.xread(%w[{s}1 {s}2], %w[0-1 1-1]) - assert_equal 1, actual['{s}1'].size - assert_equal 1, actual['{s}2'].size - assert_equal 'v02', actual['{s}1']['0-2']['f'] - assert_equal 'v12', actual['{s}2']['1-2']['f'] + + assert_equal %w(0-2), actual['{s}1'].map(&:first) + assert_equal %w(v02), actual['{s}1'].map { |i| i.last['f'] } + + assert_equal %w(1-2), actual['{s}2'].map(&:first) + assert_equal %w(v12), actual['{s}2'].map { |i| i.last['f'] } end def test_xreadgroup_with_multiple_keys @@ -38,10 +41,13 @@ def test_xreadgroup_with_multiple_keys_and_hash_tags redis.xgroup(:create, '{s}2', 'g1', '$') redis.xadd('{s}1', { f: 'v02' }, id: '0-2') redis.xadd('{s}2', { f: 'v12' }, id: '1-2') + actual = redis.xreadgroup('g1', 'c1', %w[{s}1 {s}2], %w[> >]) - assert_equal 1, actual['{s}1'].size - assert_equal 1, actual['{s}2'].size - assert_equal 'v02', actual['{s}1']['0-2']['f'] - assert_equal 'v12', actual['{s}2']['1-2']['f'] + + assert_equal %w(0-2), actual['{s}1'].map(&:first) + assert_equal %w(v02), actual['{s}1'].map { |i| i.last['f'] } + + assert_equal %w(1-2), actual['{s}2'].map(&:first) + assert_equal %w(v12), actual['{s}2'].map { |i| i.last['f'] } end end diff --git a/test/lint/streams.rb b/test/lint/streams.rb index f97a7b4c7..1b908cefb 100644 --- a/test/lint/streams.rb +++ b/test/lint/streams.rb @@ -152,43 +152,36 @@ def test_xrange actual = redis.xrange('s1') - assert_equal 'v1', actual['0-1']['f'] - assert_equal 'v2', actual['0-2']['f'] - assert_equal 'v3', actual['0-3']['f'] + assert_equal %w(v1 v2 v3), actual.map { |i| i.last['f'] } end - def test_xrange_with_first_option + def test_xrange_with_start_option redis.xadd('s1', { f: 'v' }, id: '0-1') redis.xadd('s1', { f: 'v' }, id: '0-2') redis.xadd('s1', { f: 'v' }, id: '0-3') - actual = redis.xrange('s1', first: '0-2') + actual = redis.xrange('s1', '0-2') - assert_equal 2, actual.size - assert_equal '0-2', actual.keys.first + assert_equal %w(0-2 0-3), actual.map(&:first) end - def test_xrange_with_last_option + def test_xrange_with_end_option redis.xadd('s1', { f: 'v' }, id: '0-1') redis.xadd('s1', { f: 'v' }, id: '0-2') redis.xadd('s1', { f: 'v' }, id: '0-3') - actual = redis.xrange('s1', last: '0-2') - - assert_equal 2, actual.size - assert_equal '0-1', actual.keys.first - assert_equal '0-2', actual.keys.last + actual = redis.xrange('s1', '-', '0-2') + assert_equal %w(0-1 0-2), actual.map(&:first) end - def test_xrange_with_first_and_last_options + def test_xrange_with_start_and_end_options redis.xadd('s1', { f: 'v' }, id: '0-1') redis.xadd('s1', { f: 'v' }, id: '0-2') redis.xadd('s1', { f: 'v' }, id: '0-3') - actual = redis.xrange('s1', first: '0-2', last: '0-2') + actual = redis.xrange('s1', '0-2', '0-2') - assert_equal 1, actual.size - assert_equal '0-2', actual.keys.first + assert_equal %w(0-2), actual.map(&:first) end def test_xrange_with_incomplete_entry_id_options @@ -196,10 +189,10 @@ def test_xrange_with_incomplete_entry_id_options redis.xadd('s1', { f: 'v' }, id: '1-1') redis.xadd('s1', { f: 'v' }, id: '2-1') - actual = redis.xrange('s1', first: '0', last: '1') + actual = redis.xrange('s1', '0', '1') assert_equal 2, actual.size - assert_equal '0-1', actual.keys.first + assert_equal %w(0-1 1-1), actual.map(&:first) end def test_xrange_with_count_option @@ -209,21 +202,20 @@ def test_xrange_with_count_option actual = redis.xrange('s1', count: 2) - assert_equal 2, actual.size - assert_equal '0-1', actual.keys.first + assert_equal %w(0-1 0-2), actual.map(&:first) end def test_xrange_with_not_existed_stream_key - assert_equal({}, redis.xrange('not-existed')) + assert_equal([], redis.xrange('not-existed')) end def test_xrange_with_invalid_entry_id_options - assert_raise(Redis::CommandError) { redis.xrange('s1', first: 'invalid', last: 'invalid') } + assert_raise(Redis::CommandError) { redis.xrange('s1', 'invalid', 'invalid') } end def test_xrange_with_invalid_arguments - assert_equal({}, redis.xrange(nil)) - assert_equal({}, redis.xrange('')) + assert_equal([], redis.xrange(nil)) + assert_equal([], redis.xrange('')) end def test_xrevrange @@ -233,44 +225,38 @@ def test_xrevrange actual = redis.xrevrange('s1') - assert_equal '0-3', actual.keys.first - assert_equal 'v1', actual['0-1']['f'] - assert_equal 'v2', actual['0-2']['f'] - assert_equal 'v3', actual['0-3']['f'] + assert_equal %w(0-3 0-2 0-1), actual.map(&:first) + assert_equal %w(v3 v2 v1), actual.map { |i| i.last['f'] } end - def test_xrevrange_with_first_option + def test_xrevrange_with_start_option redis.xadd('s1', { f: 'v' }, id: '0-1') redis.xadd('s1', { f: 'v' }, id: '0-2') redis.xadd('s1', { f: 'v' }, id: '0-3') - actual = redis.xrevrange('s1', first: '0-2') + actual = redis.xrevrange('s1', '+', '0-2') - assert_equal 2, actual.size - assert_equal '0-3', actual.keys.first + assert_equal %w(0-3 0-2), actual.map(&:first) end - def test_xrevrange_with_last_option + def test_xrevrange_with_end_option redis.xadd('s1', { f: 'v' }, id: '0-1') redis.xadd('s1', { f: 'v' }, id: '0-2') redis.xadd('s1', { f: 'v' }, id: '0-3') - actual = redis.xrevrange('s1', last: '0-2') + actual = redis.xrevrange('s1', '0-2') - assert_equal 2, actual.size - assert_equal '0-2', actual.keys.first - assert_equal '0-1', actual.keys.last + assert_equal %w(0-2 0-1), actual.map(&:first) end - def test_xrevrange_with_first_and_last_options + def test_xrevrange_with_start_and_end_options redis.xadd('s1', { f: 'v' }, id: '0-1') redis.xadd('s1', { f: 'v' }, id: '0-2') redis.xadd('s1', { f: 'v' }, id: '0-3') - actual = redis.xrevrange('s1', first: '0-2', last: '0-2') + actual = redis.xrevrange('s1', '0-2', '0-2') - assert_equal 1, actual.size - assert_equal '0-2', actual.keys.first + assert_equal %w(0-2), actual.map(&:first) end def test_xrevrange_with_incomplete_entry_id_options @@ -278,10 +264,10 @@ def test_xrevrange_with_incomplete_entry_id_options redis.xadd('s1', { f: 'v' }, id: '1-1') redis.xadd('s1', { f: 'v' }, id: '2-1') - actual = redis.xrevrange('s1', first: '0', last: '1') + actual = redis.xrevrange('s1', '1', '0') assert_equal 2, actual.size - assert_equal '1-1', actual.keys.first + assert_equal '1-1', actual.first.first end def test_xrevrange_with_count_option @@ -292,20 +278,20 @@ def test_xrevrange_with_count_option actual = redis.xrevrange('s1', count: 2) assert_equal 2, actual.size - assert_equal '0-3', actual.keys.first + assert_equal '0-3', actual.first.first end def test_xrevrange_with_not_existed_stream_key - assert_equal({}, redis.xrevrange('not-existed')) + assert_equal([], redis.xrevrange('not-existed')) end def test_xrevrange_with_invalid_entry_id_options - assert_raise(Redis::CommandError) { redis.xrevrange('s1', first: 'invalid', last: 'invalid') } + assert_raise(Redis::CommandError) { redis.xrevrange('s1', 'invalid', 'invalid') } end def test_xrevrange_with_invalid_arguments - assert_equal({}, redis.xrevrange(nil)) - assert_equal({}, redis.xrevrange('')) + assert_equal([], redis.xrevrange(nil)) + assert_equal([], redis.xrevrange('')) end def test_xlen @@ -329,9 +315,7 @@ def test_xread_with_a_key actual = redis.xread('s1', 0) - assert_equal 2, actual['s1'].size - assert_equal 'v1', actual['s1']['0-1']['f'] - assert_equal 'v2', actual['s1']['0-2']['f'] + assert_equal %w(v1 v2), actual.fetch('s1').map { |i| i.last['f'] } end def test_xread_with_multiple_keys @@ -344,8 +328,8 @@ def test_xread_with_multiple_keys assert_equal 1, actual['s1'].size assert_equal 1, actual['s2'].size - assert_equal 'v02', actual['s1']['0-2']['f'] - assert_equal 'v12', actual['s2']['1-2']['f'] + assert_equal 'v02', actual['s1'][0].last['f'] + assert_equal 'v12', actual['s2'][0].last['f'] end def test_xread_with_count_option @@ -423,8 +407,8 @@ def test_xreadgroup_with_a_key actual = redis.xreadgroup('g1', 'c1', 's1', '>') assert_equal 2, actual['s1'].size - assert_equal 'v2', actual['s1']['0-2']['f'] - assert_equal 'v3', actual['s1']['0-3']['f'] + assert_equal 'v2', actual['s1'][0].last['f'] + assert_equal 'v3', actual['s1'][1].last['f'] end def test_xreadgroup_with_multiple_keys @@ -439,8 +423,8 @@ def test_xreadgroup_with_multiple_keys assert_equal 1, actual['s1'].size assert_equal 1, actual['s2'].size - assert_equal 'v02', actual['s1']['0-2']['f'] - assert_equal 'v12', actual['s2']['1-2']['f'] + assert_equal 'v02', actual['s1'][0].last['f'] + assert_equal 'v12', actual['s2'][0].last['f'] end def test_xreadgroup_with_count_option @@ -533,9 +517,8 @@ def test_xclaim_with_splatted_entry_ids actual = redis.xclaim('s1', 'g1', 'c2', 10, '0-2', '0-3') - assert_equal 2, actual.size - assert_equal 'v2', actual['0-2']['f'] - assert_equal 'v3', actual['0-3']['f'] + assert_equal %w(0-2 0-3), actual.map(&:first) + assert_equal %w(v2 v3), actual.map { |i| i.last['f'] } end def test_xclaim_with_arrayed_entry_ids @@ -548,9 +531,8 @@ def test_xclaim_with_arrayed_entry_ids actual = redis.xclaim('s1', 'g1', 'c2', 10, %w[0-2 0-3]) - assert_equal 2, actual.size - assert_equal 'v2', actual['0-2']['f'] - assert_equal 'v3', actual['0-3']['f'] + assert_equal %w(0-2 0-3), actual.map(&:first) + assert_equal %w(v2 v3), actual.map { |i| i.last['f'] } end def test_xclaim_with_idle_option @@ -563,9 +545,8 @@ def test_xclaim_with_idle_option actual = redis.xclaim('s1', 'g1', 'c2', 10, '0-2', '0-3', idle: 0) - assert_equal 2, actual.size - assert_equal 'v2', actual['0-2']['f'] - assert_equal 'v3', actual['0-3']['f'] + assert_equal %w(0-2 0-3), actual.map(&:first) + assert_equal %w(v2 v3), actual.map { |i| i.last['f'] } end def test_xclaim_with_time_option @@ -579,9 +560,8 @@ def test_xclaim_with_time_option actual = redis.xclaim('s1', 'g1', 'c2', 10, '0-2', '0-3', time: time) - assert_equal 2, actual.size - assert_equal 'v2', actual['0-2']['f'] - assert_equal 'v3', actual['0-3']['f'] + assert_equal %w(0-2 0-3), actual.map(&:first) + assert_equal %w(v2 v3), actual.map { |i| i.last['f'] } end def test_xclaim_with_retrycount_option @@ -594,9 +574,8 @@ def test_xclaim_with_retrycount_option actual = redis.xclaim('s1', 'g1', 'c2', 10, '0-2', '0-3', retrycount: 10) - assert_equal 2, actual.size - assert_equal 'v2', actual['0-2']['f'] - assert_equal 'v3', actual['0-3']['f'] + assert_equal %w(0-2 0-3), actual.map(&:first) + assert_equal %w(v2 v3), actual.map { |i| i.last['f'] } end def test_xclaim_with_force_option @@ -609,9 +588,8 @@ def test_xclaim_with_force_option actual = redis.xclaim('s1', 'g1', 'c2', 10, '0-2', '0-3', force: true) - assert_equal 2, actual.size - assert_equal 'v2', actual['0-2']['f'] - assert_equal 'v3', actual['0-3']['f'] + assert_equal %w(0-2 0-3), actual.map(&:first) + assert_equal %w(v2 v3), actual.map { |i| i.last['f'] } end def test_xclaim_with_justid_option @@ -658,7 +636,7 @@ def test_xpending_with_range_options redis.xadd('s1', { f: 'v4' }, id: '0-4') redis.xreadgroup('g1', 'c2', 's1', '>') - actual = redis.xpending('s1', 'g1', first: '-', last: '+', count: 10) + actual = redis.xpending('s1', 'g1', '-', '+', 10) assert_equal 3, actual.size assert_equal '0-2', actual[0]['entry_id'] @@ -684,7 +662,7 @@ def test_xpending_with_range_and_consumer_options redis.xadd('s1', { f: 'v4' }, id: '0-4') redis.xreadgroup('g1', 'c2', 's1', '>') - actual = redis.xpending('s1', 'g1', 'c1', first: '-', last: '+', count: 10) + actual = redis.xpending('s1', 'g1', '-', '+', 10, 'c1') assert_equal 2, actual.size assert_equal '0-2', actual[0]['entry_id']