Repository: redis/lettuce
Pull request #2868 (2024-05-30 18:00:56)

Add a `evalReadOnly` overload that accepts the script as a `String`
<!--
Thank you for proposing a pull request. This template will guide you through the essential steps necessary for a pull request.
-->
Make sure that:

- [x] You have read the [contribution guidelines](https://github.com/lettuce-io/lettuce-core/blob/main/.github/CONTRIBUTING.md).
- [ ] You have created a feature request first to discuss your contribution intent. Please reference the feature request ticket number in the pull request.
- [x] You use the code formatters provided [here](https://github.com/lettuce-io/lettuce-core/blob/main/formatting.xml) and have them applied to your changes. Don’t submit any formatting related changes.
- [x] You submit test cases (unit or integration tests) that back your changes.

 <!--
Great! Live long and prosper.
-->

-----

I am assuming the only reason why this method is missing is just an oversight, please let me know if there is anything else I should have considered.

-----

Related to #1987 



Patch:
diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
index 4749ad984..b7da8fb2f 100644
--- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
+++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
@@ -741,6 +741,12 @@ public abstract class AbstractRedisAsyncCommands<K, V> implements RedisAclAsyncC
         return (RedisFuture<T>) dispatch(commandBuilder.eval(script, type, keys, values));
     }
 
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> RedisFuture<T> evalReadOnly(String script, ScriptOutputType type, K[] keys, V... values) {
+        return evalReadOnly(encodeScript(script), type, keys, values);
+    }
+
     @Override
     public <T> RedisFuture<T> evalReadOnly(byte[] script, ScriptOutputType type, K[] keys, V... values) {
         return (RedisFuture<T>) dispatch(commandBuilder.eval(script, type, true, keys, values));
diff --git a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
index fa5630ed7..38404c1ea 100644
--- a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
+++ b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
@@ -797,6 +797,12 @@ public abstract class AbstractRedisReactiveCommands<K, V>
         return createFlux(() -> commandBuilder.eval(script, type, keys, values));
     }
 
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> Flux<T> evalReadOnly(String script, ScriptOutputType type, K[] keys, V... values) {
+        return evalReadOnly(encodeScript(script), type, keys, values);
+    }
+
     @Override
     public <T> Flux<T> evalReadOnly(byte[] script, ScriptOutputType type, K[] keys, V... values) {
         return createFlux(() -> commandBuilder.eval(script, type, true, keys, values));
diff --git a/src/main/java/io/lettuce/core/api/async/RedisScriptingAsyncCommands.java b/src/main/java/io/lettuce/core/api/async/RedisScriptingAsyncCommands.java
index 1367b489f..0158e92f7 100644
--- a/src/main/java/io/lettuce/core/api/async/RedisScriptingAsyncCommands.java
+++ b/src/main/java/io/lettuce/core/api/async/RedisScriptingAsyncCommands.java
@@ -85,6 +85,19 @@ public interface RedisScriptingAsyncCommands<K, V> {
      */
     <T> RedisFuture<T> eval(byte[] script, ScriptOutputType type, K[] keys, V... values);
 
+    /**
+     * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
+     *
+     * @param script Lua 5.1 script.
+     * @param type the type.
+     * @param keys the keys.
+     * @param values the values.
+     * @param <T> expected return type.
+     * @return script result.
+     * @since 7.0
+     */
+    <T> RedisFuture<T> evalReadOnly(String script, ScriptOutputType type, K[] keys, V... values);
+
     /**
      * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
      *
diff --git a/src/main/java/io/lettuce/core/api/reactive/RedisScriptingReactiveCommands.java b/src/main/java/io/lettuce/core/api/reactive/RedisScriptingReactiveCommands.java
index 0272f0cda..1d9d7917c 100644
--- a/src/main/java/io/lettuce/core/api/reactive/RedisScriptingReactiveCommands.java
+++ b/src/main/java/io/lettuce/core/api/reactive/RedisScriptingReactiveCommands.java
@@ -84,6 +84,19 @@ public interface RedisScriptingReactiveCommands<K, V> {
      */
     <T> Flux<T> eval(byte[] script, ScriptOutputType type, K[] keys, V... values);
 
+    /**
+     * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
+     *
+     * @param script Lua 5.1 script.
+     * @param type the type.
+     * @param keys the keys.
+     * @param values the values.
+     * @param <T> expected return type.
+     * @return script result.
+     * @since 7.0
+     */
+    <T> Flux<T> evalReadOnly(String script, ScriptOutputType type, K[] keys, V... values);
+
     /**
      * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
      *
diff --git a/src/main/java/io/lettuce/core/api/sync/RedisScriptingCommands.java b/src/main/java/io/lettuce/core/api/sync/RedisScriptingCommands.java
index cc359cb42..d6161251e 100644
--- a/src/main/java/io/lettuce/core/api/sync/RedisScriptingCommands.java
+++ b/src/main/java/io/lettuce/core/api/sync/RedisScriptingCommands.java
@@ -84,6 +84,19 @@ public interface RedisScriptingCommands<K, V> {
      */
     <T> T eval(byte[] script, ScriptOutputType type, K[] keys, V... values);
 
+    /**
+     * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
+     *
+     * @param script Lua 5.1 script.
+     * @param type output type.
+     * @param keys the keys.
+     * @param values the values.
+     * @param <T> expected return type.
+     * @return script result.
+     * @since 7.0
+     */
+    <T> T evalReadOnly(String script, ScriptOutputType type, K[] keys, V... values);
+
     /**
      * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
      *
diff --git a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionScriptingAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionScriptingAsyncCommands.java
index e116ce20b..df0b55178 100644
--- a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionScriptingAsyncCommands.java
+++ b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionScriptingAsyncCommands.java
@@ -84,6 +84,19 @@ public interface NodeSelectionScriptingAsyncCommands<K, V> {
      */
     <T> AsyncExecutions<T> eval(byte[] script, ScriptOutputType type, K[] keys, V... values);
 
+    /**
+     * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
+     *
+     * @param script Lua 5.1 script.
+     * @param type the type.
+     * @param keys the keys.
+     * @param values the values.
+     * @param <T> expected return type.
+     * @return script result.
+     * @since 7.0
+     */
+    <T> AsyncExecutions<T> evalReadOnly(String script, ScriptOutputType type, K[] keys, V... values);
+
     /**
      * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
      *
diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionScriptingCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionScriptingCommands.java
index e1c230662..b7b40351b 100644
--- a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionScriptingCommands.java
+++ b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionScriptingCommands.java
@@ -84,6 +84,19 @@ public interface NodeSelectionScriptingCommands<K, V> {
      */
     <T> Executions<T> eval(byte[] script, ScriptOutputType type, K[] keys, V... values);
 
+    /**
+     * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
+     *
+     * @param script Lua 5.1 script.
+     * @param type the type.
+     * @param keys the keys.
+     * @param values the values.
+     * @param <T> expected return type.
+     * @return script result.
+     * @since 7.0
+     */
+    <T> Executions<T> evalReadOnly(String script, ScriptOutputType type, K[] keys, V... values);
+
     /**
      * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
      *
diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisScriptingCoroutinesCommands.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisScriptingCoroutinesCommands.kt
index 020ac1a87..711e7569b 100644
--- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisScriptingCoroutinesCommands.kt
+++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisScriptingCoroutinesCommands.kt
@@ -85,6 +85,24 @@ interface RedisScriptingCoroutinesCommands<K : Any, V : Any> {
      */
     suspend fun <T> eval(script: ByteArray, type: ScriptOutputType, keys: Array<K>, vararg values: V): T?
 
+    /**
+     * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
+     *
+     * @param script Lua 5.1 script.
+     * @param type the type.
+     * @param keys the keys.
+     * @param values the values.
+     * @param <T> expected return type.
+     * @return script result.
+     * @since 7.0
+     */
+    suspend fun <T> evalReadOnly(
+        script: String,
+        type: ScriptOutputType,
+        keys: Array<K>,
+        vararg values: V
+    ): T?
+
     /**
      * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
      *
@@ -214,4 +232,3 @@ interface RedisScriptingCoroutinesCommands<K : Any, V : Any> {
     suspend fun digest(script: ByteArray): String?
 
 }
-
diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisScriptingCoroutinesCommandsImpl.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisScriptingCoroutinesCommandsImpl.kt
index 403cb2616..30d0625b4 100644
--- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisScriptingCoroutinesCommandsImpl.kt
+++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisScriptingCoroutinesCommandsImpl.kt
@@ -51,6 +51,13 @@ internal class RedisScriptingCoroutinesCommandsImpl<K : Any, V : Any>(internal v
 
     override suspend fun <T> eval(script: ByteArray, type: ScriptOutputType, keys: Array<K>, vararg values: V): T? = ops.eval<T>(script, type, keys, *values).awaitFirstOrNull()
 
+    override suspend fun <T> evalReadOnly(
+        script: String,
+        type: ScriptOutputType,
+        keys: Array<K>,
+        vararg values: V
+    ): T? = ops.evalReadOnly<T>(script, type, keys, *values).awaitFirstOrNull()
+
     override suspend fun <T> evalReadOnly(
         script: ByteArray,
         type: ScriptOutputType,
@@ -86,4 +93,3 @@ internal class RedisScriptingCoroutinesCommandsImpl<K : Any, V : Any>(internal v
     override suspend fun digest(script: ByteArray): String = ops.digest(script)
 
 }
-
diff --git a/src/main/templates/io/lettuce/core/api/RedisScriptingCommands.java b/src/main/templates/io/lettuce/core/api/RedisScriptingCommands.java
index ed47b21ca..96e09c394 100644
--- a/src/main/templates/io/lettuce/core/api/RedisScriptingCommands.java
+++ b/src/main/templates/io/lettuce/core/api/RedisScriptingCommands.java
@@ -83,6 +83,19 @@ public interface RedisScriptingCommands<K, V> {
      */
     <T> T eval(byte[] script, ScriptOutputType type, K[] keys, V... values);
 
+    /**
+     * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
+     *
+     * @param script Lua 5.1 script.
+     * @param type the type.
+     * @param keys the keys.
+     * @param values the values.
+     * @param <T> expected return type.
+     * @return script result.
+     * @since 7.0
+     */
+    <T> T evalReadOnly(String script, ScriptOutputType type, K[] keys, V... values);
+
     /**
      * This is a read-only variant of the EVAL command that cannot execute commands that modify data.
      *


Test patch:
diff --git a/src/test/java/io/lettuce/core/commands/ScriptingCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/ScriptingCommandIntegrationTests.java
index 96cd29db3..1c7afd30e 100644
--- a/src/test/java/io/lettuce/core/commands/ScriptingCommandIntegrationTests.java
+++ b/src/test/java/io/lettuce/core/commands/ScriptingCommandIntegrationTests.java
@@ -134,7 +134,7 @@ public class ScriptingCommandIntegrationTests extends TestSupport {
     @EnabledOnCommand("EVAL_RO") // Redis 7.0
     void evalReadOnly() {
         String[] keys = new String[] { "key1" };
-        assertThat((String) redis.evalReadOnly("return KEYS[1]".getBytes(), STATUS, keys, "a")).isEqualTo("key1");
+        assertThat((String) redis.evalReadOnly("return KEYS[1]", STATUS, keys, "a")).isEqualTo("key1");
     }
 
     @Test