|
9 | 9 | from typing import Any, Callable, Dict, Tuple
|
10 | 10 |
|
11 | 11 | from redis.client import CaseInsensitiveDict, PubSub, Redis, parse_scan
|
12 |
| -from redis.commands import CommandsParser, RedisClusterCommands |
| 12 | +from redis.commands import READ_COMMANDS, CommandsParser, RedisClusterCommands |
13 | 13 | from redis.connection import ConnectionPool, DefaultParser, Encoder, parse_url
|
14 | 14 | from redis.crc import REDIS_CLUSTER_HASH_SLOTS, key_slot
|
15 | 15 | from redis.exceptions import (
|
@@ -154,52 +154,6 @@ def parse_cluster_shards(resp, **options):
|
154 | 154 | )
|
155 | 155 | KWARGS_DISABLED_KEYS = ("host", "port")
|
156 | 156 |
|
157 |
| -# Not complete, but covers the major ones |
158 |
| -# https://redis.io/commands |
159 |
| -READ_COMMANDS = frozenset( |
160 |
| - [ |
161 |
| - "BITCOUNT", |
162 |
| - "BITPOS", |
163 |
| - "EXISTS", |
164 |
| - "GEODIST", |
165 |
| - "GEOHASH", |
166 |
| - "GEOPOS", |
167 |
| - "GEORADIUS", |
168 |
| - "GEORADIUSBYMEMBER", |
169 |
| - "GET", |
170 |
| - "GETBIT", |
171 |
| - "GETRANGE", |
172 |
| - "HEXISTS", |
173 |
| - "HGET", |
174 |
| - "HGETALL", |
175 |
| - "HKEYS", |
176 |
| - "HLEN", |
177 |
| - "HMGET", |
178 |
| - "HSTRLEN", |
179 |
| - "HVALS", |
180 |
| - "KEYS", |
181 |
| - "LINDEX", |
182 |
| - "LLEN", |
183 |
| - "LRANGE", |
184 |
| - "MGET", |
185 |
| - "PTTL", |
186 |
| - "RANDOMKEY", |
187 |
| - "SCARD", |
188 |
| - "SDIFF", |
189 |
| - "SINTER", |
190 |
| - "SISMEMBER", |
191 |
| - "SMEMBERS", |
192 |
| - "SRANDMEMBER", |
193 |
| - "STRLEN", |
194 |
| - "SUNION", |
195 |
| - "TTL", |
196 |
| - "ZCARD", |
197 |
| - "ZCOUNT", |
198 |
| - "ZRANGE", |
199 |
| - "ZSCORE", |
200 |
| - ] |
201 |
| -) |
202 |
| - |
203 | 157 |
|
204 | 158 | def cleanup_kwargs(**kwargs):
|
205 | 159 | """
|
@@ -1993,14 +1947,25 @@ def _send_cluster_commands(
|
1993 | 1947 | # refer to our internal node -> slot table that
|
1994 | 1948 | # tells us where a given
|
1995 | 1949 | # command should route to.
|
1996 |
| - node = self._determine_nodes(*c.args) |
| 1950 | + passed_targets = c.options.pop("target_nodes", None) |
| 1951 | + if passed_targets and not self._is_nodes_flag(passed_targets): |
| 1952 | + target_nodes = self._parse_target_nodes(passed_targets) |
| 1953 | + else: |
| 1954 | + target_nodes = self._determine_nodes(*c.args, node_flag=passed_targets) |
| 1955 | + if not target_nodes: |
| 1956 | + raise RedisClusterException( |
| 1957 | + f"No targets were found to execute {c.args} command on" |
| 1958 | + ) |
| 1959 | + if len(target_nodes) > 1: |
| 1960 | + raise RedisClusterException(f"Too many targets for command {c.args}") |
1997 | 1961 |
|
| 1962 | + node = target_nodes[0] |
1998 | 1963 | # now that we know the name of the node
|
1999 | 1964 | # ( it's just a string in the form of host:port )
|
2000 | 1965 | # we can build a list of commands for each node.
|
2001 |
| - node_name = node[0].name |
| 1966 | + node_name = node.name |
2002 | 1967 | if node_name not in nodes:
|
2003 |
| - redis_node = self.get_redis_connection(node[0]) |
| 1968 | + redis_node = self.get_redis_connection(node) |
2004 | 1969 | connection = get_connection(redis_node, c.args)
|
2005 | 1970 | nodes[node_name] = NodeCommands(
|
2006 | 1971 | redis_node.parse_response, redis_node.connection_pool, connection
|
|
0 commit comments