Skip to content

Commit

Permalink
Python: add FUNCTION DELETE command (valkey-io#1714)
Browse files Browse the repository at this point in the history
* Python: adds FUNCTION DELETE command

Co-authored-by: Shoham Elias <[email protected]>
  • Loading branch information
yipin-chen and shohamazon authored Jun 29, 2024
1 parent 0005c1b commit 6013ef7
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
* Python: Added XPENDING command ([#1704](https://github.com/aws/glide-for-redis/pull/1704))
* Python: Added RANDOMKEY command ([#1701](https://github.com/aws/glide-for-redis/pull/1701))
* Python: Added FUNCTION FLUSH command ([#1700](https://github.com/aws/glide-for-redis/pull/1700))
* Python: Added FUNCTION DELETE command ([#1714](https://github.com/aws/glide-for-redis/pull/1714))

### Breaking Changes
* Node: Update XREAD to return a Map of Map ([#1494](https://github.com/aws/glide-for-redis/pull/1494))
Expand Down
31 changes: 31 additions & 0 deletions python/python/glide/async_commands/cluster_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,37 @@ async def function_flush(
),
)

async def function_delete(
self, library_name: str, route: Optional[Route] = None
) -> TOK:
"""
Deletes a library and all its functions.
See https://valkey.io/docs/latest/commands/function-delete/ for more details.
Args:
library_code (str): The libary name to delete
route (Optional[Route]): The command will be routed to all primaries, unless `route` is provided,
in which case the client will route the command to the nodes defined by `route`.
Returns:
TOK: A simple `OK`.
Examples:
>>> await client.function_delete("my_lib")
"OK"
Since: Redis 7.0.0.
"""
return cast(
TOK,
await self._execute_command(
RequestType.FunctionDelete,
[library_name],
route,
),
)

async def time(self, route: Optional[Route] = None) -> TClusterResponse[List[str]]:
"""
Returns the server time.
Expand Down
26 changes: 26 additions & 0 deletions python/python/glide/async_commands/standalone_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,32 @@ async def function_flush(self, mode: Optional[FlushMode] = None) -> TOK:
),
)

async def function_delete(self, library_name: str) -> TOK:
"""
Deletes a library and all its functions.
See https://valkey.io/docs/latest/commands/function-delete/ for more details.
Args:
library_code (str): The libary name to delete
Returns:
TOK: A simple `OK`.
Examples:
>>> await client.function_delete("my_lib")
"OK"
Since: Redis 7.0.0.
"""
return cast(
TOK,
await self._execute_command(
RequestType.FunctionDelete,
[library_name],
),
)

async def time(self) -> List[str]:
"""
Returns the server time.
Expand Down
19 changes: 19 additions & 0 deletions python/python/glide/async_commands/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -1822,6 +1822,25 @@ def function_flush(
[mode.value] if mode else [],
)

def function_delete(self: TTransaction, library_name: str) -> TTransaction:
"""
Deletes a library and all its functions.
See https://valkey.io/docs/latest/commands/function-delete/ for more details.
Args:
library_code (str): The libary name to delete
Commands response:
TOK: A simple `OK`.
Since: Redis 7.0.0.
"""
return self.append_command(
RequestType.FunctionDelete,
[library_name],
)

def xadd(
self: TTransaction,
key: str,
Expand Down
58 changes: 58 additions & 0 deletions python/python/tests/test_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6673,6 +6673,7 @@ async def test_function_load(self, redis_client: TGlideClient):
assert await redis_client.function_load(code, True) == lib_name

func2_name = f"myfunc2c{get_random_string(5)}"
new_code = f"""{code}\n redis.register_function({func2_name}, function(keys, args) return #args end)"""
new_code = generate_lua_lib_code(
lib_name, {func_name: "return args[1]", func2_name: "return #args"}, True
)
Expand Down Expand Up @@ -6725,6 +6726,7 @@ async def test_function_load_cluster_with_route(
assert await redis_client.function_load(code, True, route) == lib_name

func2_name = f"myfunc2c{get_random_string(5)}"
new_code = f"""{code}\n redis.register_function({func2_name}, function(keys, args) return #args end)"""
new_code = generate_lua_lib_code(
lib_name, {func_name: "return args[1]", func2_name: "return #args"}, True
)
Expand Down Expand Up @@ -6791,6 +6793,62 @@ async def test_function_flush_with_routing(
# Clean up by flushing functions again
assert await redis_client.function_flush(route=route) == OK

@pytest.mark.parametrize("cluster_mode", [True, False])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_function_delete(self, redis_client: TGlideClient):
min_version = "7.0.0"
if await check_if_server_version_lt(redis_client, min_version):
pytest.skip(f"Redis version required >= {min_version}")

lib_name = f"mylib1C{get_random_string(5)}"
func_name = f"myfunc1c{get_random_string(5)}"
code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True)

# Load the function
assert await redis_client.function_load(code) == lib_name

# TODO: Ensure the library exists with FUNCTION LIST

# Delete the function
assert await redis_client.function_delete(lib_name) == OK

# TODO: Ensure the function is no longer present with FUNCTION LIST

# deleting a non-existing library
with pytest.raises(RequestError) as e:
await redis_client.function_delete(lib_name)
assert "Library not found" in str(e)

@pytest.mark.parametrize("cluster_mode", [True])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
@pytest.mark.parametrize("single_route", [True, False])
async def test_function_delete_with_routing(
self, redis_client: GlideClusterClient, single_route: bool
):
min_version = "7.0.0"
if await check_if_server_version_lt(redis_client, min_version):
pytest.skip(f"Redis version required >= {min_version}")

lib_name = f"mylib1C{get_random_string(5)}"
func_name = f"myfunc1c{get_random_string(5)}"
code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True)
route = SlotKeyRoute(SlotType.PRIMARY, "1") if single_route else AllPrimaries()

# Load the function
assert await redis_client.function_load(code, False, route) == lib_name

# TODO: Ensure the library exists with FUNCTION LIST

# Delete the function
assert await redis_client.function_delete(lib_name, route) == OK

# TODO: Ensure the function is no longer present with FUNCTION LIST

# deleting a non-existing library
with pytest.raises(RequestError) as e:
await redis_client.function_delete(lib_name)
assert "Library not found" in str(e)

@pytest.mark.parametrize("cluster_mode", [True, False])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_srandmember(self, redis_client: TGlideClient):
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 @@ -102,6 +102,8 @@ async def transaction_test(
args.append(lib_name)
transaction.function_load(code, True)
args.append(lib_name)
transaction.function_delete(lib_name)
args.append(OK)
transaction.function_flush()
args.append(OK)
transaction.function_flush(FlushMode.ASYNC)
Expand Down

0 comments on commit 6013ef7

Please sign in to comment.