Skip to content

Commit 59744fd

Browse files
feat(java): Implement missing eval & script commands (#5125)
* Implement missing evalsha & script command for java client Signed-off-by: Sasidharan Gopal <[email protected]> * Applying splotlessapply changes Signed-off-by: Sasidharan Gopal <[email protected]> * Update test for script debug Signed-off-by: Sasidharan Gopal <[email protected]> * Fixing tests Signed-off-by: Sasidharan Gopal <[email protected]> * Addressing review comments Signed-off-by: Sasidharan Gopal <[email protected]> * Updating CHANGELOG Signed-off-by: Sasidharan Gopal <[email protected]> * Fixing spotlessApply changes Signed-off-by: Sasidharan Gopal <[email protected]> --------- Signed-off-by: Sasidharan Gopal <[email protected]> Signed-off-by: Sasidharan3094 <[email protected]> Co-authored-by: Thomas Zhou <[email protected]>
1 parent 0031ed0 commit 59744fd

File tree

6 files changed

+389
-1
lines changed

6 files changed

+389
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#### Changes
44

5+
* JAVA: Add EVAL_RO, EVALSHA_RO, and SCRIPT DEBUG commands ([#5125](https://github.com/valkey-io/valkey-glide/pull/5125))
56
* CORE: Add client certificate and private key support for mTLS ([#5092](https://github.com/valkey-io/valkey-glide/issues/5092))
67
* Python: Add client certificate and private key support for mTLS ([5123](https://github.com/valkey-io/valkey-glide/issues/5123))
78

glide-core/src/request_type.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,9 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
682682
ProtobufRequestType::PubSubNumPat => RequestType::PubSubNumPat,
683683
ProtobufRequestType::PubSubShardChannels => RequestType::PubSubShardChannels,
684684
ProtobufRequestType::PubSubShardNumSub => RequestType::PubSubShardNumSub,
685+
ProtobufRequestType::EvalReadOnly => RequestType::EvalReadOnly,
686+
ProtobufRequestType::EvalShaReadOnly => RequestType::EvalShaReadOnly,
687+
ProtobufRequestType::ScriptDebug => RequestType::ScriptDebug,
685688
ProtobufRequestType::ScriptExists => RequestType::ScriptExists,
686689
ProtobufRequestType::ScriptFlush => RequestType::ScriptFlush,
687690
ProtobufRequestType::ScriptKill => RequestType::ScriptKill,
@@ -1081,10 +1084,13 @@ impl RequestType {
10811084
Some(get_two_word_command("PUBSUB", "SHARDCHANNELS"))
10821085
}
10831086
RequestType::PubSubShardNumSub => Some(get_two_word_command("PUBSUB", "SHARDNUMSUB")),
1084-
RequestType::ScriptShow => Some(get_two_word_command("SCRIPT", "SHOW")),
1087+
RequestType::EvalReadOnly => Some(cmd("EVAL_RO")),
1088+
RequestType::EvalShaReadOnly => Some(cmd("EVALSHA_RO")),
1089+
RequestType::ScriptDebug => Some(get_two_word_command("SCRIPT", "DEBUG")),
10851090
RequestType::ScriptExists => Some(get_two_word_command("SCRIPT", "EXISTS")),
10861091
RequestType::ScriptFlush => Some(get_two_word_command("SCRIPT", "FLUSH")),
10871092
RequestType::ScriptKill => Some(get_two_word_command("SCRIPT", "KILL")),
1093+
RequestType::ScriptShow => Some(get_two_word_command("SCRIPT", "SHOW")),
10881094
RequestType::JsonArrAppend => Some(cmd("JSON.ARRAPPEND")),
10891095
RequestType::JsonArrIndex => Some(cmd("JSON.ARRINDEX")),
10901096
RequestType::JsonArrInsert => Some(cmd("JSON.ARRINSERT")),

java/client/src/main/java/glide/api/BaseClient.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import static command_request.CommandRequestOuterClass.RequestType.DecrBy;
2020
import static command_request.CommandRequestOuterClass.RequestType.Del;
2121
import static command_request.CommandRequestOuterClass.RequestType.Dump;
22+
import static command_request.CommandRequestOuterClass.RequestType.EvalReadOnly;
23+
import static command_request.CommandRequestOuterClass.RequestType.EvalShaReadOnly;
2224
import static command_request.CommandRequestOuterClass.RequestType.Exists;
2325
import static command_request.CommandRequestOuterClass.RequestType.Expire;
2426
import static command_request.CommandRequestOuterClass.RequestType.ExpireAt;
@@ -122,6 +124,7 @@
122124
import static command_request.CommandRequestOuterClass.RequestType.SScan;
123125
import static command_request.CommandRequestOuterClass.RequestType.SUnion;
124126
import static command_request.CommandRequestOuterClass.RequestType.SUnionStore;
127+
import static command_request.CommandRequestOuterClass.RequestType.ScriptDebug;
125128
import static command_request.CommandRequestOuterClass.RequestType.ScriptExists;
126129
import static command_request.CommandRequestOuterClass.RequestType.ScriptFlush;
127130
import static command_request.CommandRequestOuterClass.RequestType.ScriptKill;
@@ -246,6 +249,7 @@
246249
import glide.api.models.commands.RangeOptions.ScoredRangeQuery;
247250
import glide.api.models.commands.RestoreOptions;
248251
import glide.api.models.commands.ScoreFilter;
252+
import glide.api.models.commands.ScriptDebugMode;
249253
import glide.api.models.commands.ScriptOptions;
250254
import glide.api.models.commands.ScriptOptionsGlideString;
251255
import glide.api.models.commands.SetOptions;
@@ -5016,6 +5020,68 @@ public CompletableFuture<Object> fcallReadOnly(
50165020
FCallReadOnly, args, this::handleBinaryObjectOrNullResponse);
50175021
}
50185022

5023+
@Override
5024+
public CompletableFuture<Object> evalReadOnly(@NonNull String script) {
5025+
return evalReadOnly(script, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY);
5026+
}
5027+
5028+
@Override
5029+
public CompletableFuture<Object> evalReadOnly(
5030+
@NonNull String script, @NonNull String[] keys, @NonNull String[] args) {
5031+
String[] arguments =
5032+
concatenateArrays(new String[] {script, String.valueOf(keys.length)}, keys, args);
5033+
return commandManager.submitNewCommand(
5034+
EvalReadOnly, arguments, this::handleObjectOrNullResponse);
5035+
}
5036+
5037+
@Override
5038+
public CompletableFuture<Object> evalReadOnly(@NonNull GlideString script) {
5039+
return evalReadOnly(script, EMPTY_GLIDE_STRING_ARRAY, EMPTY_GLIDE_STRING_ARRAY);
5040+
}
5041+
5042+
@Override
5043+
public CompletableFuture<Object> evalReadOnly(
5044+
@NonNull GlideString script, @NonNull GlideString[] keys, @NonNull GlideString[] args) {
5045+
GlideString[] arguments =
5046+
concatenateArrays(new GlideString[] {script, gs(String.valueOf(keys.length))}, keys, args);
5047+
return commandManager.submitNewCommand(
5048+
EvalReadOnly, arguments, this::handleBinaryObjectOrNullResponse);
5049+
}
5050+
5051+
@Override
5052+
public CompletableFuture<Object> evalshaReadOnly(@NonNull String sha1) {
5053+
return evalshaReadOnly(sha1, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY);
5054+
}
5055+
5056+
@Override
5057+
public CompletableFuture<Object> evalshaReadOnly(
5058+
@NonNull String sha1, @NonNull String[] keys, @NonNull String[] args) {
5059+
String[] arguments =
5060+
concatenateArrays(new String[] {sha1, String.valueOf(keys.length)}, keys, args);
5061+
return commandManager.submitNewCommand(
5062+
EvalShaReadOnly, arguments, this::handleObjectOrNullResponse);
5063+
}
5064+
5065+
@Override
5066+
public CompletableFuture<Object> evalshaReadOnly(@NonNull GlideString sha1) {
5067+
return evalshaReadOnly(sha1, EMPTY_GLIDE_STRING_ARRAY, EMPTY_GLIDE_STRING_ARRAY);
5068+
}
5069+
5070+
@Override
5071+
public CompletableFuture<Object> evalshaReadOnly(
5072+
@NonNull GlideString sha1, @NonNull GlideString[] keys, @NonNull GlideString[] args) {
5073+
GlideString[] arguments =
5074+
concatenateArrays(new GlideString[] {sha1, gs(String.valueOf(keys.length))}, keys, args);
5075+
return commandManager.submitNewCommand(
5076+
EvalShaReadOnly, arguments, this::handleBinaryObjectOrNullResponse);
5077+
}
5078+
5079+
@Override
5080+
public CompletableFuture<String> scriptDebug(@NonNull ScriptDebugMode mode) {
5081+
return commandManager.submitNewCommand(
5082+
ScriptDebug, new String[] {mode.name()}, this::handleStringResponse);
5083+
}
5084+
50195085
@Override
50205086
public CompletableFuture<Boolean> copy(
50215087
@NonNull String source, @NonNull String destination, boolean replace) {

java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsBaseCommands.java

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import glide.api.models.GlideString;
55
import glide.api.models.Script;
6+
import glide.api.models.commands.ScriptDebugMode;
67
import glide.api.models.commands.ScriptOptions;
78
import glide.api.models.commands.ScriptOptionsGlideString;
89
import glide.api.models.configuration.ReadFrom;
@@ -246,4 +247,173 @@ CompletableFuture<Object> fcallReadOnly(
246247
* }</pre>
247248
*/
248249
CompletableFuture<Object> invokeScript(Script script, ScriptOptionsGlideString options);
250+
251+
/**
252+
* Executes a read-only Lua script.<br>
253+
* This command is routed depending on the client's {@link ReadFrom} strategy.
254+
*
255+
* @since Valkey 7.0 and above.
256+
* @see <a href="https://valkey.io/commands/eval_ro/">valkey.io</a> for details.
257+
* @param script The Lua script to execute.
258+
* @return A value that depends on the script that was executed.
259+
* @example
260+
* <pre>{@code
261+
* String script = "return 'Hello, World!'";
262+
* String result = (String) client.evalReadOnly(script).get();
263+
* assert result.equals("Hello, World!");
264+
* }</pre>
265+
*/
266+
CompletableFuture<Object> evalReadOnly(String script);
267+
268+
/**
269+
* Executes a read-only Lua script with keys and arguments.<br>
270+
* This command is routed depending on the client's {@link ReadFrom} strategy.
271+
*
272+
* @apiNote When in cluster mode, all <code>keys</code> must map to the same hash slot.
273+
* @since Valkey 7.0 and above.
274+
* @see <a href="https://valkey.io/commands/eval_ro/">valkey.io</a> for details.
275+
* @param script The Lua script to execute.
276+
* @param keys An array of keys accessed by the script.
277+
* @param args An array of script arguments.
278+
* @return A value that depends on the script that was executed.
279+
* @example
280+
* <pre>{@code
281+
* String script = "return {KEYS[1], ARGV[1]}";
282+
* Object[] result = (Object[]) client.evalReadOnly(script, new String[]{"key1"}, new String[]{"arg1"}).get();
283+
* assert result[0].equals("key1");
284+
* assert result[1].equals("arg1");
285+
* }</pre>
286+
*/
287+
CompletableFuture<Object> evalReadOnly(String script, String[] keys, String[] args);
288+
289+
/**
290+
* Executes a read-only Lua script.<br>
291+
* This command is routed depending on the client's {@link ReadFrom} strategy.
292+
*
293+
* @since Valkey 7.0 and above.
294+
* @see <a href="https://valkey.io/commands/eval_ro/">valkey.io</a> for details.
295+
* @param script The Lua script to execute.
296+
* @return A value that depends on the script that was executed.
297+
* @example
298+
* <pre>{@code
299+
* GlideString script = gs("return 'Hello, World!'");
300+
* GlideString result = (GlideString) client.evalReadOnly(script).get();
301+
* assert result.equals(gs("Hello, World!"));
302+
* }</pre>
303+
*/
304+
CompletableFuture<Object> evalReadOnly(GlideString script);
305+
306+
/**
307+
* Executes a read-only Lua script with keys and arguments.<br>
308+
* This command is routed depending on the client's {@link ReadFrom} strategy.
309+
*
310+
* @apiNote When in cluster mode, all <code>keys</code> must map to the same hash slot.
311+
* @since Valkey 7.0 and above.
312+
* @see <a href="https://valkey.io/commands/eval_ro/">valkey.io</a> for details.
313+
* @param script The Lua script to execute.
314+
* @param keys An array of keys accessed by the script.
315+
* @param args An array of script arguments.
316+
* @return A value that depends on the script that was executed.
317+
* @example
318+
* <pre>{@code
319+
* GlideString script = gs("return {KEYS[1], ARGV[1]}");
320+
* Object[] result = (Object[]) client.evalReadOnly(script, new GlideString[]{gs("key1")}, new GlideString[]{gs("arg1")}).get();
321+
* assert result[0].equals(gs("key1"));
322+
* assert result[1].equals(gs("arg1"));
323+
* }</pre>
324+
*/
325+
CompletableFuture<Object> evalReadOnly(
326+
GlideString script, GlideString[] keys, GlideString[] args);
327+
328+
/**
329+
* Executes a read-only Lua script by its SHA1 digest.<br>
330+
* This command is routed depending on the client's {@link ReadFrom} strategy.
331+
*
332+
* @since Valkey 7.0 and above.
333+
* @see <a href="https://valkey.io/commands/evalsha_ro/">valkey.io</a> for details.
334+
* @param sha1 The SHA1 digest of the script to execute.
335+
* @return A value that depends on the script that was executed.
336+
* @example
337+
* <pre>{@code
338+
* String sha1 = client.scriptLoad("return 'Hello from SHA!'").get();
339+
* String result = (String) client.evalshaReadOnly(sha1).get();
340+
* assert result.equals("Hello from SHA!");
341+
* }</pre>
342+
*/
343+
CompletableFuture<Object> evalshaReadOnly(String sha1);
344+
345+
/**
346+
* Executes a read-only Lua script by its SHA1 digest with keys and arguments.<br>
347+
* This command is routed depending on the client's {@link ReadFrom} strategy.
348+
*
349+
* @apiNote When in cluster mode, all <code>keys</code> must map to the same hash slot.
350+
* @since Valkey 7.0 and above.
351+
* @see <a href="https://valkey.io/commands/evalsha_ro/">valkey.io</a> for details.
352+
* @param sha1 The SHA1 digest of the script to execute.
353+
* @param keys An array of keys accessed by the script.
354+
* @param args An array of script arguments.
355+
* @return A value that depends on the script that was executed.
356+
* @example
357+
* <pre>{@code
358+
* String sha1 = client.scriptLoad("return {KEYS[1], ARGV[1]}").get();
359+
* Object[] result = (Object[]) client.evalshaReadOnly(sha1, new String[]{"key1"}, new String[]{"arg1"}).get();
360+
* assert result[0].equals("key1");
361+
* assert result[1].equals("arg1");
362+
* }</pre>
363+
*/
364+
CompletableFuture<Object> evalshaReadOnly(String sha1, String[] keys, String[] args);
365+
366+
/**
367+
* Executes a read-only Lua script by its SHA1 digest.<br>
368+
* This command is routed depending on the client's {@link ReadFrom} strategy.
369+
*
370+
* @since Valkey 7.0 and above.
371+
* @see <a href="https://valkey.io/commands/evalsha_ro/">valkey.io</a> for details.
372+
* @param sha1 The SHA1 digest of the script to execute.
373+
* @return A value that depends on the script that was executed.
374+
* @example
375+
* <pre>{@code
376+
* GlideString sha1 = client.scriptLoad(gs("return 'Hello from SHA!'")).get();
377+
* GlideString result = (GlideString) client.evalshaReadOnly(sha1).get();
378+
* assert result.equals(gs("Hello from SHA!"));
379+
* }</pre>
380+
*/
381+
CompletableFuture<Object> evalshaReadOnly(GlideString sha1);
382+
383+
/**
384+
* Executes a read-only Lua script by its SHA1 digest with keys and arguments.<br>
385+
* This command is routed depending on the client's {@link ReadFrom} strategy.
386+
*
387+
* @apiNote When in cluster mode, all <code>keys</code> must map to the same hash slot.
388+
* @since Valkey 7.0 and above.
389+
* @see <a href="https://valkey.io/commands/evalsha_ro/">valkey.io</a> for details.
390+
* @param sha1 The SHA1 digest of the script to execute.
391+
* @param keys An array of keys accessed by the script.
392+
* @param args An array of script arguments.
393+
* @return A value that depends on the script that was executed.
394+
* @example
395+
* <pre>{@code
396+
* GlideString sha1 = client.scriptLoad(gs("return {KEYS[1], ARGV[1]}")).get();
397+
* Object[] result = (Object[]) client.evalshaReadOnly(sha1, new GlideString[]{gs("key1")}, new GlideString[]{gs("arg1")}).get();
398+
* assert result[0].equals(gs("key1"));
399+
* assert result[1].equals(gs("arg1"));
400+
* }</pre>
401+
*/
402+
CompletableFuture<Object> evalshaReadOnly(
403+
GlideString sha1, GlideString[] keys, GlideString[] args);
404+
405+
/**
406+
* Sets the debugging mode for executed scripts.
407+
*
408+
* @since Redis 3.2 and above.
409+
* @see <a href="https://valkey.io/commands/script-debug/">valkey.io</a> for details.
410+
* @param mode The debugging mode to set.
411+
* @return <code>OK</code>.
412+
* @example
413+
* <pre>{@code
414+
* String response = client.scriptDebug(ScriptDebugMode.YES).get();
415+
* assert response.equals("OK");
416+
* }</pre>
417+
*/
418+
CompletableFuture<String> scriptDebug(ScriptDebugMode mode);
249419
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */
2+
package glide.api.models.commands;
3+
4+
import glide.api.commands.ScriptingAndFunctionsBaseCommands;
5+
6+
/**
7+
* Defines the debugging mode for executed scripts.
8+
*
9+
* @see ScriptingAndFunctionsBaseCommands#scriptDebug(ScriptDebugMode)
10+
*/
11+
public enum ScriptDebugMode {
12+
/**
13+
* Enable non-blocking asynchronous debugging mode. The server will fork a debugging session that
14+
* won't block the server.
15+
*/
16+
YES,
17+
18+
/**
19+
* Enable blocking synchronous debugging mode. The server will block and wait for commands from
20+
* the debugging client.
21+
*/
22+
SYNC,
23+
24+
/** Disable script debugging mode. */
25+
NO
26+
}

0 commit comments

Comments
 (0)