Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: Add FUNCTION DELETE command. #1523

Merged
merged 2 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
acarbonetto marked this conversation as resolved.
Show resolved Hide resolved

// 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";

acarbonetto marked this conversation as resolved.
Show resolved Hide resolved
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();
acarbonetto marked this conversation as resolved.
Show resolved Hide resolved
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)
// function returns first argument
.append("', function(keys, args) return args[1] end)\n");
}
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
Loading