diff --git a/lib/redis_client/cluster/key_slot_converter.rb b/lib/redis_client/cluster/key_slot_converter.rb index 8fee491..3701271 100644 --- a/lib/redis_client/cluster/key_slot_converter.rb +++ b/lib/redis_client/cluster/key_slot_converter.rb @@ -70,6 +70,17 @@ def extract_hash_tag(key) key[s + 1..e - 1] end + + def hash_tag_included?(key) + key = key.to_s + s = key.index(LEFT_BRACKET) + return false if s.nil? + + e = key.index(RIGHT_BRACKET, s + 1) + return false if e.nil? + + s + 1 < e + end end end end diff --git a/lib/redis_client/cluster/router.rb b/lib/redis_client/cluster/router.rb index 02fa49f..05b951e 100644 --- a/lib/redis_client/cluster/router.rb +++ b/lib/redis_client/cluster/router.rb @@ -336,7 +336,7 @@ def send_watch_command(command) def send_multiple_keys_command(cmd, method, command, args, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity key_step = @command.determine_key_step(cmd) - if command.size <= key_step + 1 || !::RedisClient::Cluster::KeySlotConverter.extract_hash_tag(command[1]).empty? # rubocop:disable Style/IfUnlessModifier + if command.size <= key_step + 1 || ::RedisClient::Cluster::KeySlotConverter.hash_tag_included?(command[1]) # rubocop:disable Style/IfUnlessModifier return try_send(assign_node(command), method, command, args, &block) end diff --git a/test/redis_client/cluster/test_key_slot_converter.rb b/test/redis_client/cluster/test_key_slot_converter.rb index 7de7609..2038f3a 100644 --- a/test/redis_client/cluster/test_key_slot_converter.rb +++ b/test/redis_client/cluster/test_key_slot_converter.rb @@ -48,6 +48,27 @@ def test_extract_hash_tag assert_equal(c[:want], got, msg) end end + + def test_hash_tag_included? + [ + { key: 'foo', want: false }, + { key: 'foo{bar}baz', want: true }, + { key: 'foo{bar}baz{qux}quuc', want: true }, + { key: 'foo}bar{baz', want: false }, + { key: 'foo{bar', want: false }, + { key: 'foo}bar', want: false }, + { key: 'foo{}bar', want: false }, + { key: '{}foo', want: false }, + { key: 'foo{}', want: false }, + { key: '{}', want: false }, + { key: '', want: false }, + { key: nil, want: false } + ].each_with_index do |c, idx| + msg = "Case: #{idx}" + got = ::RedisClient::Cluster::KeySlotConverter.hash_tag_included?(c[:key]) + assert_equal(c[:want], got, msg) + end + end end end end