From fc5d14b993e499bb569a8f8343cc077357291d32 Mon Sep 17 00:00:00 2001 From: Tihomir Mateev Date: Fri, 9 Aug 2024 13:10:49 +0300 Subject: [PATCH] Implemented all JSON commands --- .../core/AbstractRedisAsyncCommands.java | 6 +- .../core/AbstractRedisReactiveCommands.java | 6 +- .../lettuce/core/RedisAsyncCommandsImpl.java | 2 +- .../lettuce/core/RedisJsonCommandBuilder.java | 186 ++++++++++----- .../core/RedisReactiveCommandsImpl.java | 2 +- .../api/async/RedisJsonAsyncCommands.java | 12 +- .../reactive/RedisJsonReactiveCommands.java | 13 +- .../core/api/sync/RedisJsonCommands.java | 12 +- .../async/NodeSelectionJsonAsyncCommands.java | 12 +- .../api/sync/NodeSelectionJsonCommands.java | 12 +- .../core/json/arguments/JsonMsetArgs.java | 8 +- .../core/json/arguments/JsonRangeArgs.java | 25 +- .../MasterSlaveConnectionWrapper.java | 10 - .../io/lettuce/core/protocol/CommandType.java | 2 +- .../coroutines/RedisJsonCoroutinesCommands.kt | 12 +- .../RedisJsonCoroutinesCommandsImpl.kt | 6 +- .../lettuce/core/api/RedisJsonCommands.java | 12 +- .../core/RedisContainerIntegrationTests.java | 10 +- .../RedisJsonCommandBuilderUnitTests.java | 220 +++++++++++++++++- .../core/json/RedisJsonIntegrationTests.java | 11 +- 20 files changed, 432 insertions(+), 147 deletions(-) diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java index 946171b3ad..82b23df407 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java @@ -1518,7 +1518,7 @@ public RedisFuture>> jsonMGet(JsonPath jsonPath, K... keys) } @Override - public RedisFuture jsonMSet(JsonMsetArgs... arguments) { + public RedisFuture jsonMSet(JsonMsetArgs... arguments) { return dispatch(jsonCommandBuilder.jsonMSet(arguments)); } @@ -1528,7 +1528,7 @@ public RedisFuture> jsonNumincrby(K key, JsonPath jsonPath, Number } @Override - public RedisFuture>> jsonObjkeys(K key, JsonPath jsonPath) { + public RedisFuture> jsonObjkeys(K key, JsonPath jsonPath) { return dispatch(jsonCommandBuilder.jsonObjkeys(key, jsonPath)); } @@ -1553,7 +1553,7 @@ public RedisFuture> jsonStrlen(K key, JsonPath jsonPath) { } @Override - public RedisFuture> jsonToggle(K key, JsonPath jsonPath) { + public RedisFuture> jsonToggle(K key, JsonPath jsonPath) { return dispatch(jsonCommandBuilder.jsonToggle(key, jsonPath)); } diff --git a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java index 31a2328c98..de618e13ce 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java @@ -1583,7 +1583,7 @@ public Flux> jsonMGet(JsonPath jsonPath, K... keys) { } @Override - public Mono jsonMSet(JsonMsetArgs... arguments) { + public Mono jsonMSet(JsonMsetArgs... arguments) { return createMono(() -> jsonCommandBuilder.jsonMSet(arguments)); } @@ -1593,7 +1593,7 @@ public Flux jsonNumincrby(K key, JsonPath jsonPath, Number number) { } @Override - public Flux> jsonObjkeys(K key, JsonPath jsonPath) { + public Flux jsonObjkeys(K key, JsonPath jsonPath) { return createDissolvingFlux(() -> jsonCommandBuilder.jsonObjkeys(key, jsonPath)); } @@ -1618,7 +1618,7 @@ public Flux jsonStrlen(K key, JsonPath jsonPath) { } @Override - public Flux jsonToggle(K key, JsonPath jsonPath) { + public Flux jsonToggle(K key, JsonPath jsonPath) { return createDissolvingFlux(() -> jsonCommandBuilder.jsonToggle(key, jsonPath)); } diff --git a/src/main/java/io/lettuce/core/RedisAsyncCommandsImpl.java b/src/main/java/io/lettuce/core/RedisAsyncCommandsImpl.java index 4c14d8418b..d7c5799229 100644 --- a/src/main/java/io/lettuce/core/RedisAsyncCommandsImpl.java +++ b/src/main/java/io/lettuce/core/RedisAsyncCommandsImpl.java @@ -17,7 +17,7 @@ public class RedisAsyncCommandsImpl extends AbstractRedisAsyncCommands implements RedisAsyncCommands, RedisClusterAsyncCommands { - private final RedisCodec codec; + private final RedisCodec codec; /** * Initialize a new instance. diff --git a/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java b/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java index 7b19c98e89..0e5871d8cb 100644 --- a/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java +++ b/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java @@ -3,19 +3,6 @@ * All rights reserved. * * Licensed under the MIT License. - * - * This file contains contributions from third-party contributors - * 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; @@ -27,29 +14,21 @@ import io.lettuce.core.json.JsonPath; import io.lettuce.core.json.arguments.JsonRangeArgs; import io.lettuce.core.json.arguments.JsonSetArgs; -import io.lettuce.core.output.BooleanListOutput; import io.lettuce.core.output.BooleanOutput; import io.lettuce.core.output.IntegerListOutput; import io.lettuce.core.output.IntegerOutput; import io.lettuce.core.output.JsonValueListOutput; +import io.lettuce.core.output.KeyListOutput; import io.lettuce.core.output.NumberListOutput; import io.lettuce.core.output.StatusOutput; import io.lettuce.core.output.ValueListOutput; import io.lettuce.core.protocol.BaseRedisCommandBuilder; import io.lettuce.core.protocol.Command; import io.lettuce.core.protocol.CommandArgs; -import io.lettuce.core.protocol.RedisCommand; import java.util.List; -import static io.lettuce.core.protocol.CommandType.JSON_ARRAPPEND; -import static io.lettuce.core.protocol.CommandType.JSON_ARRLEN; -import static io.lettuce.core.protocol.CommandType.JSON_ARRPOP; -import static io.lettuce.core.protocol.CommandType.JSON_DEL; -import static io.lettuce.core.protocol.CommandType.JSON_GET; -import static io.lettuce.core.protocol.CommandType.JSON_NUMINCRBY; -import static io.lettuce.core.protocol.CommandType.JSON_SET; -import static io.lettuce.core.protocol.CommandType.JSON_TYPE; +import static io.lettuce.core.protocol.CommandType.*; /** * Implementation of the {@link BaseRedisCommandBuilder} handling JSON commands. @@ -63,7 +42,7 @@ class RedisJsonCommandBuilder extends BaseRedisCommandBuilder { super(codec); } - Command> jsonArrappend(K key, JsonPath jsonPath, JsonValue[] jsonValues) { + Command> jsonArrappend(K key, JsonPath jsonPath, JsonValue... jsonValues) { notNullKey(key); CommandArgs args = new CommandArgs<>(codec).addKey(key); @@ -79,7 +58,7 @@ Command> jsonArrappend(K key, JsonPath jsonPath, JsonValue(codec), args); } - RedisCommand> jsonArrindex(K key, JsonPath jsonPath, JsonValue value, JsonRangeArgs range) { + Command> jsonArrindex(K key, JsonPath jsonPath, JsonValue value, JsonRangeArgs range) { notNullKey(key); CommandArgs args = new CommandArgs<>(codec).addKey(key); @@ -95,14 +74,28 @@ RedisCommand> jsonArrindex(K key, JsonPath jsonPath, JsonValue< range.build(args); } - return createCommand(JSON_ARRLEN, new IntegerListOutput<>(codec), args); + return createCommand(JSON_ARRINDEX, new IntegerListOutput<>(codec), args); } - RedisCommand> jsonArrinsert(K key, JsonPath jsonPath, int index, JsonValue[] values) { - return null; + Command> jsonArrinsert(K key, JsonPath jsonPath, int index, JsonValue... values) { + notNullKey(key); + + CommandArgs args = new CommandArgs<>(codec).addKey(key); + + if (jsonPath != null && !jsonPath.isRootPath()) { + args.add(jsonPath.toString()); + } + + args.add(index); + + for (JsonValue value : values) { + args.add(value.asByteBuffer().array()); + } + + return createCommand(JSON_ARRINSERT, new IntegerListOutput<>(codec), args); } - RedisCommand> jsonArrlen(K key, JsonPath jsonPath) { + Command> jsonArrlen(K key, JsonPath jsonPath) { notNullKey(key); CommandArgs args = new CommandArgs<>(codec).addKey(key); @@ -113,7 +106,7 @@ RedisCommand> jsonArrlen(K key, JsonPath jsonPath) { return createCommand(JSON_ARRLEN, new IntegerListOutput<>(codec), args); } - RedisCommand>> jsonArrpop(K key, JsonPath jsonPath, int index) { + Command>> jsonArrpop(K key, JsonPath jsonPath, int index) { notNullKey(key); CommandArgs args = new CommandArgs<>(codec).addKey(key); @@ -129,15 +122,36 @@ RedisCommand>> jsonArrpop(K key, JsonPath jsonPath, i return createCommand(JSON_ARRPOP, new JsonValueListOutput<>(codec), args); } - RedisCommand> jsonArrtrim(K key, JsonPath jsonPath, JsonRangeArgs range) { - return null; + Command> jsonArrtrim(K key, JsonPath jsonPath, JsonRangeArgs range) { + + notNullKey(key); + + CommandArgs args = new CommandArgs<>(codec).addKey(key); + + if (jsonPath != null && !jsonPath.isRootPath()) { + args.add(jsonPath.toString()); + } + + if (range != null) { + range.build(args); + } + + return createCommand(JSON_ARRTRIM, new IntegerListOutput<>(codec), args); } - RedisCommand jsonClear(K key, JsonPath jsonPath) { - return null; + Command jsonClear(K key, JsonPath jsonPath) { + notNullKey(key); + + CommandArgs args = new CommandArgs<>(codec).addKey(key); + + if (jsonPath != null && !jsonPath.isRootPath()) { + args.add(jsonPath.toString()); + } + + return createCommand(JSON_CLEAR, new IntegerOutput<>(codec), args); } - RedisCommand>> jsonGet(K key, JsonGetArgs options, JsonPath[] jsonPaths) { + Command>> jsonGet(K key, JsonGetArgs options, JsonPath... jsonPaths) { notNullKey(key); CommandArgs args = new CommandArgs<>(codec).addKey(key); @@ -157,11 +171,22 @@ RedisCommand>> jsonGet(K key, JsonGetArgs options, Js return createCommand(JSON_GET, new JsonValueListOutput<>(codec), args); } - RedisCommand jsonMerge(K key, JsonPath jsonPath, JsonValue value) { - return null; + Command jsonMerge(K key, JsonPath jsonPath, JsonValue value) { + + notNullKey(key); + + CommandArgs args = new CommandArgs<>(codec).addKey(key); + + if (jsonPath != null && !jsonPath.isRootPath()) { + args.add(jsonPath.toString()); + } + + args.add(value.asByteBuffer().array()); + + return createCommand(JSON_MERGE, new BooleanOutput<>(codec), args); } - RedisCommand>> jsonMGet(JsonPath jsonPath, K[] keys) { + Command>> jsonMGet(JsonPath jsonPath, K... keys) { notEmpty(keys); CommandArgs args = new CommandArgs<>(codec).addKeys(keys); @@ -170,14 +195,23 @@ RedisCommand>> jsonMGet(JsonPath jsonPath, K[] keys) args.add(jsonPath.toString()); } - return createCommand(JSON_GET, new JsonValueListOutput<>(codec), args); + return createCommand(JSON_MGET, new JsonValueListOutput<>(codec), args); } - RedisCommand jsonMSet(JsonMsetArgs[] arguments) { - return null; + Command jsonMSet(JsonMsetArgs... arguments) { + + notEmpty(arguments); + + CommandArgs args = new CommandArgs<>(codec); + + for (JsonMsetArgs argument : arguments) { + argument.build(args); + } + + return createCommand(JSON_MSET, new StatusOutput<>(codec), args); } - RedisCommand> jsonNumincrby(K key, JsonPath jsonPath, Number number) { + Command> jsonNumincrby(K key, JsonPath jsonPath, Number number) { notNullKey(key); CommandArgs args = new CommandArgs<>(codec).addKey(key); @@ -191,15 +225,32 @@ RedisCommand> jsonNumincrby(K key, JsonPath jsonPath, Number return createCommand(JSON_NUMINCRBY, new NumberListOutput<>(codec), args); } - RedisCommand>> jsonObjkeys(K key, JsonPath jsonPath) { - return null; + Command> jsonObjkeys(K key, JsonPath jsonPath) { + notNullKey(key); + + CommandArgs args = new CommandArgs<>(codec).addKey(key); + + if (jsonPath != null && !jsonPath.isRootPath()) { + args.add(jsonPath.toString()); + } + + return createCommand(JSON_OBJKEYS, new KeyListOutput<>(codec), args); } - RedisCommand> jsonObjlen(K key, JsonPath jsonPath) { - return null; + Command> jsonObjlen(K key, JsonPath jsonPath) { + + notNullKey(key); + + CommandArgs args = new CommandArgs<>(codec).addKey(key); + + if (jsonPath != null && !jsonPath.isRootPath()) { + args.add(jsonPath.toString()); + } + + return createCommand(JSON_OBJLEN, new IntegerListOutput<>(codec), args); } - RedisCommand jsonSet(K key, JsonPath jsonPath, JsonValue value, JsonSetArgs options) { + Command jsonSet(K key, JsonPath jsonPath, JsonValue value, JsonSetArgs options) { notNullKey(key); CommandArgs args = new CommandArgs<>(codec).addKey(key); @@ -217,19 +268,46 @@ RedisCommand jsonSet(K key, JsonPath jsonPath, JsonValue val return createCommand(JSON_SET, new StatusOutput<>(codec), args); } - RedisCommand> jsonStrappend(K key, JsonPath jsonPath, JsonValue value) { - return null; + Command> jsonStrappend(K key, JsonPath jsonPath, JsonValue value) { + notNullKey(key); + + CommandArgs args = new CommandArgs<>(codec).addKey(key); + + if (jsonPath != null && !jsonPath.isRootPath()) { + args.add(jsonPath.toString()); + } + + args.add(value.asByteBuffer().array()); + + return createCommand(JSON_STRAPPEND, new IntegerListOutput<>(codec), args); } - RedisCommand> jsonStrlen(K key, JsonPath jsonPath) { - return null; + Command> jsonStrlen(K key, JsonPath jsonPath) { + + notNullKey(key); + + CommandArgs args = new CommandArgs<>(codec).addKey(key); + + if (jsonPath != null && !jsonPath.isRootPath()) { + args.add(jsonPath.toString()); + } + + return createCommand(JSON_STRLEN, new IntegerListOutput<>(codec), args); } - RedisCommand> jsonToggle(K key, JsonPath jsonPath) { - return null; + Command> jsonToggle(K key, JsonPath jsonPath) { + notNullKey(key); + + CommandArgs args = new CommandArgs<>(codec).addKey(key); + + if (jsonPath != null && !jsonPath.isRootPath()) { + args.add(jsonPath.toString()); + } + + return createCommand(JSON_TOGGLE, new IntegerListOutput<>(codec), args); } - RedisCommand jsonDel(K key, JsonPath jsonPath) { + Command jsonDel(K key, JsonPath jsonPath) { notNullKey(key); CommandArgs args = new CommandArgs<>(codec).addKey(key); diff --git a/src/main/java/io/lettuce/core/RedisReactiveCommandsImpl.java b/src/main/java/io/lettuce/core/RedisReactiveCommandsImpl.java index b3ee424307..a972c12e86 100644 --- a/src/main/java/io/lettuce/core/RedisReactiveCommandsImpl.java +++ b/src/main/java/io/lettuce/core/RedisReactiveCommandsImpl.java @@ -17,7 +17,7 @@ public class RedisReactiveCommandsImpl extends AbstractRedisReactiveCommands implements RedisReactiveCommands, RedisClusterReactiveCommands { - private final RedisCodec codec; + private final RedisCodec codec; /** * Initialize a new instance. diff --git a/src/main/java/io/lettuce/core/api/async/RedisJsonAsyncCommands.java b/src/main/java/io/lettuce/core/api/async/RedisJsonAsyncCommands.java index 532dfff9cd..aa68d7277f 100644 --- a/src/main/java/io/lettuce/core/api/async/RedisJsonAsyncCommands.java +++ b/src/main/java/io/lettuce/core/api/async/RedisJsonAsyncCommands.java @@ -199,10 +199,10 @@ public interface RedisJsonAsyncCommands { * A JSON value is a hierarchical structure. If you change a value in a specific path - nested values are affected. * * @param arguments the {@link JsonMsetArgs} specifying the values to change. - * @return Boolean true if the merge was successful, false otherwise. + * @return "OK" if the operation was successful, error otherwise * @since 6.5 */ - RedisFuture jsonMSet(JsonMsetArgs... arguments); + RedisFuture jsonMSet(JsonMsetArgs... arguments); /** * Increment the number value stored at the specified {@link JsonPath} in the JSON document by the provided increment. @@ -220,10 +220,10 @@ public interface RedisJsonAsyncCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s) whose key(s) we want. - * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. + * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. * @since 6.5 */ - RedisFuture>> jsonObjkeys(K key, JsonPath jsonPath); + RedisFuture> jsonObjkeys(K key, JsonPath jsonPath); /** * Report the number of keys in the JSON object at path in key @@ -282,10 +282,10 @@ public interface RedisJsonAsyncCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s). - * @return List the new value after the toggle, or null if the path does not exist. + * @return List the new value after the toggle, 0 for false, 1 for true or null if the path does not exist. * @since 6.5 */ - RedisFuture> jsonToggle(K key, JsonPath jsonPath); + RedisFuture> jsonToggle(K key, JsonPath jsonPath); /** * Report the type of JSON value at the provided {@link JsonPath} in the JSON document. diff --git a/src/main/java/io/lettuce/core/api/reactive/RedisJsonReactiveCommands.java b/src/main/java/io/lettuce/core/api/reactive/RedisJsonReactiveCommands.java index 4ffad73c6a..91446ea6b9 100644 --- a/src/main/java/io/lettuce/core/api/reactive/RedisJsonReactiveCommands.java +++ b/src/main/java/io/lettuce/core/api/reactive/RedisJsonReactiveCommands.java @@ -19,7 +19,6 @@ */ package io.lettuce.core.api.reactive; -import java.util.List; import io.lettuce.core.json.JsonPath; import io.lettuce.core.json.JsonValue; import io.lettuce.core.json.arguments.JsonGetArgs; @@ -200,10 +199,10 @@ public interface RedisJsonReactiveCommands { * A JSON value is a hierarchical structure. If you change a value in a specific path - nested values are affected. * * @param arguments the {@link JsonMsetArgs} specifying the values to change. - * @return Boolean true if the merge was successful, false otherwise. + * @return "OK" if the operation was successful, error otherwise * @since 6.5 */ - Mono jsonMSet(JsonMsetArgs... arguments); + Mono jsonMSet(JsonMsetArgs... arguments); /** * Increment the number value stored at the specified {@link JsonPath} in the JSON document by the provided increment. @@ -221,10 +220,10 @@ public interface RedisJsonReactiveCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s) whose key(s) we want. - * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. + * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. * @since 6.5 */ - Flux> jsonObjkeys(K key, JsonPath jsonPath); + Flux jsonObjkeys(K key, JsonPath jsonPath); /** * Report the number of keys in the JSON object at path in key @@ -283,10 +282,10 @@ public interface RedisJsonReactiveCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s). - * @return List the new value after the toggle, or null if the path does not exist. + * @return List the new value after the toggle, 0 for false, 1 for true or null if the path does not exist. * @since 6.5 */ - Flux jsonToggle(K key, JsonPath jsonPath); + Flux jsonToggle(K key, JsonPath jsonPath); /** * Report the type of JSON value at the provided {@link JsonPath} in the JSON document. diff --git a/src/main/java/io/lettuce/core/api/sync/RedisJsonCommands.java b/src/main/java/io/lettuce/core/api/sync/RedisJsonCommands.java index 1595258e8b..09aab63272 100644 --- a/src/main/java/io/lettuce/core/api/sync/RedisJsonCommands.java +++ b/src/main/java/io/lettuce/core/api/sync/RedisJsonCommands.java @@ -198,10 +198,10 @@ public interface RedisJsonCommands { * A JSON value is a hierarchical structure. If you change a value in a specific path - nested values are affected. * * @param arguments the {@link JsonMsetArgs} specifying the values to change. - * @return Boolean true if the merge was successful, false otherwise. + * @return "OK" if the operation was successful, error otherwise * @since 6.5 */ - Boolean jsonMSet(JsonMsetArgs... arguments); + String jsonMSet(JsonMsetArgs... arguments); /** * Increment the number value stored at the specified {@link JsonPath} in the JSON document by the provided increment. @@ -219,10 +219,10 @@ public interface RedisJsonCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s) whose key(s) we want. - * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. + * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. * @since 6.5 */ - List> jsonObjkeys(K key, JsonPath jsonPath); + List jsonObjkeys(K key, JsonPath jsonPath); /** * Report the number of keys in the JSON object at path in key @@ -281,10 +281,10 @@ public interface RedisJsonCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s). - * @return List the new value after the toggle, or null if the path does not exist. + * @return List the new value after the toggle, 0 for false, 1 for true or null if the path does not exist. * @since 6.5 */ - List jsonToggle(K key, JsonPath jsonPath); + List jsonToggle(K key, JsonPath jsonPath); /** * Report the type of JSON value at the provided {@link JsonPath} in the JSON document. diff --git a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionJsonAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionJsonAsyncCommands.java index de201b0e13..be54374e6e 100644 --- a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionJsonAsyncCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionJsonAsyncCommands.java @@ -198,10 +198,10 @@ public interface NodeSelectionJsonAsyncCommands { * A JSON value is a hierarchical structure. If you change a value in a specific path - nested values are affected. * * @param arguments the {@link JsonMsetArgs} specifying the values to change. - * @return Boolean true if the merge was successful, false otherwise. + * @return "OK" if the operation was successful, error otherwise * @since 6.5 */ - AsyncExecutions jsonMSet(JsonMsetArgs... arguments); + AsyncExecutions jsonMSet(JsonMsetArgs... arguments); /** * Increment the number value stored at the specified {@link JsonPath} in the JSON document by the provided increment. @@ -219,10 +219,10 @@ public interface NodeSelectionJsonAsyncCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s) whose key(s) we want. - * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. + * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. * @since 6.5 */ - AsyncExecutions>> jsonObjkeys(K key, JsonPath jsonPath); + AsyncExecutions> jsonObjkeys(K key, JsonPath jsonPath); /** * Report the number of keys in the JSON object at path in key @@ -281,10 +281,10 @@ public interface NodeSelectionJsonAsyncCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s). - * @return List the new value after the toggle, or null if the path does not exist. + * @return List the new value after the toggle, 0 for false, 1 for true or null if the path does not exist. * @since 6.5 */ - AsyncExecutions> jsonToggle(K key, JsonPath jsonPath); + AsyncExecutions> jsonToggle(K key, JsonPath jsonPath); /** * Report the type of JSON value at the provided {@link JsonPath} in the JSON document. diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionJsonCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionJsonCommands.java index 4bd7f7bea5..c5743ec69b 100644 --- a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionJsonCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionJsonCommands.java @@ -198,10 +198,10 @@ public interface NodeSelectionJsonCommands { * A JSON value is a hierarchical structure. If you change a value in a specific path - nested values are affected. * * @param arguments the {@link JsonMsetArgs} specifying the values to change. - * @return Boolean true if the merge was successful, false otherwise. + * @return "OK" if the operation was successful, error otherwise * @since 6.5 */ - Executions jsonMSet(JsonMsetArgs... arguments); + Executions jsonMSet(JsonMsetArgs... arguments); /** * Increment the number value stored at the specified {@link JsonPath} in the JSON document by the provided increment. @@ -219,10 +219,10 @@ public interface NodeSelectionJsonCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s) whose key(s) we want. - * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. + * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. * @since 6.5 */ - Executions>> jsonObjkeys(K key, JsonPath jsonPath); + Executions> jsonObjkeys(K key, JsonPath jsonPath); /** * Report the number of keys in the JSON object at path in key @@ -281,10 +281,10 @@ public interface NodeSelectionJsonCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s). - * @return List the new value after the toggle, or null if the path does not exist. + * @return List the new value after the toggle, 0 for false, 1 for true or null if the path does not exist. * @since 6.5 */ - Executions> jsonToggle(K key, JsonPath jsonPath); + Executions> jsonToggle(K key, JsonPath jsonPath); /** * Report the type of JSON value at the provided {@link JsonPath} in the JSON document. diff --git a/src/main/java/io/lettuce/core/json/arguments/JsonMsetArgs.java b/src/main/java/io/lettuce/core/json/arguments/JsonMsetArgs.java index d336295ae3..a0a5045269 100644 --- a/src/main/java/io/lettuce/core/json/arguments/JsonMsetArgs.java +++ b/src/main/java/io/lettuce/core/json/arguments/JsonMsetArgs.java @@ -39,7 +39,7 @@ public class JsonMsetArgs implements CompositeArgument { private JsonPath path; - private JsonValue element; + private JsonValue element; /** * Builder entry points for {@link JsonGetArgs}. @@ -75,7 +75,7 @@ public static JsonMsetArgs path(JsonPath path) { * * @return new {@link JsonGetArgs} with spacing set. */ - public static JsonMsetArgs element(JsonValue element) { + public static JsonMsetArgs element(JsonValue element) { return new JsonMsetArgs().element(element); } @@ -108,7 +108,7 @@ public JsonMsetArgs path(JsonPath path) { * * @return {@code this}. */ - public JsonMsetArgs element(JsonValue element) { + public JsonMsetArgs element(JsonValue element) { this.element = element; return this; @@ -126,7 +126,7 @@ public void build(CommandArgs args) { } if (element != null) { - args.add(element.toString()); + args.add(element.asByteBuffer().array()); } } diff --git a/src/main/java/io/lettuce/core/json/arguments/JsonRangeArgs.java b/src/main/java/io/lettuce/core/json/arguments/JsonRangeArgs.java index bdb4785d8f..ab82e83937 100644 --- a/src/main/java/io/lettuce/core/json/arguments/JsonRangeArgs.java +++ b/src/main/java/io/lettuce/core/json/arguments/JsonRangeArgs.java @@ -36,6 +36,16 @@ */ public class JsonRangeArgs implements CompositeArgument { + /** + * Default start index to indicate where to start slicing the array + */ + public static final int DEFAULT_START_INDEX = 0; + + /** + * Default end index to indicate where to stop slicing the array + */ + public static final int DEFAULT_END_INDEX = 0; + private long start = 0; private long stop = 0; @@ -69,6 +79,17 @@ public static JsonRangeArgs stop(long stop) { return new JsonRangeArgs().stop(stop); } + /** + * Creates new {@link JsonRangeArgs} and sets default values. + *

+ * The default start index is 0 and the default end index is 0. + * + * @return new {@link JsonRangeArgs} with the end index set. + */ + public static JsonRangeArgs defaults() { + return new JsonRangeArgs(); + } + } /** @@ -96,11 +117,11 @@ public JsonRangeArgs stop(long stop) { @Override public void build(CommandArgs args) { - if (start != 0) { + if (start != DEFAULT_START_INDEX || stop != DEFAULT_END_INDEX) { args.add(start); } - if (stop != 0) { + if (stop != DEFAULT_END_INDEX) { args.add(stop); } } diff --git a/src/main/java/io/lettuce/core/masterslave/MasterSlaveConnectionWrapper.java b/src/main/java/io/lettuce/core/masterslave/MasterSlaveConnectionWrapper.java index 5684bab304..9594f391b4 100644 --- a/src/main/java/io/lettuce/core/masterslave/MasterSlaveConnectionWrapper.java +++ b/src/main/java/io/lettuce/core/masterslave/MasterSlaveConnectionWrapper.java @@ -80,16 +80,6 @@ public void removeListener(PushListener listener) { delegate.removeListener(listener); } - @Override - public JsonParser getJsonParser() { - return delegate.getJsonParser(); - } - - @Override - public void setJsonParser(JsonParser jsonParser) { - delegate.setJsonParser(jsonParser); - } - @Override public void setTimeout(Duration timeout) { delegate.setTimeout(timeout); diff --git a/src/main/java/io/lettuce/core/protocol/CommandType.java b/src/main/java/io/lettuce/core/protocol/CommandType.java index 7bab4c10d8..7eb949e5d3 100644 --- a/src/main/java/io/lettuce/core/protocol/CommandType.java +++ b/src/main/java/io/lettuce/core/protocol/CommandType.java @@ -106,7 +106,7 @@ public enum CommandType implements ProtocolKeyword { // JSON JSON_ARRAPPEND("JSON.ARRAPPEND"), JSON_ARRINDEX("JSON.ARRINDEX"), JSON_ARRINSERT("JSON.ARRINSERT"), JSON_ARRLEN( - "JSON.ARRLEN"), JSON_ARRPOP("JSON.ARRPOP"), JSON_ARRTRIM("JSON.ARRAPPEND"), JSON_CLEAR("JSON.CLEAR"), JSON_DEL( + "JSON.ARRLEN"), JSON_ARRPOP("JSON.ARRPOP"), JSON_ARRTRIM("JSON.ARRTRIM"), JSON_CLEAR("JSON.CLEAR"), JSON_DEL( "JSON.DEL"), JSON_GET("JSON.GET"), JSON_MERGE("JSON.MERGE"), JSON_MGET("JSON.MGET"), JSON_MSET( "JSON.MSET"), JSON_NUMINCRBY("JSON.NUMINCRBY"), JSON_OBJKEYS("JSON.OBJKEYS"), JSON_OBJLEN( "JSON.OBJLEN"), JSON_SET("JSON.SET"), JSON_STRAPPEND("JSON.STRAPPEND"), JSON_STRLEN( diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisJsonCoroutinesCommands.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisJsonCoroutinesCommands.kt index addfafe5c3..74b41c01dd 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisJsonCoroutinesCommands.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisJsonCoroutinesCommands.kt @@ -201,10 +201,10 @@ interface RedisJsonCoroutinesCommands { * A JSON value is a hierarchical structure. If you change a value in a specific path - nested values are affected. * * @param arguments the [JsonMsetArgs] specifying the values to change. - * @return Boolean true if the merge was successful, false otherwise. + * @return "OK" if the operation was successful, error otherwise * @since 6.5 */ - suspend fun jsonMSet(vararg arguments: JsonMsetArgs): Boolean? + suspend fun jsonMSet(vararg arguments: JsonMsetArgs): String? /** * Increment the number value stored at the specified [JsonPath] in the JSON document by the provided increment. @@ -222,10 +222,10 @@ interface RedisJsonCoroutinesCommands { * * @param key the key holding the JSON document. * @param jsonPath the [JsonPath] pointing to the value(s) whose key(s) we want. - * @return List the keys in the JSON document that are referenced by the given [JsonPath]. + * @return List the keys in the JSON document that are referenced by the given [JsonPath]. * @since 6.5 */ - suspend fun jsonObjkeys(key: K, jsonPath: JsonPath): List> + suspend fun jsonObjkeys(key: K, jsonPath: JsonPath): List /** * Report the number of keys in the JSON object at path in key @@ -284,10 +284,10 @@ interface RedisJsonCoroutinesCommands { * * @param key the key holding the JSON document. * @param jsonPath the [JsonPath] pointing to the value(s). - * @return List the new value after the toggle, or null if the path does not exist. + * @return List the new value after the toggle, 0 for false, 1 for true or null if the path does not exist. * @since 6.5 */ - suspend fun jsonToggle(key: K, jsonPath: JsonPath): List + suspend fun jsonToggle(key: K, jsonPath: JsonPath): List /** * Report the type of JSON value at the provided [JsonPath] in the JSON document. diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisJsonCoroutinesCommandsImpl.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisJsonCoroutinesCommandsImpl.kt index 1374db9284..787f540d37 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisJsonCoroutinesCommandsImpl.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisJsonCoroutinesCommandsImpl.kt @@ -89,13 +89,13 @@ internal class RedisJsonCoroutinesCommandsImpl(internal val op override suspend fun jsonMGet(jsonPath: JsonPath, vararg keys: K): List> = ops.jsonMGet(jsonPath, *keys).asFlow().toList() - override suspend fun jsonMSet(vararg arguments: JsonMsetArgs): Boolean? = + override suspend fun jsonMSet(vararg arguments: JsonMsetArgs): String? = ops.jsonMSet(*arguments).awaitFirstOrNull() override suspend fun jsonType(key: K, jsonPath: JsonPath): List = ops.jsonType(key, jsonPath).asFlow().toList() - override suspend fun jsonToggle(key: K, jsonPath: JsonPath): List = + override suspend fun jsonToggle(key: K, jsonPath: JsonPath): List = ops.jsonToggle(key, jsonPath).asFlow().toList() override suspend fun jsonStrlen(key: K, jsonPath: JsonPath): List = @@ -110,7 +110,7 @@ internal class RedisJsonCoroutinesCommandsImpl(internal val op override suspend fun jsonObjlen(key: K, jsonPath: JsonPath): List = ops.jsonObjlen(key, jsonPath).asFlow().toList() - override suspend fun jsonObjkeys(key: K, jsonPath: JsonPath): List> = + override suspend fun jsonObjkeys(key: K, jsonPath: JsonPath): List = ops.jsonObjkeys(key, jsonPath).asFlow().toList() override suspend fun jsonNumincrby(key: K, jsonPath: JsonPath, number: Number): List = diff --git a/src/main/templates/io/lettuce/core/api/RedisJsonCommands.java b/src/main/templates/io/lettuce/core/api/RedisJsonCommands.java index cef5e633a0..e29d01f98b 100644 --- a/src/main/templates/io/lettuce/core/api/RedisJsonCommands.java +++ b/src/main/templates/io/lettuce/core/api/RedisJsonCommands.java @@ -198,10 +198,10 @@ public interface RedisJsonCommands { * A JSON value is a hierarchical structure. If you change a value in a specific path - nested values are affected. * * @param arguments the {@link JsonMsetArgs} specifying the values to change. - * @return Boolean true if the merge was successful, false otherwise. + * @return "OK" if the operation was successful, error otherwise * @since 6.5 */ - Boolean jsonMSet(JsonMsetArgs... arguments); + String jsonMSet(JsonMsetArgs... arguments); /** * Increment the number value stored at the specified {@link JsonPath} in the JSON document by the provided increment. @@ -219,10 +219,10 @@ public interface RedisJsonCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s) whose key(s) we want. - * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. + * @return List the keys in the JSON document that are referenced by the given {@link JsonPath}. * @since 6.5 */ - List> jsonObjkeys(K key, JsonPath jsonPath); + List jsonObjkeys(K key, JsonPath jsonPath); /** * Report the number of keys in the JSON object at path in key @@ -281,10 +281,10 @@ public interface RedisJsonCommands { * * @param key the key holding the JSON document. * @param jsonPath the {@link JsonPath} pointing to the value(s). - * @return List the new value after the toggle, or null if the path does not exist. + * @return List the new value after the toggle, 0 for false, 1 for true or null if the path does not exist. * @since 6.5 */ - List jsonToggle(K key, JsonPath jsonPath); + List jsonToggle(K key, JsonPath jsonPath); /** * Report the type of JSON value at the provided {@link JsonPath} in the JSON document. diff --git a/src/test/java/io/lettuce/core/RedisContainerIntegrationTests.java b/src/test/java/io/lettuce/core/RedisContainerIntegrationTests.java index 1aebbfb73b..52bba199ad 100644 --- a/src/test/java/io/lettuce/core/RedisContainerIntegrationTests.java +++ b/src/test/java/io/lettuce/core/RedisContainerIntegrationTests.java @@ -36,8 +36,8 @@ public class RedisContainerIntegrationTests { @BeforeAll static void setup() { - RedisURI redisURI = RedisURI.Builder.redis("redis-19897.c55.eu-central-1-1.ec2.redns.redis-cloud.com").withPort(19897) - .withPassword("9CH6niJKjHFzAiPtp9jvoI9OvErZ7urh").withTimeout(Duration.ofSeconds(30)).build(); + RedisURI redisURI = RedisURI.Builder.redis("").withPort(19897) + .withPassword("").withTimeout(Duration.ofSeconds(30)).build(); redisClient = RedisClient.create(redisURI); StatefulRedisConnection connect = redisClient.connect(); redis = connect.async(); @@ -45,8 +45,10 @@ static void setup() { @AfterAll static void teardown() { - redis.getStatefulConnection().close(); - redisClient.shutdown(); + if (redis != null) + redis.getStatefulConnection().close(); + if (redisClient != null) + redisClient.shutdown(); } } diff --git a/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java b/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java index f6ffe73ae9..3c1b6424d4 100644 --- a/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java @@ -1,9 +1,14 @@ package io.lettuce.core; import io.lettuce.core.codec.StringCodec; +import io.lettuce.core.json.JsonParser; import io.lettuce.core.json.JsonValue; import io.lettuce.core.json.JsonParserRegistry; import io.lettuce.core.json.JsonPath; +import io.lettuce.core.json.arguments.JsonGetArgs; +import io.lettuce.core.json.arguments.JsonMsetArgs; +import io.lettuce.core.json.arguments.JsonRangeArgs; +import io.lettuce.core.json.arguments.JsonSetArgs; import io.lettuce.core.protocol.Command; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -23,40 +28,231 @@ class RedisJsonCommandBuilderUnitTests { public static final String MY_KEY = "bikes:inventory"; + public static final String MY_KEY2 = "bikes:repairLog"; + + public static final String ID_BIKE_6 = "{\"id\":\"bike6\"}"; + + public static final JsonParser PARSER = JsonParserRegistry.getJsonParser(StringCodec.UTF8); + + public static final JsonValue ELEMENT = PARSER.createJsonValue(ID_BIKE_6); + + public static final JsonPath MY_PATH = JsonPath.of("$..commuter_bikes"); + RedisJsonCommandBuilder builder = new RedisJsonCommandBuilder<>(StringCodec.UTF8); @Test void shouldCorrectlyConstructJsonArrappend() { - - final JsonPath myPath = JsonPath.of("$..commuter_bikes"); - JsonValue element = JsonParserRegistry.getJsonParser(StringCodec.UTF8).createJsonValue("{id:bike6}"); - Command> command = builder.jsonArrappend(MY_KEY, myPath, new JsonValue[] { element }); + Command> command = builder.jsonArrappend(MY_KEY, MY_PATH, ELEMENT); ByteBuf buf = Unpooled.directBuffer(); command.encode(buf); assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*4\r\n" + "$14\r\n" + "JSON.ARRAPPEND\r\n" + "$15\r\n" - + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n" + "$10\r\n" + "{id:bike6}" + "\r\n"); + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n" + "$14\r\n" + ID_BIKE_6 + "\r\n"); } @Test - void shouldCorrectlyConstructJsonType() { + void shouldCorrectlyConstructJsonArrindex() { + JsonRangeArgs range = JsonRangeArgs.Builder.start(0).stop(1); + Command> command = builder.jsonArrindex(MY_KEY, MY_PATH, ELEMENT, range); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); - final JsonPath myPath = JsonPath.of("$..commuter_bikes"); + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*6\r\n" + "$13\r\n" + "JSON.ARRINDEX\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n" + "$14\r\n" + ID_BIKE_6 + "\r\n" + "$1" + "\r\n" + + "0" + "\r\n" + "$1" + "\r\n" + "1" + "\r\n"); + } - Command command = builder.jsonType(MY_KEY, myPath); + @Test + void shouldCorrectlyConstructJsonArrinsert() { + Command> command = builder.jsonArrinsert(MY_KEY, MY_PATH, 1, ELEMENT); ByteBuf buf = Unpooled.directBuffer(); command.encode(buf); - assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*3\r\n" + "$9\r\n" + "JSON.TYPE\r\n" + "$15\r\n" + assertThat(buf.toString(StandardCharsets.UTF_8)) + .isEqualTo("*5\r\n" + "$14\r\n" + "JSON.ARRINSERT\r\n" + "$15\r\n" + "bikes:inventory\r\n" + "$17\r\n" + + "$..commuter_bikes\r\n" + "$1" + "\r\n" + "1" + "\r\n" + "$14\r\n" + ID_BIKE_6 + "\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonArrlen() { + Command> command = builder.jsonArrlen(MY_KEY, MY_PATH); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*3\r\n" + "$11\r\n" + "JSON.ARRLEN\r\n" + "$15\r\n" + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n"); } @Test - void shouldCorrectlyConstructJsonTypeRootPath() { + void shouldCorrectlyConstructJsonArrpop() { + Command>> command = builder.jsonArrpop(MY_KEY, MY_PATH, 3); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*4\r\n" + "$11\r\n" + "JSON.ARRPOP\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n" + "$1" + "\r\n" + "3" + "\r\n"); + } - final JsonPath myPath = JsonPath.ROOT_PATH; + @Test + void shouldCorrectlyConstructJsonArrtrim() { + JsonRangeArgs range = JsonRangeArgs.Builder.start(0).stop(1); + Command> command = builder.jsonArrtrim(MY_KEY, MY_PATH, range); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)) + .isEqualTo("*5\r\n" + "$12\r\n" + "JSON.ARRTRIM\r\n" + "$15\r\n" + "bikes:inventory\r\n" + "$17\r\n" + + "$..commuter_bikes\r\n" + "$1" + "\r\n" + "0" + "\r\n" + "$1" + "\r\n" + "1" + "\r\n"); + } - Command command = builder.jsonType(MY_KEY, myPath); + @Test + void shouldCorrectlyConstructJsonClear() { + Command command = builder.jsonClear(MY_KEY, MY_PATH); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*3\r\n" + "$10\r\n" + "JSON.CLEAR\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonGet() { + JsonGetArgs args = JsonGetArgs.Builder.indent(" ").newline("\n").space("/"); + Command>> command = builder.jsonGet(MY_KEY, args, MY_PATH); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*9\r\n" + "$8\r\n" + "JSON.GET\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$6\r\n" + "INDENT\r\n" + "$3\r\n" + " \r\n" + "$7\r\n" + "NEWLINE\r\n" + "$1\r\n" + + "\n\r\n" + "$5\r\n" + "SPACE\r\n" + "$1\r\n" + "/\r\n" + "$17\r\n" + "$..commuter_bikes\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonMerge() { + Command command = builder.jsonMerge(MY_KEY, MY_PATH, ELEMENT); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*4\r\n" + "$10\r\n" + "JSON.MERGE\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n" + "$14\r\n" + ID_BIKE_6 + "\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonMget() { + Command>> command = builder.jsonMGet(MY_PATH, MY_KEY, MY_KEY2); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*4\r\n" + "$9\r\n" + "JSON.MGET\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$15\r\n" + "bikes:repairLog\r\n" + "$17\r\n" + "$..commuter_bikes\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonMset() { + Command command = builder + .jsonMSet(JsonMsetArgs.Builder.element(ELEMENT).key(MY_KEY).path(MY_PATH)); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*4\r\n" + "$9\r\n" + "JSON.MSET\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n" + "$14\r\n" + ID_BIKE_6 + "\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonNumincrby() { + Command> command = builder.jsonNumincrby(MY_KEY, MY_PATH, 3); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*4\r\n" + "$14\r\n" + "JSON.NUMINCRBY\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n" + "$1" + "\r\n" + "3" + "\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonObjkeys() { + Command> command = builder.jsonObjkeys(MY_KEY, MY_PATH); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*3\r\n" + "$12\r\n" + "JSON.OBJKEYS\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonObjlen() { + Command> command = builder.jsonObjlen(MY_KEY, MY_PATH); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*3\r\n" + "$11\r\n" + "JSON.OBJLEN\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonSet() { + JsonSetArgs args = JsonSetArgs.Builder.nx(); + Command command = builder.jsonSet(MY_KEY, MY_PATH, ELEMENT, args); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)) + .isEqualTo("*5\r\n" + "$8\r\n" + "JSON.SET\r\n" + "$15\r\n" + "bikes:inventory\r\n" + "$17\r\n" + + "$..commuter_bikes\r\n" + "$14\r\n" + ID_BIKE_6 + "\r\n" + "$2\r\n" + "NX\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonStrappend() { + Command> command = builder.jsonStrappend(MY_KEY, MY_PATH, ELEMENT); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*4\r\n" + "$14\r\n" + "JSON.STRAPPEND\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n" + "$14\r\n" + ID_BIKE_6 + "\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonStrlen() { + Command> command = builder.jsonStrlen(MY_KEY, MY_PATH); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*3\r\n" + "$11\r\n" + "JSON.STRLEN\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonToggle() { + Command> command = builder.jsonToggle(MY_KEY, MY_PATH); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*3\r\n" + "$11\r\n" + "JSON.TOGGLE\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonDel() { + Command command = builder.jsonDel(MY_KEY, MY_PATH); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo( + "*3\r\n" + "$8\r\n" + "JSON.DEL\r\n" + "$15\r\n" + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonType() { + Command command = builder.jsonType(MY_KEY, MY_PATH); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*3\r\n" + "$9\r\n" + "JSON.TYPE\r\n" + "$15\r\n" + + "bikes:inventory\r\n" + "$17\r\n" + "$..commuter_bikes\r\n"); + } + + @Test + void shouldCorrectlyConstructJsonTypeRootPath() { + Command command = builder.jsonType(MY_KEY, JsonPath.ROOT_PATH); ByteBuf buf = Unpooled.directBuffer(); command.encode(buf); diff --git a/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java b/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java index d8965c3e49..3e0c4b9333 100644 --- a/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java +++ b/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java @@ -41,7 +41,7 @@ public class RedisJsonIntegrationTests extends RedisContainerIntegrationTests { @Test void jsonArrappend() throws ExecutionException, InterruptedException { - JsonParser parser = redis.getStatefulConnection().getJsonParser(); + JsonParser parser = redis.getJsonParser(); JsonValue element = parser.createJsonValue("\"{id:bike6}\""); List appendedElements = redis.jsonArrappend(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, element).get(); @@ -57,11 +57,10 @@ void jsonArrappend() throws ExecutionException, InterruptedException { @Test void jsonArrindex() throws ExecutionException, InterruptedException { - JsonRangeArgs range = JsonRangeArgs.Builder.start(1).stop(4); - JsonParser parser = redis.getStatefulConnection().getJsonParser(); - JsonValue element = parser.createJsonValue("\"{id:bike3}\""); + JsonParser parser = redis.getJsonParser(); + JsonValue element = parser.createJsonValue("\"{id:bike6}\""); - List arrayIndex = redis.jsonArrindex(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, element, range).get(); + List arrayIndex = redis.jsonArrindex(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, element, null).get(); assertThat(arrayIndex).isNotNull(); assertThat(arrayIndex.get(0).longValue()).isEqualTo(3L); } @@ -163,7 +162,7 @@ void jsonObjlen() throws ExecutionException, InterruptedException { @Test void jsonSet() throws ExecutionException, InterruptedException { - JsonParser parser = redis.getStatefulConnection().getJsonParser(); + JsonParser parser = redis.getJsonParser(); JsonObject bikeRecord = parser.createEmptyJsonObject(); JsonObject bikeSpecs = parser.createEmptyJsonObject(); JsonArray bikeColors = parser.createEmptyJsonArray();