From a30addff30efb1f75c7cd0b92621150972509f0e Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 18 Oct 2023 15:52:17 +0200 Subject: [PATCH] Add support for Redis 7 functions #2185 Support for FCALL and FUNCTION commands. --- src/main/asciidoc/getting-started.asciidoc | 5 + src/main/asciidoc/new-features.adoc | 5 + .../asciidoc/scripting-and-functions.asciidoc | 4 + .../core/AbstractRedisAsyncCommands.java | 71 ++++++++ .../core/AbstractRedisReactiveCommands.java | 71 ++++++++ .../io/lettuce/core/FunctionRestoreMode.java | 57 ++++++ .../io/lettuce/core/RedisCommandBuilder.java | 67 +++++++ .../io/lettuce/core/ScriptOutputType.java | 34 +++- .../core/api/async/RedisAsyncCommands.java | 11 +- .../api/async/RedisFunctionAsyncCommands.java | 152 ++++++++++++++++ .../RedisFunctionReactiveCommands.java | 152 ++++++++++++++++ .../api/reactive/RedisReactiveCommands.java | 13 +- .../lettuce/core/api/sync/RedisCommands.java | 9 +- .../core/api/sync/RedisFunctionCommands.java | 151 ++++++++++++++++ .../core/api/sync/RedisScriptingCommands.java | 12 +- .../api/async/NodeSelectionAsyncCommands.java | 4 +- .../NodeSelectionFunctionAsyncCommands.java | 151 ++++++++++++++++ .../api/async/RedisClusterAsyncCommands.java | 5 +- .../RedisClusterReactiveCommands.java | 8 +- .../api/sync/NodeSelectionCommands.java | 10 +- .../sync/NodeSelectionFunctionCommands.java | 151 ++++++++++++++++ .../api/sync/RedisClusterCommands.java | 8 +- .../core/output/NestedMultiOutput.java | 2 +- .../protocol/BaseRedisCommandBuilder.java | 10 +- .../io/lettuce/core/protocol/CommandType.java | 4 + .../api/coroutines/RedisCoroutinesCommands.kt | 1 + .../coroutines/RedisCoroutinesCommandsImpl.kt | 1 + .../RedisFunctionCoroutinesCommands.kt | 170 ++++++++++++++++++ .../RedisFunctionCoroutinesCommandsImpl.kt | 92 ++++++++++ .../core/api/RedisFunctionCommands.java | 150 ++++++++++++++++ .../io/lettuce/apigenerator/Constants.java | 1 + .../apigenerator/CreateReactiveApi.java | 2 +- .../FunctionCommandIntegrationTests.java | 131 ++++++++++++++ .../ScriptingCommandIntegrationTests.java | 1 + ...nctionReactiveCommandIntegrationTests.java | 35 ++++ 35 files changed, 1709 insertions(+), 42 deletions(-) create mode 100644 src/main/asciidoc/scripting-and-functions.asciidoc create mode 100644 src/main/java/io/lettuce/core/FunctionRestoreMode.java create mode 100644 src/main/java/io/lettuce/core/api/async/RedisFunctionAsyncCommands.java create mode 100644 src/main/java/io/lettuce/core/api/reactive/RedisFunctionReactiveCommands.java create mode 100644 src/main/java/io/lettuce/core/api/sync/RedisFunctionCommands.java create mode 100644 src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionFunctionAsyncCommands.java create mode 100644 src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionFunctionCommands.java create mode 100644 src/main/kotlin/io/lettuce/core/api/coroutines/RedisFunctionCoroutinesCommands.kt create mode 100644 src/main/kotlin/io/lettuce/core/api/coroutines/RedisFunctionCoroutinesCommandsImpl.kt create mode 100644 src/main/templates/io/lettuce/core/api/RedisFunctionCommands.java create mode 100644 src/test/java/io/lettuce/core/commands/FunctionCommandIntegrationTests.java create mode 100644 src/test/java/io/lettuce/core/commands/reactive/FunctionReactiveCommandIntegrationTests.java diff --git a/src/main/asciidoc/getting-started.asciidoc b/src/main/asciidoc/getting-started.asciidoc index 2375310a75..54f166c867 100644 --- a/src/main/asciidoc/getting-started.asciidoc +++ b/src/main/asciidoc/getting-started.asciidoc @@ -41,3 +41,8 @@ include::{ext-doc}/Pub-Sub.asciidoc[leveloffset=+1] === Transactions/Multi include::{ext-doc}/Transactions.asciidoc[leveloffset=+1] + +[[scripting-and-functions]] +=== Scripting and Functions + +include::scripting-and-functions.asciidoc[] diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index ee78d9f246..e7c1207783 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -1,6 +1,11 @@ [[new-features]] = New & Noteworthy +[[new-features.6-3-0]] +== What's new in Lettuce 6.3 + +* <<_redis_functions,Redis Function support>> (`fcall` and `FUNCTION` commands). + [[new-features.6-2-0]] == What's new in Lettuce 6.2 diff --git a/src/main/asciidoc/scripting-and-functions.asciidoc b/src/main/asciidoc/scripting-and-functions.asciidoc new file mode 100644 index 0000000000..73c7f66345 --- /dev/null +++ b/src/main/asciidoc/scripting-and-functions.asciidoc @@ -0,0 +1,4 @@ +:command-interfaces-link: <> +[[redis-scripting-and-functions]] +include::{ext-doc}/Scripting-and-Functions.asciidoc[leveloffset=+2] + diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java index 16a48f25fb..4d25d9d9e5 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java @@ -826,6 +826,71 @@ public RedisFuture expiretime(K key) { return dispatch(commandBuilder.expiretime(key)); } + @Override + public RedisFuture fcall(String function, ScriptOutputType type, K... keys) { + return dispatch(commandBuilder.fcall(function, type, false, keys)); + } + + @Override + public RedisFuture fcall(String function, ScriptOutputType type, K[] keys, V... values) { + return dispatch(commandBuilder.fcall(function, type, false, keys, values)); + } + + @Override + public RedisFuture fcallReadOnly(String function, ScriptOutputType type, K... keys) { + return dispatch(commandBuilder.fcall(function, type, true, keys)); + } + + @Override + public RedisFuture fcallReadOnly(String function, ScriptOutputType type, K[] keys, V... values) { + return dispatch(commandBuilder.fcall(function, type, true, keys, values)); + } + + @Override + public RedisFuture functionLoad(String functionCode) { + return functionLoad(functionCode, false); + } + + @Override + public RedisFuture functionLoad(String functionCode, boolean replace) { + return dispatch(commandBuilder.functionLoad(encodeFunction(functionCode), replace)); + } + + @Override + public RedisFuture functionDump() { + return dispatch(commandBuilder.functionDump()); + } + + @Override + public RedisFuture functionRestore(byte[] dump) { + return functionRestore(dump, null); + } + + @Override + public RedisFuture functionRestore(byte[] dump, FunctionRestoreMode mode) { + return dispatch(commandBuilder.functionRestore(dump, mode)); + } + + @Override + public RedisFuture functionFlush(FlushMode flushMode) { + return dispatch(commandBuilder.functionFlush(flushMode)); + } + + @Override + public RedisFuture functionKill() { + return dispatch(commandBuilder.functionKill()); + } + + @Override + public RedisFuture>> functionList() { + return functionList(null); + } + + @Override + public RedisFuture>> functionList(String libraryName) { + return dispatch(commandBuilder.functionList(libraryName)); + } + @Override public void flushCommands() { connection.flushCommands(); @@ -2906,6 +2971,12 @@ public RedisFuture zunionstore(K destination, ZStoreArgs zStoreArgs, K... return dispatch(commandBuilder.zunionstore(destination, zStoreArgs, keys)); } + private byte[] encodeFunction(String functionCode) { + LettuceAssert.notNull(functionCode, "Function code must not be null"); + LettuceAssert.notEmpty(functionCode, "Function code script must not be empty"); + return functionCode.getBytes(getConnection().getOptions().getScriptCharset()); + } + private byte[] encodeScript(String script) { LettuceAssert.notNull(script, "Lua script must not be null"); LettuceAssert.notEmpty(script, "Lua script must not be empty"); diff --git a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java index 911cfc443e..8ac54d0908 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java @@ -886,6 +886,71 @@ public Mono expiretime(K key) { return createMono(() -> commandBuilder.expiretime(key)); } + @Override + public Flux fcall(String function, ScriptOutputType type, K... keys) { + return createFlux(() -> commandBuilder.fcall(function, type, false, keys)); + } + + @Override + public Flux fcall(String function, ScriptOutputType type, K[] keys, V... values) { + return createFlux(() -> commandBuilder.fcall(function, type, false, keys, values)); + } + + @Override + public Flux fcallReadOnly(String function, ScriptOutputType type, K... keys) { + return createFlux(() -> commandBuilder.fcall(function, type, true, keys)); + } + + @Override + public Flux fcallReadOnly(String function, ScriptOutputType type, K[] keys, V... values) { + return createFlux(() -> commandBuilder.fcall(function, type, true, keys, values)); + } + + @Override + public Mono functionLoad(String functionCode) { + return functionLoad(functionCode, false); + } + + @Override + public Mono functionLoad(String functionCode, boolean replace) { + return createMono(() -> commandBuilder.functionLoad(encodeScript(functionCode), replace)); + } + + @Override + public Mono functionDump() { + return createMono(commandBuilder::functionDump); + } + + @Override + public Mono functionRestore(byte[] dump) { + return createMono(() -> commandBuilder.functionRestore(dump, null)); + } + + @Override + public Mono functionRestore(byte[] dump, FunctionRestoreMode mode) { + return createMono(() -> commandBuilder.functionRestore(dump, mode)); + } + + @Override + public Mono functionFlush(FlushMode flushMode) { + return createMono(() -> commandBuilder.functionFlush(flushMode)); + } + + @Override + public Mono functionKill() { + return createMono(commandBuilder::functionKill); + } + + @Override + public Flux> functionList() { + return createDissolvingFlux(() -> commandBuilder.functionList(null)); + } + + @Override + public Flux> functionList(String libraryName) { + return createDissolvingFlux(() -> commandBuilder.functionList(libraryName)); + } + @Override public void flushCommands() { connection.flushCommands(); @@ -2975,6 +3040,12 @@ public Mono zunionstore(K destination, ZStoreArgs zStoreArgs, K... keys) { return createMono(() -> commandBuilder.zunionstore(destination, zStoreArgs, keys)); } + private byte[] encodeFunction(String functionCode) { + LettuceAssert.notNull(functionCode, "Function code must not be null"); + LettuceAssert.notEmpty(functionCode, "Function code script must not be empty"); + return functionCode.getBytes(getConnection().getOptions().getScriptCharset()); + } + private byte[] encodeScript(String script) { LettuceAssert.notNull(script, "Lua script must not be null"); LettuceAssert.notEmpty(script, "Lua script must not be empty"); diff --git a/src/main/java/io/lettuce/core/FunctionRestoreMode.java b/src/main/java/io/lettuce/core/FunctionRestoreMode.java new file mode 100644 index 0000000000..e26401faaf --- /dev/null +++ b/src/main/java/io/lettuce/core/FunctionRestoreMode.java @@ -0,0 +1,57 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.lettuce.core; + +import java.nio.charset.StandardCharsets; + +import io.lettuce.core.protocol.ProtocolKeyword; + +/** + * Restore mode for {@code FUNCTION RESTORE}. + * + * @author Mark Paluch + * @since 6.3 + */ +public enum FunctionRestoreMode implements ProtocolKeyword { + + /** + * Appends the restored libraries to the existing libraries and aborts on collision. This is the default policy. + */ + APPEND, + + /** + * Deletes all existing libraries before restoring the payload. + */ + FLUSH, + + /** + * Appends the restored libraries to the existing libraries, replacing any existing ones in case of name collisions. Note + * that this policy doesn't prevent function name collisions, only libraries. + */ + REPLACE; + + public final byte[] bytes; + + FunctionRestoreMode() { + bytes = name().getBytes(StandardCharsets.US_ASCII); + } + + @Override + public byte[] getBytes() { + return bytes; + } + +} diff --git a/src/main/java/io/lettuce/core/RedisCommandBuilder.java b/src/main/java/io/lettuce/core/RedisCommandBuilder.java index 5fe86772a4..599b47e6c2 100644 --- a/src/main/java/io/lettuce/core/RedisCommandBuilder.java +++ b/src/main/java/io/lettuce/core/RedisCommandBuilder.java @@ -1011,6 +1011,73 @@ Command flushdb(FlushMode flushMode) { return createCommand(FLUSHDB, new StatusOutput<>(codec), new CommandArgs<>(codec).add(flushMode)); } + Command fcall(String function, ScriptOutputType type, boolean readonly, K[] keys, V... values) { + LettuceAssert.notEmpty(function, "Function " + MUST_NOT_BE_EMPTY); + LettuceAssert.notNull(type, "ScriptOutputType " + MUST_NOT_BE_NULL); + LettuceAssert.notNull(keys, "Keys " + MUST_NOT_BE_NULL); + LettuceAssert.notNull(values, "Values " + MUST_NOT_BE_NULL); + + CommandArgs args = new CommandArgs<>(codec); + args.add(function).add(keys.length).addKeys(keys).addValues(values); + CommandOutput output = newScriptOutput(codec, type); + + return createCommand(readonly ? FCALL_RO : FCALL, output, args); + } + + Command functionLoad(byte[] functionCode, boolean replace) { + LettuceAssert.notNull(functionCode, "Function code " + MUST_NOT_BE_NULL); + + CommandArgs args = new CommandArgs<>(codec).add(LOAD); + if (replace) { + args.add(REPLACE); + } + args.add(functionCode); + + return createCommand(FUNCTION, new StatusOutput<>(codec), args); + } + + Command functionDump() { + return createCommand(FUNCTION, new ByteArrayOutput<>(codec), new CommandArgs<>(codec).add(DUMP)); + } + + Command functionRestore(byte dump[], FunctionRestoreMode mode) { + + LettuceAssert.notNull(dump, "Function dump " + MUST_NOT_BE_NULL); + CommandArgs args = new CommandArgs<>(codec).add(RESTORE).add(dump); + + if (mode != null) { + args.add(mode); + } + + return createCommand(FUNCTION, new StatusOutput<>(codec), args); + } + + Command functionFlush(FlushMode mode) { + + CommandArgs args = new CommandArgs<>(codec).add(FLUSH); + + if (mode != null) { + args.add(mode); + } + + return createCommand(FUNCTION, new StatusOutput<>(codec), args); + } + + Command functionKill() { + return createCommand(FUNCTION, new StatusOutput<>(codec), new CommandArgs<>(codec).add(KILL)); + } + + Command>> functionList(String pattern) { + + CommandArgs args = new CommandArgs<>(codec).add(LIST); + + if (pattern != null) { + args.add("LIBRARYNAME").add(pattern); + } + + return createCommand(FUNCTION, (CommandOutput) new ObjectOutput<>(StringCodec.UTF8), args); + } + Command geoadd(K key, double longitude, double latitude, V member, GeoAddArgs geoArgs) { notNullKey(key); diff --git a/src/main/java/io/lettuce/core/ScriptOutputType.java b/src/main/java/io/lettuce/core/ScriptOutputType.java index b857b29ebc..dc3f8a5385 100644 --- a/src/main/java/io/lettuce/core/ScriptOutputType.java +++ b/src/main/java/io/lettuce/core/ScriptOutputType.java @@ -15,6 +15,8 @@ */ package io.lettuce.core; +import java.nio.ByteBuffer; + /** * A Lua script returns one of the following types: * @@ -24,6 +26,7 @@ *
  • {@link #STATUS} status string
  • *
  • {@link #VALUE} value
  • *
  • {@link #MULTI} of these types
  • + *
  • {@link #OBJECT} result object defined by the RESP3 response
  • * * * Redis to Lua conversion table. @@ -49,5 +52,34 @@ * @author Will Glozer */ public enum ScriptOutputType { - BOOLEAN, INTEGER, MULTI, STATUS, VALUE + + /** + * Boolean output (expects a number {@code 0} or {@code 1} to be converted to a boolean value). + */ + BOOLEAN, + + /** + * {@link Long integer} output. + */ + INTEGER, + + /** + * List of flat arrays. + */ + MULTI, + + /** + * Simple status value such as {@code OK}. The Redis response is parsed as ASCII. + */ + STATUS, + + /** + * Value return type decoded through {@link io.lettuce.core.codec.RedisCodec#decodeValue(ByteBuffer)}. + */ + VALUE, + + /** + * RESP3-defined object output supporting all Redis response structures. + */ + OBJECT } diff --git a/src/main/java/io/lettuce/core/api/async/RedisAsyncCommands.java b/src/main/java/io/lettuce/core/api/async/RedisAsyncCommands.java index 8f2560eedc..f7686bdf62 100644 --- a/src/main/java/io/lettuce/core/api/async/RedisAsyncCommands.java +++ b/src/main/java/io/lettuce/core/api/async/RedisAsyncCommands.java @@ -27,11 +27,12 @@ * @author Mark Paluch * @since 3.0 */ -public interface RedisAsyncCommands extends BaseRedisAsyncCommands, RedisAclAsyncCommands, RedisClusterAsyncCommands, - RedisGeoAsyncCommands, RedisHashAsyncCommands, RedisHLLAsyncCommands, RedisKeyAsyncCommands, - RedisListAsyncCommands, RedisScriptingAsyncCommands, RedisServerAsyncCommands, - RedisSetAsyncCommands, RedisSortedSetAsyncCommands, RedisStreamAsyncCommands, - RedisStringAsyncCommands, RedisTransactionalAsyncCommands { +public interface RedisAsyncCommands extends BaseRedisAsyncCommands, RedisAclAsyncCommands, + RedisClusterAsyncCommands, RedisFunctionAsyncCommands, RedisGeoAsyncCommands, + RedisHashAsyncCommands, RedisHLLAsyncCommands, RedisKeyAsyncCommands, RedisListAsyncCommands, + RedisScriptingAsyncCommands, RedisServerAsyncCommands, RedisSetAsyncCommands, + RedisSortedSetAsyncCommands, RedisStreamAsyncCommands, RedisStringAsyncCommands, + RedisTransactionalAsyncCommands { /** * Authenticate to the server. diff --git a/src/main/java/io/lettuce/core/api/async/RedisFunctionAsyncCommands.java b/src/main/java/io/lettuce/core/api/async/RedisFunctionAsyncCommands.java new file mode 100644 index 0000000000..8ac5b2538d --- /dev/null +++ b/src/main/java/io/lettuce/core/api/async/RedisFunctionAsyncCommands.java @@ -0,0 +1,152 @@ +/* + * Copyright 2017-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.lettuce.core.api.async; + +import java.util.List; +import java.util.Map; + +import io.lettuce.core.FlushMode; +import io.lettuce.core.FunctionRestoreMode; +import io.lettuce.core.RedisFuture; +import io.lettuce.core.ScriptOutputType; + +/** + * Asynchronous executed commands for Redis Functions. {@link java.lang.String Function code} is encoded by using the configured + * {@link io.lettuce.core.ClientOptions#getScriptCharset() charset}. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 6.3 + * @generated by io.lettuce.apigenerator.CreateAsyncApi + */ +public interface RedisFunctionAsyncCommands { + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + RedisFuture fcall(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + RedisFuture fcall(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + RedisFuture fcallReadOnly(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + RedisFuture fcallReadOnly(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @return name of the library. + */ + RedisFuture functionLoad(String functionCode); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @param replace whether to replace an existing function. + * @return name of the library. + */ + RedisFuture functionLoad(String functionCode, boolean replace); + + /** + * Return the serialized payload of loaded libraries. You can restore the dump through {@link #functionRestore(byte[])}. + * + * @return the serialized payload. + */ + RedisFuture functionDump(); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + RedisFuture functionRestore(byte[] dump); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + RedisFuture functionRestore(byte[] dump, FunctionRestoreMode mode); + + /** + * Deletes all the libraries using the specified {@link FlushMode}. + * + * @param flushMode the flush mode (sync/async). + * @return String simple-string-reply. + */ + RedisFuture functionFlush(FlushMode flushMode); + + /** + * Kill a function that is currently executing. + * + * @return String simple-string-reply. + */ + RedisFuture functionKill(); + + /** + * Return information about the functions and libraries. + * + * @return Array reply. + */ + RedisFuture>> functionList(); + + /** + * Return information about the functions and libraries. + * + * @param libraryName specify a pattern for matching library names. + * @return Array reply. + */ + RedisFuture>> functionList(String libraryName); + +} diff --git a/src/main/java/io/lettuce/core/api/reactive/RedisFunctionReactiveCommands.java b/src/main/java/io/lettuce/core/api/reactive/RedisFunctionReactiveCommands.java new file mode 100644 index 0000000000..c90ed800f7 --- /dev/null +++ b/src/main/java/io/lettuce/core/api/reactive/RedisFunctionReactiveCommands.java @@ -0,0 +1,152 @@ +/* + * Copyright 2017-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.lettuce.core.api.reactive; + +import java.util.Map; + +import io.lettuce.core.FlushMode; +import io.lettuce.core.FunctionRestoreMode; +import io.lettuce.core.ScriptOutputType; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * Reactive executed commands for Redis Functions. {@link java.lang.String Function code} is encoded by using the configured + * {@link io.lettuce.core.ClientOptions#getScriptCharset() charset}. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 6.3 + * @generated by io.lettuce.apigenerator.CreateReactiveApi + */ +public interface RedisFunctionReactiveCommands { + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + Flux fcall(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + Flux fcall(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + Flux fcallReadOnly(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + Flux fcallReadOnly(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @return name of the library. + */ + Mono functionLoad(String functionCode); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @param replace whether to replace an existing function. + * @return name of the library. + */ + Mono functionLoad(String functionCode, boolean replace); + + /** + * Return the serialized payload of loaded libraries. You can restore the dump through {@link #functionRestore(byte[])}. + * + * @return the serialized payload. + */ + Mono functionDump(); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + Mono functionRestore(byte[] dump); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + Mono functionRestore(byte[] dump, FunctionRestoreMode mode); + + /** + * Deletes all the libraries using the specified {@link FlushMode}. + * + * @param flushMode the flush mode (sync/async). + * @return String simple-string-reply. + */ + Mono functionFlush(FlushMode flushMode); + + /** + * Kill a function that is currently executing. + * + * @return String simple-string-reply. + */ + Mono functionKill(); + + /** + * Return information about the functions and libraries. + * + * @return Array reply. + */ + Flux> functionList(); + + /** + * Return information about the functions and libraries. + * + * @param libraryName specify a pattern for matching library names. + * @return Array reply. + */ + Flux> functionList(String libraryName); + +} diff --git a/src/main/java/io/lettuce/core/api/reactive/RedisReactiveCommands.java b/src/main/java/io/lettuce/core/api/reactive/RedisReactiveCommands.java index f5d2f66858..6a62c758cc 100644 --- a/src/main/java/io/lettuce/core/api/reactive/RedisReactiveCommands.java +++ b/src/main/java/io/lettuce/core/api/reactive/RedisReactiveCommands.java @@ -15,9 +15,9 @@ */ package io.lettuce.core.api.reactive; -import reactor.core.publisher.Mono; import io.lettuce.core.api.StatefulRedisConnection; import io.lettuce.core.cluster.api.reactive.RedisClusterReactiveCommands; +import reactor.core.publisher.Mono; /** * A complete reactive and thread-safe Redis API with 400+ Methods. @@ -27,11 +27,12 @@ * @author Mark Paluch * @since 5.0 */ -public interface RedisReactiveCommands extends BaseRedisReactiveCommands, RedisAclReactiveCommands, RedisClusterReactiveCommands, - RedisGeoReactiveCommands, RedisHashReactiveCommands, RedisHLLReactiveCommands, - RedisKeyReactiveCommands, RedisListReactiveCommands, RedisScriptingReactiveCommands, - RedisServerReactiveCommands, RedisSetReactiveCommands, RedisSortedSetReactiveCommands, - RedisStreamReactiveCommands, RedisStringReactiveCommands, RedisTransactionalReactiveCommands { +public interface RedisReactiveCommands extends BaseRedisReactiveCommands, RedisAclReactiveCommands, + RedisClusterReactiveCommands, RedisFunctionReactiveCommands, RedisGeoReactiveCommands, + RedisHashReactiveCommands, RedisHLLReactiveCommands, RedisKeyReactiveCommands, + RedisListReactiveCommands, RedisScriptingReactiveCommands, RedisServerReactiveCommands, + RedisSetReactiveCommands, RedisSortedSetReactiveCommands, RedisStreamReactiveCommands, + RedisStringReactiveCommands, RedisTransactionalReactiveCommands { /** * Authenticate to the server. diff --git a/src/main/java/io/lettuce/core/api/sync/RedisCommands.java b/src/main/java/io/lettuce/core/api/sync/RedisCommands.java index f261d6a2f6..a744f7de52 100644 --- a/src/main/java/io/lettuce/core/api/sync/RedisCommands.java +++ b/src/main/java/io/lettuce/core/api/sync/RedisCommands.java @@ -27,10 +27,11 @@ * @author Mark Paluch * @since 3.0 */ -public interface RedisCommands extends BaseRedisCommands, RedisAclCommands, RedisClusterCommands, RedisGeoCommands, - RedisHashCommands, RedisHLLCommands, RedisKeyCommands, RedisListCommands, - RedisScriptingCommands, RedisServerCommands, RedisSetCommands, RedisSortedSetCommands, - RedisStreamCommands, RedisStringCommands, RedisTransactionalCommands { +public interface RedisCommands + extends BaseRedisCommands, RedisAclCommands, RedisClusterCommands, RedisFunctionCommands, + RedisGeoCommands, RedisHashCommands, RedisHLLCommands, RedisKeyCommands, + RedisListCommands, RedisScriptingCommands, RedisServerCommands, RedisSetCommands, + RedisSortedSetCommands, RedisStreamCommands, RedisStringCommands, RedisTransactionalCommands { /** * Authenticate to the server. diff --git a/src/main/java/io/lettuce/core/api/sync/RedisFunctionCommands.java b/src/main/java/io/lettuce/core/api/sync/RedisFunctionCommands.java new file mode 100644 index 0000000000..6310b4ad87 --- /dev/null +++ b/src/main/java/io/lettuce/core/api/sync/RedisFunctionCommands.java @@ -0,0 +1,151 @@ +/* + * Copyright 2017-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.lettuce.core.api.sync; + +import java.util.List; +import java.util.Map; + +import io.lettuce.core.FlushMode; +import io.lettuce.core.FunctionRestoreMode; +import io.lettuce.core.ScriptOutputType; + +/** + * Synchronous executed commands for Redis Functions. {@link java.lang.String Function code} is encoded by using the configured + * {@link io.lettuce.core.ClientOptions#getScriptCharset() charset}. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 6.3 + * @generated by io.lettuce.apigenerator.CreateSyncApi + */ +public interface RedisFunctionCommands { + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + T fcall(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + T fcall(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + T fcallReadOnly(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + T fcallReadOnly(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @return name of the library. + */ + String functionLoad(String functionCode); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @param replace whether to replace an existing function. + * @return name of the library. + */ + String functionLoad(String functionCode, boolean replace); + + /** + * Return the serialized payload of loaded libraries. You can restore the dump through {@link #functionRestore(byte[])}. + * + * @return the serialized payload. + */ + byte[] functionDump(); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + String functionRestore(byte[] dump); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + String functionRestore(byte[] dump, FunctionRestoreMode mode); + + /** + * Deletes all the libraries using the specified {@link FlushMode}. + * + * @param flushMode the flush mode (sync/async). + * @return String simple-string-reply. + */ + String functionFlush(FlushMode flushMode); + + /** + * Kill a function that is currently executing. + * + * @return String simple-string-reply. + */ + String functionKill(); + + /** + * Return information about the functions and libraries. + * + * @return Array reply. + */ + List> functionList(); + + /** + * Return information about the functions and libraries. + * + * @param libraryName specify a pattern for matching library names. + * @return Array reply. + */ + List> functionList(String libraryName); + +} 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 a0fb95e25d..9c6bbf6709 100644 --- a/src/main/java/io/lettuce/core/api/sync/RedisScriptingCommands.java +++ b/src/main/java/io/lettuce/core/api/sync/RedisScriptingCommands.java @@ -59,7 +59,7 @@ public interface RedisScriptingCommands { * Execute a Lua script server side. * * @param script Lua 5.1 script. - * @param type the type. + * @param type output type. * @param keys the keys. * @param values the values. * @param expected return type. @@ -71,7 +71,7 @@ public interface RedisScriptingCommands { * Execute a Lua script server side. * * @param script Lua 5.1 script. - * @param type the type. + * @param type output type. * @param keys the keys. * @param values the values. * @param expected return type. @@ -84,7 +84,7 @@ public interface RedisScriptingCommands { * 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 type output type. * @param keys the keys. * @param values the values. * @param expected return type. @@ -97,7 +97,7 @@ public interface RedisScriptingCommands { * Evaluates a script cached on the server side by its SHA1 digest. * * @param digest SHA1 of the script. - * @param type the type. + * @param type output type. * @param keys the keys. * @param expected return type. * @return script result. @@ -108,7 +108,7 @@ public interface RedisScriptingCommands { * Execute a Lua script server side. * * @param digest SHA1 of the script. - * @param type the type. + * @param type output type. * @param keys the keys. * @param values the values. * @param expected return type. @@ -120,7 +120,7 @@ public interface RedisScriptingCommands { * This is a read-only variant of the EVALSHA command that cannot execute commands that modify data. * * @param digest SHA1 of the script. - * @param type the type. + * @param type output type. * @param keys the keys. * @param values the values. * @param expected return type. diff --git a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionAsyncCommands.java index 62f2edee10..7feb2ff2fc 100644 --- a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionAsyncCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionAsyncCommands.java @@ -23,8 +23,8 @@ * * @author Mark Paluch */ -public interface NodeSelectionAsyncCommands - extends BaseNodeSelectionAsyncCommands, NodeSelectionGeoAsyncCommands, NodeSelectionHashAsyncCommands, +public interface NodeSelectionAsyncCommands extends BaseNodeSelectionAsyncCommands, + NodeSelectionFunctionAsyncCommands, NodeSelectionGeoAsyncCommands, NodeSelectionHashAsyncCommands, NodeSelectionHLLAsyncCommands, NodeSelectionKeyAsyncCommands, NodeSelectionListAsyncCommands, NodeSelectionScriptingAsyncCommands, NodeSelectionServerAsyncCommands, NodeSelectionSetAsyncCommands, NodeSelectionSortedSetAsyncCommands, NodeSelectionStreamCommands, NodeSelectionStringAsyncCommands { diff --git a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionFunctionAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionFunctionAsyncCommands.java new file mode 100644 index 0000000000..b7cb9ca8e2 --- /dev/null +++ b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionFunctionAsyncCommands.java @@ -0,0 +1,151 @@ +/* + * Copyright 2017-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.lettuce.core.cluster.api.async; + +import java.util.List; +import java.util.Map; + +import io.lettuce.core.FlushMode; +import io.lettuce.core.FunctionRestoreMode; +import io.lettuce.core.ScriptOutputType; + +/** + * Asynchronous executed commands on a node selection for Redis Functions. {@link java.lang.String Function code} is encoded by + * using the configured {@link io.lettuce.core.ClientOptions#getScriptCharset() charset}. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 6.3 + * @generated by io.lettuce.apigenerator.CreateAsyncNodeSelectionClusterApi + */ +public interface NodeSelectionFunctionAsyncCommands { + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + AsyncExecutions fcall(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + AsyncExecutions fcall(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + AsyncExecutions fcallReadOnly(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + AsyncExecutions fcallReadOnly(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @return name of the library. + */ + AsyncExecutions functionLoad(String functionCode); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @param replace whether to replace an existing function. + * @return name of the library. + */ + AsyncExecutions functionLoad(String functionCode, boolean replace); + + /** + * Return the serialized payload of loaded libraries. You can restore the dump through {@link #functionRestore(byte[])}. + * + * @return the serialized payload. + */ + AsyncExecutions functionDump(); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + AsyncExecutions functionRestore(byte[] dump); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + AsyncExecutions functionRestore(byte[] dump, FunctionRestoreMode mode); + + /** + * Deletes all the libraries using the specified {@link FlushMode}. + * + * @param flushMode the flush mode (sync/async). + * @return String simple-string-reply. + */ + AsyncExecutions functionFlush(FlushMode flushMode); + + /** + * Kill a function that is currently executing. + * + * @return String simple-string-reply. + */ + AsyncExecutions functionKill(); + + /** + * Return information about the functions and libraries. + * + * @return Array reply. + */ + AsyncExecutions>> functionList(); + + /** + * Return information about the functions and libraries. + * + * @param libraryName specify a pattern for matching library names. + * @return Array reply. + */ + AsyncExecutions>> functionList(String libraryName); + +} diff --git a/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java index 3bec4011ec..c1b9265d06 100644 --- a/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/async/RedisClusterAsyncCommands.java @@ -32,8 +32,9 @@ * @author dengliming * @since 4.0 */ -public interface RedisClusterAsyncCommands extends BaseRedisAsyncCommands, RedisAclAsyncCommands, RedisGeoAsyncCommands, - RedisHashAsyncCommands, RedisHLLAsyncCommands, RedisKeyAsyncCommands, RedisListAsyncCommands, +public interface RedisClusterAsyncCommands extends BaseRedisAsyncCommands, RedisAclAsyncCommands, + RedisFunctionAsyncCommands, RedisGeoAsyncCommands, RedisHashAsyncCommands, + RedisHLLAsyncCommands, RedisKeyAsyncCommands, RedisListAsyncCommands, RedisScriptingAsyncCommands, RedisServerAsyncCommands, RedisSetAsyncCommands, RedisSortedSetAsyncCommands, RedisStreamAsyncCommands, RedisStringAsyncCommands { diff --git a/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java b/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java index 4558044d8c..48612761f2 100644 --- a/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/reactive/RedisClusterReactiveCommands.java @@ -33,10 +33,10 @@ * @since 5.0 */ public interface RedisClusterReactiveCommands extends BaseRedisReactiveCommands, RedisAclReactiveCommands, - RedisGeoReactiveCommands, RedisHashReactiveCommands, RedisHLLReactiveCommands, - RedisKeyReactiveCommands, RedisListReactiveCommands, RedisScriptingReactiveCommands, - RedisServerReactiveCommands, RedisSetReactiveCommands, RedisSortedSetReactiveCommands, - RedisStreamReactiveCommands, RedisStringReactiveCommands { + RedisFunctionReactiveCommands, RedisGeoReactiveCommands, RedisHashReactiveCommands, + RedisHLLReactiveCommands, RedisKeyReactiveCommands, RedisListReactiveCommands, + RedisScriptingReactiveCommands, RedisServerReactiveCommands, RedisSetReactiveCommands, + RedisSortedSetReactiveCommands, RedisStreamReactiveCommands, RedisStringReactiveCommands { /** * Set the default timeout for operations. A zero timeout value indicates to not time out. diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionCommands.java index 2783d7fd1b..dedaba9c58 100644 --- a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionCommands.java @@ -22,9 +22,9 @@ * * @author Mark Paluch */ -public interface NodeSelectionCommands - extends BaseNodeSelectionCommands, NodeSelectionGeoCommands, NodeSelectionHashCommands, - NodeSelectionHLLCommands, NodeSelectionKeyCommands, NodeSelectionListCommands, - NodeSelectionScriptingCommands, NodeSelectionServerCommands, NodeSelectionSetCommands, - NodeSelectionSortedSetCommands, NodeSelectionStreamCommands, NodeSelectionStringCommands { +public interface NodeSelectionCommands extends BaseNodeSelectionCommands, NodeSelectionFunctionCommands, + NodeSelectionGeoCommands, NodeSelectionHashCommands, NodeSelectionHLLCommands, + NodeSelectionKeyCommands, NodeSelectionListCommands, NodeSelectionScriptingCommands, + NodeSelectionServerCommands, NodeSelectionSetCommands, NodeSelectionSortedSetCommands, + NodeSelectionStreamCommands, NodeSelectionStringCommands { } diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionFunctionCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionFunctionCommands.java new file mode 100644 index 0000000000..f1c10716d8 --- /dev/null +++ b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionFunctionCommands.java @@ -0,0 +1,151 @@ +/* + * Copyright 2017-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.lettuce.core.cluster.api.sync; + +import java.util.List; +import java.util.Map; + +import io.lettuce.core.FlushMode; +import io.lettuce.core.FunctionRestoreMode; +import io.lettuce.core.ScriptOutputType; + +/** + * Synchronous executed commands on a node selection for Redis Functions. {@link java.lang.String Function code} is encoded by + * using the configured {@link io.lettuce.core.ClientOptions#getScriptCharset() charset}. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 6.3 + * @generated by io.lettuce.apigenerator.CreateSyncNodeSelectionClusterApi + */ +public interface NodeSelectionFunctionCommands { + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + Executions fcall(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + Executions fcall(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + Executions fcallReadOnly(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + Executions fcallReadOnly(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @return name of the library. + */ + Executions functionLoad(String functionCode); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @param replace whether to replace an existing function. + * @return name of the library. + */ + Executions functionLoad(String functionCode, boolean replace); + + /** + * Return the serialized payload of loaded libraries. You can restore the dump through {@link #functionRestore(byte[])}. + * + * @return the serialized payload. + */ + Executions functionDump(); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + Executions functionRestore(byte[] dump); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + Executions functionRestore(byte[] dump, FunctionRestoreMode mode); + + /** + * Deletes all the libraries using the specified {@link FlushMode}. + * + * @param flushMode the flush mode (sync/async). + * @return String simple-string-reply. + */ + Executions functionFlush(FlushMode flushMode); + + /** + * Kill a function that is currently executing. + * + * @return String simple-string-reply. + */ + Executions functionKill(); + + /** + * Return information about the functions and libraries. + * + * @return Array reply. + */ + Executions>> functionList(); + + /** + * Return information about the functions and libraries. + * + * @param libraryName specify a pattern for matching library names. + * @return Array reply. + */ + Executions>> functionList(String libraryName); + +} diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java index 9dc74c61bd..c8ced35d9a 100644 --- a/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/sync/RedisClusterCommands.java @@ -30,10 +30,10 @@ * @author dengliming * @since 4.0 */ -public interface RedisClusterCommands extends BaseRedisCommands, RedisAclCommands, RedisGeoCommands, - RedisHashCommands, RedisHLLCommands, RedisKeyCommands, RedisListCommands, - RedisScriptingCommands, RedisServerCommands, RedisSetCommands, RedisSortedSetCommands, - RedisStreamCommands, RedisStringCommands { +public interface RedisClusterCommands extends BaseRedisCommands, RedisAclCommands, + RedisFunctionCommands, RedisGeoCommands, RedisHashCommands, RedisHLLCommands, + RedisKeyCommands, RedisListCommands, RedisScriptingCommands, RedisServerCommands, + RedisSetCommands, RedisSortedSetCommands, RedisStreamCommands, RedisStringCommands { /** * Set the default timeout for operations. A zero timeout value indicates to not time out. diff --git a/src/main/java/io/lettuce/core/output/NestedMultiOutput.java b/src/main/java/io/lettuce/core/output/NestedMultiOutput.java index b58786f968..d1ebffe887 100644 --- a/src/main/java/io/lettuce/core/output/NestedMultiOutput.java +++ b/src/main/java/io/lettuce/core/output/NestedMultiOutput.java @@ -26,7 +26,7 @@ import io.lettuce.core.internal.LettuceFactories; /** - * {@link List} of command outputs, possibly deeply nested. Decodes simple strings through {@link StringCodec#UTF8}. + * {@link List} of flat arrays, possibly deeply nested. Decodes simple strings through {@link StringCodec#UTF8}. * * @param Key type. * @param Value type. diff --git a/src/main/java/io/lettuce/core/protocol/BaseRedisCommandBuilder.java b/src/main/java/io/lettuce/core/protocol/BaseRedisCommandBuilder.java index 481e336197..02d46d6289 100644 --- a/src/main/java/io/lettuce/core/protocol/BaseRedisCommandBuilder.java +++ b/src/main/java/io/lettuce/core/protocol/BaseRedisCommandBuilder.java @@ -18,7 +18,13 @@ import io.lettuce.core.RedisException; import io.lettuce.core.ScriptOutputType; import io.lettuce.core.codec.RedisCodec; -import io.lettuce.core.output.*; +import io.lettuce.core.output.BooleanOutput; +import io.lettuce.core.output.CommandOutput; +import io.lettuce.core.output.IntegerOutput; +import io.lettuce.core.output.NestedMultiOutput; +import io.lettuce.core.output.ObjectOutput; +import io.lettuce.core.output.StatusOutput; +import io.lettuce.core.output.ValueOutput; /** * @author Mark Paluch @@ -68,6 +74,8 @@ protected CommandOutput newScriptOutput(RedisCodec codec, Scr return (CommandOutput) new NestedMultiOutput<>(codec); case VALUE: return (CommandOutput) new ValueOutput<>(codec); + case OBJECT: + return (CommandOutput) new ObjectOutput<>(codec); default: throw new RedisException("Unsupported script output type"); } diff --git a/src/main/java/io/lettuce/core/protocol/CommandType.java b/src/main/java/io/lettuce/core/protocol/CommandType.java index b9c49bff53..79992f39ec 100644 --- a/src/main/java/io/lettuce/core/protocol/CommandType.java +++ b/src/main/java/io/lettuce/core/protocol/CommandType.java @@ -80,6 +80,10 @@ public enum CommandType implements ProtocolKeyword { BZMPOP, BZPOPMIN, BZPOPMAX, ZADD, ZCARD, ZCOUNT, ZDIFF, ZDIFFSTORE, ZINCRBY, ZINTER, ZINTERCARD, ZINTERSTORE, ZLEXCOUNT, ZMSCORE, ZMPOP, ZPOPMIN, ZPOPMAX, ZRANDMEMBER, ZRANGE, ZRANGEBYSCORE, ZRANGESTORE, ZRANK, ZREM, ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZREVRANGE, ZREVRANGEBYLEX, ZREVRANGEBYSCORE, ZREVRANK, ZSCAN, ZSCORE, ZUNION, ZUNIONSTORE, ZREMRANGEBYLEX, ZRANGEBYLEX, + // Functions + + FCALL, FCALL_RO, FUNCTION, + // Scripting EVAL, EVAL_RO, EVALSHA, EVALSHA_RO, SCRIPT, diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisCoroutinesCommands.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisCoroutinesCommands.kt index 07deba933b..b49a2de9bf 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisCoroutinesCommands.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisCoroutinesCommands.kt @@ -30,6 +30,7 @@ import io.lettuce.core.cluster.api.coroutines.RedisClusterCoroutinesCommands interface RedisCoroutinesCommands : BaseRedisCoroutinesCommands, RedisAclCoroutinesCommands, + RedisFunctionCoroutinesCommands, RedisGeoCoroutinesCommands, RedisHashCoroutinesCommands, RedisHLLCoroutinesCommands, diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisCoroutinesCommandsImpl.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisCoroutinesCommandsImpl.kt index 4b3e444fe7..bbdbcb6392 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisCoroutinesCommandsImpl.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisCoroutinesCommandsImpl.kt @@ -37,6 +37,7 @@ open class RedisCoroutinesCommandsImpl( ) : RedisCoroutinesCommands, RedisClusterCoroutinesCommands, BaseRedisCoroutinesCommands by BaseRedisCoroutinesCommandsImpl(ops), RedisAclCoroutinesCommands by RedisAclCoroutinesCommandsImpl(ops), + RedisFunctionCoroutinesCommands by RedisFunctionCoroutinesCommandsImpl(ops), RedisGeoCoroutinesCommands by RedisGeoCoroutinesCommandsImpl(ops), RedisHashCoroutinesCommands by RedisHashCoroutinesCommandsImpl(ops), RedisHLLCoroutinesCommands by RedisHLLCoroutinesCommandsImpl(ops), diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisFunctionCoroutinesCommands.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisFunctionCoroutinesCommands.kt new file mode 100644 index 0000000000..b7c5de7bcd --- /dev/null +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisFunctionCoroutinesCommands.kt @@ -0,0 +1,170 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.lettuce.core.api.coroutines + +import io.lettuce.core.ExperimentalLettuceCoroutinesApi +import io.lettuce.core.FlushMode +import io.lettuce.core.FunctionRestoreMode +import io.lettuce.core.ScriptOutputType + +/** + * Coroutine executed commands for Redis Functions. [java.lang.String Function code] is encoded by using the configured + * [io.lettuce.core.ClientOptions#getScriptCharset charset]. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 6.3 + * @generated by io.lettuce.apigenerator.CreateKotlinCoroutinesApi + */ +@ExperimentalLettuceCoroutinesApi +interface RedisFunctionCoroutinesCommands { + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + suspend fun fcall( + function: String, + type: ScriptOutputType, + vararg keys: K + ): T? + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + suspend fun fcall( + function: String, + type: ScriptOutputType, + keys: Array, + vararg values: V + ): T? + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + suspend fun fcallReadOnly( + function: String, + type: ScriptOutputType, + vararg keys: K + ): T? + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + suspend fun fcallReadOnly( + function: String, + type: ScriptOutputType, + keys: Array, + vararg values: V + ): T? + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @return name of the library. + */ + suspend fun functionLoad(functionCode: String): String? + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @param replace whether to replace an existing function. + * @return name of the library. + */ + suspend fun functionLoad(functionCode: String, replace: Boolean): String? + + /** + * Return the serialized payload of loaded libraries. You can restore the dump through {@link #functionRestore(byte[])}. + * + * @return the serialized payload. + */ + suspend fun functionDump(): ByteArray? + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + suspend fun functionRestore(dump: ByteArray): String? + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + suspend fun functionRestore(dump: ByteArray, mode: FunctionRestoreMode): String? + + /** + * Deletes all the libraries using the specified [FlushMode]. + * + * @param flushMode the flush mode (sync/async). + * @return String simple-string-reply. + */ + suspend fun functionFlush(flushMode: FlushMode): String? + + /** + * Kill a function that is currently executing. + * + * @return String simple-string-reply. + */ + suspend fun functionKill(): String? + + /** + * Return information about the functions and libraries. + * + * @return Array reply. + */ + suspend fun functionList(): List> + + /** + * Return information about the functions and libraries. + * + * @param libraryName specify a pattern for matching library names. + * @return Array reply. + */ + suspend fun functionList(libraryName: String): List> + +} + diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisFunctionCoroutinesCommandsImpl.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisFunctionCoroutinesCommandsImpl.kt new file mode 100644 index 0000000000..c0a36f326a --- /dev/null +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisFunctionCoroutinesCommandsImpl.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.lettuce.core.api.coroutines + +import io.lettuce.core.ExperimentalLettuceCoroutinesApi +import io.lettuce.core.FlushMode +import io.lettuce.core.FunctionRestoreMode +import io.lettuce.core.ScriptOutputType +import io.lettuce.core.api.reactive.RedisFunctionReactiveCommands +import kotlinx.coroutines.reactive.awaitFirstOrNull + + +/** + * Coroutine executed commands (based on reactive commands) for the Function API. + * + * @author Mark Paluch + * @since 6.3 + */ +@ExperimentalLettuceCoroutinesApi +internal class RedisFunctionCoroutinesCommandsImpl(internal val ops: RedisFunctionReactiveCommands) : + RedisFunctionCoroutinesCommands { + + override suspend fun fcall( + function: String, + type: ScriptOutputType, + vararg keys: K + ): T? = ops.fcall(function, type, *keys).awaitFirstOrNull() + + override suspend fun fcall( + function: String, + type: ScriptOutputType, + keys: Array, + vararg values: V + ): T? = ops.fcall(function, type, keys, *values).awaitFirstOrNull() + + override suspend fun fcallReadOnly( + function: String, + type: ScriptOutputType, + vararg keys: K + ): T? = ops.fcallReadOnly(function, type, *keys).awaitFirstOrNull() + + override suspend fun fcallReadOnly( + function: String, + type: ScriptOutputType, + keys: Array, + vararg values: V + ): T? = ops.fcallReadOnly(function, type, keys, *values).awaitFirstOrNull() + + override suspend fun functionLoad(functionCode: String): String? = + ops.functionLoad(functionCode).awaitFirstOrNull() + + override suspend fun functionLoad(functionCode: String, replace: Boolean): String? = + ops.functionLoad(functionCode, replace).awaitFirstOrNull() + + override suspend fun functionDump(): ByteArray? = + ops.functionDump().awaitFirstOrNull() + + override suspend fun functionRestore(dump: ByteArray): String? = + ops.functionRestore(dump).awaitFirstOrNull() + + override suspend fun functionRestore( + dump: ByteArray, + mode: FunctionRestoreMode + ): String? = ops.functionRestore(dump, mode).awaitFirstOrNull() + + override suspend fun functionFlush(flushMode: FlushMode): String? = + ops.functionFlush(flushMode).awaitFirstOrNull() + + override suspend fun functionKill(): String? = ops.functionKill().awaitFirstOrNull() + + override suspend fun functionList(): List> = + ops.functionList().collectList().awaitFirstOrNull()!! + + override suspend fun functionList(libraryName: String): List> = + ops.functionList(libraryName).collectList().awaitFirstOrNull()!! + +} + diff --git a/src/main/templates/io/lettuce/core/api/RedisFunctionCommands.java b/src/main/templates/io/lettuce/core/api/RedisFunctionCommands.java new file mode 100644 index 0000000000..2c834433f0 --- /dev/null +++ b/src/main/templates/io/lettuce/core/api/RedisFunctionCommands.java @@ -0,0 +1,150 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.lettuce.core.api; + +import java.util.Map; +import java.util.List; + +import io.lettuce.core.FlushMode; +import io.lettuce.core.FunctionRestoreMode; +import io.lettuce.core.ScriptOutputType; + +/** + * ${intent} for Redis Functions. {@link java.lang.String Function code} is encoded by using the configured + * {@link io.lettuce.core.ClientOptions#getScriptCharset() charset}. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 6.3 + */ +public interface RedisFunctionCommands { + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + T fcall(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + T fcall(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys key names. + * @param expected return type. + * @return function result. + */ + T fcallReadOnly(String function, ScriptOutputType type, K... keys); + + /** + * Invoke a function in read-only mode. + * + * @param function the function name. + * @param type output type. + * @param keys the keys. + * @param values the values (arguments). + * @param expected return type. + * @return function result. + */ + T fcallReadOnly(String function, ScriptOutputType type, K[] keys, V... values); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @return name of the library. + */ + String functionLoad(String functionCode); + + /** + * Load a library to Redis. + * + * @param functionCode code of the function. + * @param replace whether to replace an existing function. + * @return name of the library. + */ + String functionLoad(String functionCode, boolean replace); + + /** + * Return the serialized payload of loaded libraries. You can restore the dump through {@link #functionRestore(byte[])}. + * + * @return the serialized payload. + */ + byte[] functionDump(); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + String functionRestore(byte[] dump); + + /** + * You can restore the dumped payload of loaded libraries. + * + * @return Simple string reply + */ + String functionRestore(byte[] dump, FunctionRestoreMode mode); + + /** + * Deletes all the libraries using the specified {@link FlushMode}. + * + * @param flushMode the flush mode (sync/async). + * @return String simple-string-reply. + */ + String functionFlush(FlushMode flushMode); + + /** + * Kill a function that is currently executing. + * + * @return String simple-string-reply. + */ + String functionKill(); + + /** + * Return information about the functions and libraries. + * + * @return Array reply. + */ + List> functionList(); + + /** + * Return information about the functions and libraries. + * + * @param libraryName specify a pattern for matching library names. + * @return Array reply. + */ + List> functionList(String libraryName); + +} diff --git a/src/test/java/io/lettuce/apigenerator/Constants.java b/src/test/java/io/lettuce/apigenerator/Constants.java index 38bb67cf9b..2697fe9dde 100644 --- a/src/test/java/io/lettuce/apigenerator/Constants.java +++ b/src/test/java/io/lettuce/apigenerator/Constants.java @@ -25,6 +25,7 @@ class Constants { public static final String[] TEMPLATE_NAMES = { "BaseRedisCommands", "RedisAclCommands", + "RedisFunctionCommands", "RedisGeoCommands", "RedisHashCommands", "RedisHLLCommands", diff --git a/src/test/java/io/lettuce/apigenerator/CreateReactiveApi.java b/src/test/java/io/lettuce/apigenerator/CreateReactiveApi.java index aabdd15ada..d817c87291 100644 --- a/src/test/java/io/lettuce/apigenerator/CreateReactiveApi.java +++ b/src/test/java/io/lettuce/apigenerator/CreateReactiveApi.java @@ -50,7 +50,7 @@ public class CreateReactiveApi { public static Set KEEP_METHOD_RESULT_TYPE = LettuceSets.unmodifiableSet("digest", "close", "isOpen", "BaseRedisCommands.reset", "getStatefulConnection", "setAutoFlushCommands", "flushCommands"); public static Set FORCE_FLUX_RESULT = LettuceSets.unmodifiableSet("eval", "evalsha", "evalReadOnly", - "evalshaReadOnly", "dispatch"); + "evalshaReadOnly", "fcall", "fcallReadOnly", "dispatch"); public static Set VALUE_WRAP = LettuceSets.unmodifiableSet("geopos", "bitfield"); private static final Map RESULT_SPEC; diff --git a/src/test/java/io/lettuce/core/commands/FunctionCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/FunctionCommandIntegrationTests.java new file mode 100644 index 0000000000..19a219ebe6 --- /dev/null +++ b/src/test/java/io/lettuce/core/commands/FunctionCommandIntegrationTests.java @@ -0,0 +1,131 @@ +/* + * Copyright 2011-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.lettuce.core.commands; + +import static io.lettuce.core.ScriptOutputType.*; +import static org.assertj.core.api.Assertions.*; + +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; + +import io.lettuce.core.FlushMode; +import io.lettuce.core.RedisClient; +import io.lettuce.core.RedisCommandExecutionException; +import io.lettuce.core.RedisException; +import io.lettuce.core.TestSupport; +import io.lettuce.core.api.sync.RedisCommands; +import io.lettuce.test.LettuceExtension; +import io.lettuce.test.Wait; +import io.lettuce.test.condition.EnabledOnCommand; + +/** + * Integration tests for function commands. + * + * @author Mark Paluch + */ +@ExtendWith(LettuceExtension.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@EnabledOnCommand("FUNCTION") +public class FunctionCommandIntegrationTests extends TestSupport { + + private final RedisClient client; + + private final RedisCommands redis; + + @Inject + protected FunctionCommandIntegrationTests(RedisClient client, RedisCommands redis) { + this.client = client; + this.redis = redis; + } + + @BeforeEach + void setUp() { + redis.functionFlush(FlushMode.SYNC); + } + + @AfterEach + void tearDown() { + + Wait.untilNoException(() -> { + try { + redis.functionKill(); + } catch (RedisException e) { + // ignore + } + redis.ping(); + }).waitOrTimeout(); + } + + @Test + void fcall() { + + redis.functionLoad("#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)"); + assertThat((String) redis.fcall("myfunc", STATUS, new String[] { key }, "Hello")).isEqualTo("Hello"); + } + + @Test + void fcallReadOnly() { + + redis.functionLoad("#!lua name=mylib \n " + "local function my_echo(keys, args) \n" + " return args[1] \n" + "end\n" + + "redis.register_function{function_name='my_echo',callback=my_echo, flags={ 'no-writes' }}"); + assertThat((String) redis.fcallReadOnly("my_echo", STATUS, new String[] { key }, "Hello")).isEqualTo("Hello"); + } + + @Test + void functionLoad() { + + redis.functionLoad("#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)"); + assertThatExceptionOfType(RedisCommandExecutionException.class).isThrownBy(() -> redis.functionLoad( + "#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)")); + + String result = redis.functionLoad( + "#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)", true); + assertThat(result).isEqualTo("mylib"); + } + + @Test + void functionDumpAndRestore() { + + redis.functionLoad("#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)"); + byte[] dump = redis.functionDump(); + redis.functionFlush(FlushMode.SYNC); + System.out.println(redis.functionRestore(dump)); + } + + @Test + void functionList() { + + List> maps = redis.functionList(); + assertThat(maps).isEmpty(); + + redis.functionLoad("#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)"); + + redis.functionLoad("#!lua name=my_other_lib \n " + "local function my_echo(keys, args) \n" + " return args[1] \n" + + "end\n" + "redis.register_function{function_name='my_echo',callback=my_echo, flags={ 'no-writes' }}"); + + maps = redis.functionList(); + assertThat(maps).hasSize(2); + } + +} diff --git a/src/test/java/io/lettuce/core/commands/ScriptingCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/ScriptingCommandIntegrationTests.java index 37a4325988..06945432ce 100644 --- a/src/test/java/io/lettuce/core/commands/ScriptingCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/commands/ScriptingCommandIntegrationTests.java @@ -175,6 +175,7 @@ void evalshaWithArgs() { void evalshaReadOnly() { redis.scriptFlush(); redis.set("foo", "bar"); + String digest = redis.scriptLoad("return redis.call('get','foo')"); String[] keys = new String[0]; assertThat((String) redis.evalshaReadOnly(digest, STATUS, keys)).isEqualTo("bar"); diff --git a/src/test/java/io/lettuce/core/commands/reactive/FunctionReactiveCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/reactive/FunctionReactiveCommandIntegrationTests.java new file mode 100644 index 0000000000..bdf1ac0ba9 --- /dev/null +++ b/src/test/java/io/lettuce/core/commands/reactive/FunctionReactiveCommandIntegrationTests.java @@ -0,0 +1,35 @@ +/* + * Copyright 20234 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.lettuce.core.commands.reactive; + +import javax.inject.Inject; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.commands.FunctionCommandIntegrationTests; +import io.lettuce.test.ReactiveSyncInvocationHandler; + +/** + * @author Mark Paluch + */ +class FunctionReactiveCommandIntegrationTests extends FunctionCommandIntegrationTests { + + @Inject + FunctionReactiveCommandIntegrationTests(RedisClient client, StatefulRedisConnection connection) { + super(client, ReactiveSyncInvocationHandler.sync(connection)); + } + +}