Skip to content

Commit

Permalink
Java: Add FUNCTION DELETE command. (#287)
Browse files Browse the repository at this point in the history
* Add `FUNCTION DELETE` command.

Signed-off-by: Yury-Fridlyand <[email protected]>

* Address PR comments.

Signed-off-by: Yury-Fridlyand <[email protected]>

---------

Signed-off-by: Yury-Fridlyand <[email protected]>
  • Loading branch information
Yury-Fridlyand committed Jun 5, 2024
1 parent 200d68f commit 9f9ddf6
Show file tree
Hide file tree
Showing 15 changed files with 205 additions and 41 deletions.
1 change: 1 addition & 0 deletions glide-core/src/protobuf/redis_request.proto
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ enum RequestType {
HStrlen = 149;
FunctionLoad = 150;
FunctionList = 151;
FunctionDelete = 152;
LMPop = 155;
ExpireTime = 156;
PExpireTime = 157;
Expand Down
3 changes: 3 additions & 0 deletions glide-core/src/request_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ pub enum RequestType {
HStrlen = 149,
FunctionLoad = 150,
FunctionList = 151,
FunctionDelete = 152,
LMPop = 155,
ExpireTime = 156,
PExpireTime = 157,
Expand Down Expand Up @@ -340,6 +341,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::ZInter => RequestType::ZInter,
ProtobufRequestType::FunctionLoad => RequestType::FunctionLoad,
ProtobufRequestType::FunctionList => RequestType::FunctionList,
ProtobufRequestType::FunctionDelete => RequestType::FunctionDelete,
ProtobufRequestType::BitPos => RequestType::BitPos,
ProtobufRequestType::BitOp => RequestType::BitOp,
ProtobufRequestType::HStrlen => RequestType::HStrlen,
Expand Down Expand Up @@ -516,6 +518,7 @@ impl RequestType {
RequestType::ZInter => Some(cmd("ZINTER")),
RequestType::FunctionLoad => Some(get_two_word_command("FUNCTION", "LOAD")),
RequestType::FunctionList => Some(get_two_word_command("FUNCTION", "LIST")),
RequestType::FunctionDelete => Some(get_two_word_command("FUNCTION", "DELETE")),
RequestType::BitPos => Some(cmd("BITPOS")),
RequestType::BitOp => Some(cmd("BITOP")),
RequestType::HStrlen => Some(cmd("HSTRLEN")),
Expand Down
7 changes: 7 additions & 0 deletions java/client/src/main/java/glide/api/RedisClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.CustomCommand;
import static redis_request.RedisRequestOuterClass.RequestType.Echo;
import static redis_request.RedisRequestOuterClass.RequestType.FlushAll;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionDelete;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionList;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionLoad;
import static redis_request.RedisRequestOuterClass.RequestType.Info;
Expand Down Expand Up @@ -225,4 +226,10 @@ public CompletableFuture<Map<String, Object>[]> functionList(
: new String[] {LIBRARY_NAME_REDIS_API, libNamePattern},
response -> handleFunctionListResponse(handleArrayResponse(response)));
}

@Override
public CompletableFuture<String> functionDelete(@NonNull String libName) {
return commandManager.submitNewCommand(
FunctionDelete, new String[] {libName}, this::handleStringResponse);
}
}
13 changes: 13 additions & 0 deletions java/client/src/main/java/glide/api/RedisClusterClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.CustomCommand;
import static redis_request.RedisRequestOuterClass.RequestType.Echo;
import static redis_request.RedisRequestOuterClass.RequestType.FlushAll;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionDelete;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionList;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionLoad;
import static redis_request.RedisRequestOuterClass.RequestType.Info;
Expand Down Expand Up @@ -494,4 +495,16 @@ public CompletableFuture<ClusterValue<Map<String, Object>[]>> functionList(
route,
response -> handleFunctionListResponse(response, route));
}

@Override
public CompletableFuture<String> functionDelete(@NonNull String libName) {
return commandManager.submitNewCommand(
FunctionDelete, new String[] {libName}, this::handleStringResponse);
}

@Override
public CompletableFuture<String> functionDelete(@NonNull String libName, @NonNull Route route) {
return commandManager.submitNewCommand(
FunctionDelete, new String[] {libName}, route, this::handleStringResponse);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,37 @@ CompletableFuture<ClusterValue<Map<String, Object>[]>> functionList(
*/
CompletableFuture<ClusterValue<Map<String, Object>[]>> functionList(
String libNamePattern, boolean withCode, Route route);

/**
* Deletes a library and all its functions.<br>
* The command will be routed to all primary nodes.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/function-delete/">redis.io</a> for details.
* @param libName The library name to delete.
* @return <code>OK</code>.
* @example
* <pre>{@code
* String response = client.functionDelete("myLib").get();
* assert response.equals("OK");
* }</pre>
*/
CompletableFuture<String> functionDelete(String libName);

/**
* Deletes a library and all its functions.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/function-delete/">redis.io</a> for details.
* @param libName The library name to delete.
* @param route Specifies the routing configuration for the command. The client will route the
* command to the nodes defined by <code>route</code>.
* @return <code>OK</code>.
* @example
* <pre>{@code
* String response = client.functionDelete("myLib", RANDOM).get();
* assert response.equals("OK");
* }</pre>
*/
CompletableFuture<String> functionDelete(String libName, Route route);
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,19 @@ public interface ScriptingAndFunctionsCommands {
* }</pre>
*/
CompletableFuture<Map<String, Object>[]> functionList(String libNamePattern, boolean withCode);

/**
* Deletes a library and all its functions.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/function-delete/">redis.io</a> for details.
* @param libName The library name to delete.
* @return <code>OK</code>.
* @example
* <pre>{@code
* String response = client.functionDelete("myLib").get();
* assert response.equals("OK");
* }</pre>
*/
CompletableFuture<String> functionDelete(String libName);
}
14 changes: 14 additions & 0 deletions java/client/src/main/java/glide/api/models/BaseTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.ExpireTime;
import static redis_request.RedisRequestOuterClass.RequestType.FlushAll;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionDelete;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionList;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionLoad;
import static redis_request.RedisRequestOuterClass.RequestType.GeoAdd;
Expand Down Expand Up @@ -4107,6 +4108,19 @@ public T bitfieldReadOnly(
return getThis();
}

/**
* Deletes a library and all its functions.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/function-delete/">redis.io</a> for details.
* @param libName The library name to delete.
* @return Command Response - <code>OK</code>.
*/
public T functionDelete(@NonNull String libName) {
protobufTransaction.addCommands(buildCommand(FunctionDelete, buildArgs(libName)));
return getThis();
}

/** Build protobuf {@link Command} object for given command and arguments. */
protected Command buildCommand(RequestType requestType) {
return buildCommand(requestType, buildArgs());
Expand Down
25 changes: 24 additions & 1 deletion java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.ExpireTime;
import static redis_request.RedisRequestOuterClass.RequestType.FlushAll;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionDelete;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionList;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionLoad;
import static redis_request.RedisRequestOuterClass.RequestType.GeoAdd;
Expand Down Expand Up @@ -4967,6 +4968,29 @@ public void functionList_with_pattern_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void functionDelete_returns_success() {
// setup
String libName = "GLIDE";
String[] args = new String[] {libName};
String value = OK;
CompletableFuture<String> testResponse = new CompletableFuture<>();
testResponse.complete(value);

// match on protobuf request
when(commandManager.<String>submitNewCommand(eq(FunctionDelete), eq(args), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<String> response = service.functionDelete(libName);
String payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void bitcount_returns_success() {
Expand Down Expand Up @@ -5351,7 +5375,6 @@ public void lmove_returns_success() {
ListDirection whereto = ListDirection.RIGHT;
String[] arguments = new String[] {key1, key2, wherefrom.toString(), whereto.toString()};
String value = "one";

CompletableFuture<String> testResponse = new CompletableFuture<>();
testResponse.complete(value);

Expand Down
47 changes: 47 additions & 0 deletions java/client/src/test/java/glide/api/RedisClusterClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ConfigSet;
import static redis_request.RedisRequestOuterClass.RequestType.Echo;
import static redis_request.RedisRequestOuterClass.RequestType.FlushAll;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionDelete;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionList;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionLoad;
import static redis_request.RedisRequestOuterClass.RequestType.Info;
Expand Down Expand Up @@ -1270,4 +1271,50 @@ public void functionList_with_pattern_and_route_returns_success() {
assertEquals(testResponse, response);
assertEquals(value, payload.getSingleValue());
}

@SneakyThrows
@Test
public void functionDelete_returns_success() {
// setup
String libName = "GLIDE";
String[] args = new String[] {libName};
String value = OK;
CompletableFuture<String> testResponse = new CompletableFuture<>();
testResponse.complete(value);

// match on protobuf request
when(commandManager.<String>submitNewCommand(eq(FunctionDelete), eq(args), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<String> response = service.functionDelete(libName);
String payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void functionDelete_with_route_returns_success() {
// setup
String libName = "GLIDE";
String[] args = new String[] {libName};
String value = OK;
CompletableFuture<String> testResponse = new CompletableFuture<>();
testResponse.complete(value);

// match on protobuf request
when(commandManager.<String>submitNewCommand(eq(FunctionDelete), eq(args), eq(RANDOM), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<String> response = service.functionDelete(libName, RANDOM);
String payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(value, payload);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.ExpireTime;
import static redis_request.RedisRequestOuterClass.RequestType.FlushAll;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionDelete;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionList;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionLoad;
import static redis_request.RedisRequestOuterClass.RequestType.GeoAdd;
Expand Down Expand Up @@ -935,6 +936,9 @@ InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3, false), new Limit(1, 2)),
transaction.sintercard(new String[] {"key1", "key2"}, 1);
results.add(Pair.of(SInterCard, buildArgs("2", "key1", "key2", "LIMIT", "1")));

transaction.functionDelete("LIB");
results.add(Pair.of(FunctionDelete, buildArgs("LIB")));

var protobufTransaction = transaction.getProtobufTransaction().build();

for (int idx = 0; idx < protobufTransaction.getCommandsCount(); idx++) {
Expand Down
4 changes: 2 additions & 2 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -4365,8 +4365,8 @@ public void blmpop_timeout_check(BaseClient client) {
@MethodSource("getClients")
public void lset(BaseClient client) {
// setup
String key = "testKey";
String nonExistingKey = "nonExisting";
String key = UUID.randomUUID().toString();
String nonExistingKey = UUID.randomUUID().toString();
long index = 0;
long oobIndex = 10;
long negativeIndex = -1;
Expand Down
12 changes: 12 additions & 0 deletions java/integTest/src/test/java/glide/TestUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,16 @@ public static void checkFunctionListResponse(
}
assertTrue(hasLib);
}

/** Generate a dummy LUA library code. */
public static String generateLuaLibCode(String libName, List<String> funcNames) {
StringBuilder code = new StringBuilder("#!lua name=" + libName + "\n");
for (var funcName : funcNames) {
code.append("redis.register_function('")
.append(funcName)
.append(
"', function(keys, args) return args[1] end)\n"); // function returns first argument
}
return code.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ private static Object[] scriptingAndFunctionsCommands(BaseTransaction<?> transac
.functionLoad(code, true)
.functionList("otherLib", false)
.functionList("mylib1T", true)
.customCommand(new String[] {"function", "flush", "sync"});
.functionDelete("mylib1T");

return new Object[] {
OK, // customCommand("function", "flush", "sync")
Expand All @@ -715,7 +715,7 @@ private static Object[] scriptingAndFunctionsCommands(BaseTransaction<?> transac
"mylib1T", // functionLoad(code, true)
new Map[0], // functionList("otherLib", false)
expectedLibData, // functionList("mylib1T", true)
OK, // customCommand("function", "flush", "sync")
OK, // functionDelete("mylib1T")
};
}

Expand Down
Loading

0 comments on commit 9f9ddf6

Please sign in to comment.