Skip to content

Commit

Permalink
Added Python: SETRANGE command (#299)
Browse files Browse the repository at this point in the history
  • Loading branch information
yipin-chen committed May 23, 2024
1 parent 9a3fcc5 commit ec21fb3
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 0 deletions.
30 changes: 30 additions & 0 deletions python/python/glide/async_commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,36 @@ async def incrbyfloat(self, key: str, amount: float) -> float:
await self._execute_command(RequestType.IncrByFloat, [key, str(amount)]),
)

async def setrange(self, key: str, offset: int, value: str) -> int:
"""
Overwrites part of the string stored at `key`, starting at the specified
`offset`, for the entire length of `value`.
If the `offset` is larger than the current length of the string at `key`,
the string is padded with zero bytes to make `offset` fit. Create the `key`
if it doesn't exist.
See https://valkey.io/commands/setrange for more details.
Args:
key (str): The key of the string to update.
offset (int): The position in the string where `value` should be written.
value (str): The string written with `offset`.
Returns:
int: The length of the string stored at `key` after it was modified.
Examples:
>>> await client.set("key", "Hello World")
>>> await client.setrange("key", 6, "Redis")
11 # The length of the string stored at `key` after it was modified.
"""
return cast(
int,
await self._execute_command(
RequestType.SetRange, [key, str(offset), value]
),
)

async def mset(self, key_value_map: Mapping[str, str]) -> TOK:
"""
Set multiple keys to multiple values in a single atomic operation.
Expand Down
20 changes: 20 additions & 0 deletions python/python/glide/async_commands/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,26 @@ def decrby(self: TTransaction, key: str, amount: int) -> TTransaction:
"""
return self.append_command(RequestType.DecrBy, [key, str(amount)])

def setrange(self: TTransaction, key: str, offset: int, value: str) -> TTransaction:
"""
Overwrites part of the string stored at `key`, starting at the specified
`offset`, for the entire length of `value`.
If the `offset` is larger than the current length of the string at `key`,
the string is padded with zero bytes to make `offset` fit. Create the `key`
if it doesn't exist.
See https://valkey.io/commands/setrange for more details.
Args:
key (str): The key of the string to update.
offset (int): The position in the string where `value` should be written.
value (str): The string written with `offset`.
Command response:
int: The length of the string stored at `key` after it was modified.
"""
return self.append_command(RequestType.SetRange, [key, str(offset), value])

def hset(
self: TTransaction, key: str, field_value_map: Mapping[str, str]
) -> TTransaction:
Expand Down
22 changes: 22 additions & 0 deletions python/python/tests/test_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,28 @@ async def test_decr_with_str_value(self, redis_client: TRedisClient):

assert "value is not an integer" in str(e)

@pytest.mark.parametrize("cluster_mode", [True, False])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_setrange(self, redis_client: TRedisClient):
key1 = get_random_string(10)
key2 = get_random_string(10)

# test new key and existing key
assert await redis_client.setrange(key1, 0, "Hello World") == 11
assert await redis_client.setrange(key1, 6, "GLIDE") == 11

# offset > len
assert await redis_client.setrange(key1, 15, "GLIDE") == 20

# negative offset
with pytest.raises(RequestError):
assert await redis_client.setrange(key1, -1, "GLIDE")

# non-string key
assert await redis_client.lpush(key2, ["_"]) == 1
with pytest.raises(RequestError):
assert await redis_client.setrange(key2, 0, "_")

@pytest.mark.parametrize("cluster_mode", [True, False])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_hset_hget_hgetall(self, redis_client: TRedisClient):
Expand Down
2 changes: 2 additions & 0 deletions python/python/tests/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ async def transaction_test(

transaction.set(key, value)
args.append(OK)
transaction.setrange(key, 0, value)
args.append(len(value))
transaction.get(key)
args.append(value)
transaction.type(key)
Expand Down

0 comments on commit ec21fb3

Please sign in to comment.