From 948306360ceaab057785e08444510b51310a5c5a Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Wed, 9 Aug 2023 11:50:10 +0600 Subject: [PATCH 01/23] Support TOPK.LIST with WITHCOUNT option (#3495) --- .../redis/clients/jedis/BuilderFactory.java | 31 +++++++++++++++++++ .../redis/clients/jedis/CommandObjects.java | 5 +++ .../redis/clients/jedis/PipelineBase.java | 5 +++ .../redis/clients/jedis/TransactionBase.java | 5 +++ .../redis/clients/jedis/UnifiedJedis.java | 5 +++ .../jedis/bloom/RedisBloomProtocol.java | 2 +- .../bloom/commands/TopKFilterCommands.java | 21 +++++++++++++ .../commands/TopKFilterPipelineCommands.java | 2 ++ .../clients/jedis/modules/bloom/TopKTest.java | 21 +++++++++---- 9 files changed, 90 insertions(+), 7 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 46ce255c35..5e5d03a830 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -415,6 +415,37 @@ public String toString() { } }; + public static final Builder> STRING_LONG_MAP = new Builder>() { + @Override + @SuppressWarnings("unchecked") + public Map build(Object data) { + final List list = (List) data; + if (list.isEmpty()) return Collections.emptyMap(); + + if (list.get(0) instanceof KeyValue) { + final Map map = new LinkedHashMap<>(list.size(), 1f); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + KeyValue kv = (KeyValue) iterator.next(); + map.put(STRING.build(kv.getKey()), LONG.build(kv.getValue())); + } + return map; + } else { + final Map map = new LinkedHashMap<>(list.size() / 2, 1f); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + map.put(STRING.build(iterator.next()), LONG.build(iterator.next())); + } + return map; + } + } + + @Override + public String toString() { + return "Map"; + } + }; + public static final Builder> KEYED_ELEMENT = new Builder>() { @Override @SuppressWarnings("unchecked") diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index d3d77db3b4..60031520a2 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -4056,6 +4056,11 @@ public final CommandObject> topkList(String key) { return new CommandObject<>(commandArguments(TopKCommand.LIST).key(key), BuilderFactory.STRING_LIST); } + public final CommandObject> topkListWithCount(String key) { + return new CommandObject<>(commandArguments(TopKCommand.LIST).key(key) + .add(RedisBloomKeyword.WITHCOUNT), BuilderFactory.STRING_LONG_MAP); + } + public final CommandObject> topkInfo(String key) { return new CommandObject<>(commandArguments(TopKCommand.INFO).key(key), BuilderFactory.ENCODED_OBJECT_MAP); } diff --git a/src/main/java/redis/clients/jedis/PipelineBase.java b/src/main/java/redis/clients/jedis/PipelineBase.java index f7ebe3eb50..4511bfa8a5 100644 --- a/src/main/java/redis/clients/jedis/PipelineBase.java +++ b/src/main/java/redis/clients/jedis/PipelineBase.java @@ -4059,6 +4059,11 @@ public Response> topkList(String key) { return appendCommand(commandObjects.topkList(key)); } + @Override + public Response> topkListWithCount(String key) { + return appendCommand(commandObjects.topkListWithCount(key)); + } + @Override public Response> topkInfo(String key) { return appendCommand(commandObjects.topkInfo(key)); diff --git a/src/main/java/redis/clients/jedis/TransactionBase.java b/src/main/java/redis/clients/jedis/TransactionBase.java index f6a21560ee..2baf02f5c1 100644 --- a/src/main/java/redis/clients/jedis/TransactionBase.java +++ b/src/main/java/redis/clients/jedis/TransactionBase.java @@ -4227,6 +4227,11 @@ public Response> topkList(String key) { return appendCommand(commandObjects.topkList(key)); } + @Override + public Response> topkListWithCount(String key) { + return appendCommand(commandObjects.topkListWithCount(key)); + } + @Override public Response> topkInfo(String key) { return appendCommand(commandObjects.topkInfo(key)); diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index acf6ad7dfd..bf2481f712 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -4583,6 +4583,11 @@ public List topkList(String key) { return executeCommand(commandObjects.topkList(key)); } + @Override + public Map topkListWithCount(String key) { + return executeCommand(commandObjects.topkListWithCount(key)); + } + @Override public Map topkInfo(String key) { return executeCommand(commandObjects.topkInfo(key)); diff --git a/src/main/java/redis/clients/jedis/bloom/RedisBloomProtocol.java b/src/main/java/redis/clients/jedis/bloom/RedisBloomProtocol.java index 7e7bb810f2..c60b9fcc4a 100644 --- a/src/main/java/redis/clients/jedis/bloom/RedisBloomProtocol.java +++ b/src/main/java/redis/clients/jedis/bloom/RedisBloomProtocol.java @@ -120,7 +120,7 @@ public byte[] getRaw() { public enum RedisBloomKeyword implements Rawable { CAPACITY, ERROR, NOCREATE, EXPANSION, NONSCALING, BUCKETSIZE, MAXITERATIONS, ITEMS, WEIGHTS, - COMPRESSION, OVERRIDE; + COMPRESSION, OVERRIDE, WITHCOUNT; private final byte[] raw; diff --git a/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterCommands.java b/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterCommands.java index 6cc2f47b43..d16e31a72f 100644 --- a/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterCommands.java +++ b/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterCommands.java @@ -1,5 +1,6 @@ package redis.clients.jedis.bloom.commands; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -35,6 +36,18 @@ public interface TopKFilterCommands { */ List topkAdd(String key, String... items); + /** + * {@code TOPK.INCRBY {key} {item} {increment}} + * + * @param key + * @param item + * @param increment + * @return item dropped from list + */ + default String topkIncrBy(String key, String item, long increment) { + return topkIncrBy(key, Collections.singletonMap(item, increment)).get(0); + } + /** * {@code TOPK.INCRBY {key} {item} {increment} [{item} {increment} ...]} * @@ -61,6 +74,14 @@ public interface TopKFilterCommands { */ List topkList(String key); + /** + * {@code TOPK.LIST {key} WITHCOUNT} + * + * @param key + * @return k (or less) items in Top K list + */ + Map topkListWithCount(String key); + /** * {@code TOPK.INFO {key}} * diff --git a/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterPipelineCommands.java b/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterPipelineCommands.java index 692e02d3c9..d75b3d7447 100644 --- a/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterPipelineCommands.java +++ b/src/main/java/redis/clients/jedis/bloom/commands/TopKFilterPipelineCommands.java @@ -18,5 +18,7 @@ public interface TopKFilterPipelineCommands { Response> topkList(String key); + Response> topkListWithCount(String key); + Response> topkInfo(String key); } diff --git a/src/test/java/redis/clients/jedis/modules/bloom/TopKTest.java b/src/test/java/redis/clients/jedis/modules/bloom/TopKTest.java index 1e6a38ed43..706d57ef82 100644 --- a/src/test/java/redis/clients/jedis/modules/bloom/TopKTest.java +++ b/src/test/java/redis/clients/jedis/modules/bloom/TopKTest.java @@ -1,10 +1,11 @@ package redis.clients.jedis.modules.bloom; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collections; -import java.util.TreeSet; +import java.util.Map; import org.junit.BeforeClass; import org.junit.Test; @@ -30,12 +31,20 @@ public void createTopKFilter() { assertEquals(Arrays.asList(true, false, true), client.topkQuery("aaa", "bb", "gg", "cc")); - assertEquals(new TreeSet<>(Arrays.asList("bb", "cc")), new TreeSet<>(client.topkList("aaa"))); + assertEquals(Arrays.asList("bb", "cc"), client.topkList("aaa")); -// assertEquals(null, client.topkIncrBy("aaa", "ff", 10)); - assertEquals(Collections.singletonList(null), - client.topkIncrBy("aaa", Collections.singletonMap("ff", 10L))); + Map listWithCount = client.topkListWithCount("aaa"); + assertEquals(2, listWithCount.size()); + listWithCount.forEach((item, count) -> { + assertTrue(Arrays.asList("bb", "cc").contains(item)); + assertEquals(Long.valueOf(1), count); + }); + + assertEquals(null, client.topkIncrBy("aaa", "ff", 5)); + assertEquals(Arrays.asList("ff", "bb", "cc"), client.topkList("aaa")); - assertEquals(new TreeSet<>(Arrays.asList("bb", "cc", "ff")), new TreeSet<>(client.topkList("aaa"))); + assertEquals(Collections.singletonList(null), + client.topkIncrBy("aaa", Collections.singletonMap("ff", 8L))); + assertEquals(Long.valueOf(13), client.topkListWithCount("aaa").get("ff")); } } From b7f4703f4d8992b81eea6514a5bf72f85bf2fdd4 Mon Sep 17 00:00:00 2001 From: Sergii Dotsenko <33420754+sdotsenko@users.noreply.github.com> Date: Wed, 9 Aug 2023 07:36:46 +0100 Subject: [PATCH 02/23] Fixed some typos and formatting issues across the project (#3486) Signed-off-by: Sergii Dotsenko --- README.md | 10 +++++----- src/main/java/redis/clients/jedis/StreamEntryID.java | 4 ++-- .../redis/clients/jedis/commands/ServerCommands.java | 2 +- .../redis/clients/jedis/params/MigrateParams.java | 12 ++++++------ .../java/redis/clients/jedis/params/ZAddParams.java | 12 ++++++------ .../clients/jedis/resps/AccessControlLogEntry.java | 2 +- .../clients/jedis/resps/StreamConsumerFullInfo.java | 2 +- .../clients/jedis/resps/StreamConsumerInfo.java | 2 +- .../clients/jedis/resps/StreamConsumersInfo.java | 2 +- .../redis/clients/jedis/resps/StreamFullInfo.java | 2 +- .../clients/jedis/resps/StreamGroupFullInfo.java | 2 +- .../redis/clients/jedis/resps/StreamGroupInfo.java | 2 +- .../java/redis/clients/jedis/resps/StreamInfo.java | 2 +- .../redis/clients/jedis/util/RedisInputStream.java | 4 ++-- .../java/redis/clients/jedis/ConnectionTest.java | 2 +- 15 files changed, 31 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index a1f3132641..b379424023 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,10 @@ The most recent version of this library supports redis version [5.0](https://git The table below highlights version compatibility of the most-recent library versions and Redis versions. Compatibility means communication features, and Redis command capabilities. -| Library version | Supported redis versions | -|-----------------|-------------------| -| 3.9+ | 5.0 and 6.2 Family of releases | -| >= 4.0 | Version 5.0 to current | +| Library version | Supported redis versions | +|-----------------|--------------------------------| +| 3.9+ | 5.0 and 6.2 Family of releases | +| >= 4.0 | Version 5.0 to current | ## Getting started @@ -78,7 +78,7 @@ for the complete list of supported commands. ### Easier way of using connection pool -Using a *try-with-resources* block for each command may be cumbursome, so you may consider using JedisPooled. +Using a *try-with-resources* block for each command may be cumbersome, so you may consider using JedisPooled. ```java JedisPooled jedis = new JedisPooled("localhost", 6379); diff --git a/src/main/java/redis/clients/jedis/StreamEntryID.java b/src/main/java/redis/clients/jedis/StreamEntryID.java index 66683d9038..9644010d7c 100644 --- a/src/main/java/redis/clients/jedis/StreamEntryID.java +++ b/src/main/java/redis/clients/jedis/StreamEntryID.java @@ -55,8 +55,8 @@ public int hashCode() { @Override public int compareTo(StreamEntryID other) { - int timeComapre = Long.compare(this.time, other.time); - return timeComapre != 0 ? timeComapre : Long.compare(this.sequence, other.sequence); + int timeCompare = Long.compare(this.time, other.time); + return timeCompare != 0 ? timeCompare : Long.compare(this.sequence, other.sequence); } public long getTime() { diff --git a/src/main/java/redis/clients/jedis/commands/ServerCommands.java b/src/main/java/redis/clients/jedis/commands/ServerCommands.java index d96074379b..46f1220407 100644 --- a/src/main/java/redis/clients/jedis/commands/ServerCommands.java +++ b/src/main/java/redis/clients/jedis/commands/ServerCommands.java @@ -70,7 +70,7 @@ public interface ServerCommands { * The SAVE commands performs a synchronous save of the dataset producing a point in time snapshot * of all the data inside the Redis instance, in the form of an RDB file. You almost never want to * call SAVE in production environments where it will block all the other clients. Instead usually - * BGSAVE is used. However in case of issues preventing Redis to create the background saving + * BGSAVE is used. However, in case of issues preventing Redis to create the background saving * child (for instance errors in the fork(2) system call), the SAVE command can be a good last * resort to perform the dump of the latest dataset. * @return result of the save diff --git a/src/main/java/redis/clients/jedis/params/MigrateParams.java b/src/main/java/redis/clients/jedis/params/MigrateParams.java index 3b9815e7c3..a75251e0e4 100644 --- a/src/main/java/redis/clients/jedis/params/MigrateParams.java +++ b/src/main/java/redis/clients/jedis/params/MigrateParams.java @@ -8,7 +8,7 @@ public class MigrateParams implements IParams { private boolean copy = false; private boolean replace = false; private String username = null; - private String passowrd = null; + private String password = null; public MigrateParams() { } @@ -28,13 +28,13 @@ public MigrateParams replace() { } public MigrateParams auth(String password) { - this.passowrd = password; + this.password = password; return this; } public MigrateParams auth2(String username, String password) { this.username = username; - this.passowrd = password; + this.password = password; return this; } @@ -47,9 +47,9 @@ public void addParams(CommandArguments args) { args.add(Keyword.REPLACE); } if (username != null) { - args.add(Keyword.AUTH2).add(username).add(passowrd); - } else if (passowrd != null) { - args.add(Keyword.AUTH).add(passowrd); + args.add(Keyword.AUTH2).add(username).add(password); + } else if (password != null) { + args.add(Keyword.AUTH).add(password); } } } diff --git a/src/main/java/redis/clients/jedis/params/ZAddParams.java b/src/main/java/redis/clients/jedis/params/ZAddParams.java index d00b05c23d..8194c041a6 100644 --- a/src/main/java/redis/clients/jedis/params/ZAddParams.java +++ b/src/main/java/redis/clients/jedis/params/ZAddParams.java @@ -5,7 +5,7 @@ public class ZAddParams implements IParams { - private Keyword existance; + private Keyword existence; private Keyword comparison; private boolean change; @@ -21,16 +21,16 @@ public static ZAddParams zAddParams() { * @return ZAddParams */ public ZAddParams nx() { - this.existance = Keyword.NX; + this.existence = Keyword.NX; return this; } /** - * Only set the key if it already exist. + * Only set the key if it already exists. * @return ZAddParams */ public ZAddParams xx() { - this.existance = Keyword.XX; + this.existence = Keyword.XX; return this; } @@ -64,8 +64,8 @@ public ZAddParams ch() { @Override public void addParams(CommandArguments args) { - if (existance != null) { - args.add(existance); + if (existence != null) { + args.add(existence); } if (comparison != null) { args.add(comparison); diff --git a/src/main/java/redis/clients/jedis/resps/AccessControlLogEntry.java b/src/main/java/redis/clients/jedis/resps/AccessControlLogEntry.java index 09ef3a43bb..930c9b064d 100644 --- a/src/main/java/redis/clients/jedis/resps/AccessControlLogEntry.java +++ b/src/main/java/redis/clients/jedis/resps/AccessControlLogEntry.java @@ -6,7 +6,7 @@ /** * This class holds information about an Access Control Log entry (returned by ACL LOG command) They - * can be access via getters. For future purpose there is also {@link #getlogEntry} method that + * can be accessed via getters. For future purpose there is also {@link #getlogEntry} method that * returns a generic {@code Map} - in case where more info is returned from a server */ // TODO: remove diff --git a/src/main/java/redis/clients/jedis/resps/StreamConsumerFullInfo.java b/src/main/java/redis/clients/jedis/resps/StreamConsumerFullInfo.java index 6279640888..2f57329415 100644 --- a/src/main/java/redis/clients/jedis/resps/StreamConsumerFullInfo.java +++ b/src/main/java/redis/clients/jedis/resps/StreamConsumerFullInfo.java @@ -7,7 +7,7 @@ /** * This class holds information about a stream consumer with command - * {@code xinfo stream mystream full}. They can be access via getters. There is also + * {@code xinfo stream mystream full}. They can be accessed via getters. There is also * {@link StreamConsumerFullInfo#getConsumerInfo()} method that returns a generic {@link Map} in * case more info are returned from the server. */ diff --git a/src/main/java/redis/clients/jedis/resps/StreamConsumerInfo.java b/src/main/java/redis/clients/jedis/resps/StreamConsumerInfo.java index 63b417780e..0bf5a46250 100644 --- a/src/main/java/redis/clients/jedis/resps/StreamConsumerInfo.java +++ b/src/main/java/redis/clients/jedis/resps/StreamConsumerInfo.java @@ -3,7 +3,7 @@ import java.util.Map; /** - * This class holds information about a consumer. They can be access via getters. There is also + * This class holds information about a consumer. They can be accessed via getters. There is also * {@link StreamConsumersInfo#getConsumerInfo()}} method that returns a generic {@code Map} in case * more info are returned from the server. */ diff --git a/src/main/java/redis/clients/jedis/resps/StreamConsumersInfo.java b/src/main/java/redis/clients/jedis/resps/StreamConsumersInfo.java index ad12f0353b..4b12a95006 100644 --- a/src/main/java/redis/clients/jedis/resps/StreamConsumersInfo.java +++ b/src/main/java/redis/clients/jedis/resps/StreamConsumersInfo.java @@ -3,7 +3,7 @@ import java.util.Map; /** - * This class holds information about a consumer. They can be access via getters. There is also + * This class holds information about a consumer. They can be accessed via getters. There is also * {@link StreamConsumersInfo#getConsumerInfo()}} method that returns a generic {@code Map} in case * more info are returned from the server. * @deprecated Use {@link StreamConsumerInfo}. diff --git a/src/main/java/redis/clients/jedis/resps/StreamFullInfo.java b/src/main/java/redis/clients/jedis/resps/StreamFullInfo.java index 336bf9c9c2..e768b536b8 100644 --- a/src/main/java/redis/clients/jedis/resps/StreamFullInfo.java +++ b/src/main/java/redis/clients/jedis/resps/StreamFullInfo.java @@ -8,7 +8,7 @@ /** * This class holds information about a stream info with command {@code xinfo stream mystream full}. - * They can be access via getters. There is also {@link StreamFullInfo#getStreamFullInfo()} method + * They can be accessed via getters. There is also {@link StreamFullInfo#getStreamFullInfo()} method * that returns a generic {@link Map} in case where more info are returned from the server. */ public class StreamFullInfo implements Serializable { diff --git a/src/main/java/redis/clients/jedis/resps/StreamGroupFullInfo.java b/src/main/java/redis/clients/jedis/resps/StreamGroupFullInfo.java index 8472c6b7b6..8354c86815 100644 --- a/src/main/java/redis/clients/jedis/resps/StreamGroupFullInfo.java +++ b/src/main/java/redis/clients/jedis/resps/StreamGroupFullInfo.java @@ -8,7 +8,7 @@ /** * This class holds information about a stream group with command {@code xinfo stream mystream full}. - * They can be access via getters. There is also {@link StreamGroupFullInfo#getGroupFullInfo()} + * They can be accessed via getters. There is also {@link StreamGroupFullInfo#getGroupFullInfo()} * method that returns a generic {@link Map} in case more info are returned from the server. */ public class StreamGroupFullInfo implements Serializable { diff --git a/src/main/java/redis/clients/jedis/resps/StreamGroupInfo.java b/src/main/java/redis/clients/jedis/resps/StreamGroupInfo.java index d017701142..0531bb8fb5 100644 --- a/src/main/java/redis/clients/jedis/resps/StreamGroupInfo.java +++ b/src/main/java/redis/clients/jedis/resps/StreamGroupInfo.java @@ -5,7 +5,7 @@ import redis.clients.jedis.StreamEntryID; /** - * This class holds information about a stream group. They can be access via getters. There is also + * This class holds information about a stream group. They can be accessed via getters. There is also * {@link StreamGroupInfo#getGroupInfo()} method that returns a generic {@code Map} in case more * info are returned from the server. */ diff --git a/src/main/java/redis/clients/jedis/resps/StreamInfo.java b/src/main/java/redis/clients/jedis/resps/StreamInfo.java index 39e65b1202..a866f41e4c 100644 --- a/src/main/java/redis/clients/jedis/resps/StreamInfo.java +++ b/src/main/java/redis/clients/jedis/resps/StreamInfo.java @@ -5,7 +5,7 @@ import redis.clients.jedis.StreamEntryID; /** - * This class holds information about stream. They can be access via getters. There is also + * This class holds information about stream. They can be accessed via getters. There is also * {@link StreamInfo#getStreamInfo} method that returns a generic {@code Map} in case more info are * returned from the server. */ diff --git a/src/main/java/redis/clients/jedis/util/RedisInputStream.java b/src/main/java/redis/clients/jedis/util/RedisInputStream.java index 57734cffdb..a0dad9d437 100644 --- a/src/main/java/redis/clients/jedis/util/RedisInputStream.java +++ b/src/main/java/redis/clients/jedis/util/RedisInputStream.java @@ -128,7 +128,7 @@ public byte[] readLineBytes() { /** * Slow path in case a line of bytes cannot be read in one #fill() operation. This is still faster - * than creating the StrinbBuilder, String, then encoding as byte[] in Protocol, then decoding + * than creating the StringBuilder, String, then encoding as byte[] in Protocol, then decoding * back into a String. */ private byte[] readLineBytesSlowly() { @@ -236,7 +236,7 @@ public int read(byte[] b, int off, int len) throws JedisConnectionException { } /** - * This methods assumes there are required bytes to be read. If we cannot read anymore bytes an + * This method assumes there are required bytes to be read. If we cannot read anymore bytes an * exception is thrown to quickly ascertain that the stream was smaller than expected. */ private void ensureFill() throws JedisConnectionException { diff --git a/src/test/java/redis/clients/jedis/ConnectionTest.java b/src/test/java/redis/clients/jedis/ConnectionTest.java index ee9a0a9742..28eba8100c 100644 --- a/src/test/java/redis/clients/jedis/ConnectionTest.java +++ b/src/test/java/redis/clients/jedis/ConnectionTest.java @@ -17,7 +17,7 @@ public void tearDown() throws Exception { } @Test(expected = JedisConnectionException.class) - public void checkUnkownHost() { + public void checkUnknownHost() { client = new Connection("someunknownhost", Protocol.DEFAULT_PORT); client.connect(); } From 73023c575124408f45df244bbc0caae00ca42f69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 12:41:52 +0600 Subject: [PATCH 03/23] Bump json from 20230227 to 20230618 (#3472) Bumps [json](https://github.com/douglascrockford/JSON-java) from 20230227 to 20230618. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/commits) --- updated-dependencies: - dependency-name: org.json:json dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f2995791da..ecd22f14d5 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ org.json json - 20230227 + 20230618 com.google.code.gson From 80b880a3c0fb6ec28472b4829df2d2e326933d76 Mon Sep 17 00:00:00 2001 From: Oscar Besga Arcauz Date: Wed, 9 Aug 2023 10:03:48 +0200 Subject: [PATCH 04/23] Compatible JDK for JEDIS libraries in README (minor) (#3478) Co-authored-by: Chayim --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b379424023..21abd49869 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,11 @@ The most recent version of this library supports redis version [5.0](https://git The table below highlights version compatibility of the most-recent library versions and Redis versions. Compatibility means communication features, and Redis command capabilities. -| Library version | Supported redis versions | -|-----------------|--------------------------------| -| 3.9+ | 5.0 and 6.2 Family of releases | -| >= 4.0 | Version 5.0 to current | + +| Library version | Supported redis versions | JDK Compatibility | +|-----------------|-------------------|-------------------| +| 3.9+ | 5.0 and 6.2 Family of releases | 8, 11 | +| >= 4.0 | Version 5.0 to current | 8, 11, 17 | ## Getting started From ba63cf22649383ed6685789f0b9336b49cdc4b93 Mon Sep 17 00:00:00 2001 From: Chayim Date: Thu, 10 Aug 2023 14:24:02 +0300 Subject: [PATCH 05/23] Updating client license to clear, MIT (#3496) * Updating all client licenses to clearly be MIT * Update LICENSE Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> --- LICENSE | 21 +++++++++++++++++++++ LICENSE.txt | 22 ---------------------- 2 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 LICENSE delete mode 100644 LICENSE.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..15c4dd523a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2023, Redis, inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 7b8b1cee63..0000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2010 Jonathan Leibiusky - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file From 5792218e87ba196d6960497a9ea5e33e598ba53f Mon Sep 17 00:00:00 2001 From: Sergii Dotsenko <33420754+sdotsenko@users.noreply.github.com> Date: Fri, 11 Aug 2023 15:28:28 +0100 Subject: [PATCH 06/23] Fixed few typos and grammar issues across the project (#3497) as title says, few more minor typo and grammar issues I have found while was reading the code also, pom.xml links have been updated, as license link is not valid after #3496 --- Signed-off-by: Sergii Dotsenko Co-authored-by: Sergii Dotsenko --- README.md | 8 +-- docs/failover.md | 2 +- pom.xml | 6 +-- src/main/java/redis/clients/jedis/Jedis.java | 54 +++++++++---------- .../clients/jedis/JedisSentinelPool.java | 8 +-- .../jedis/commands/ClientBinaryCommands.java | 8 +-- .../jedis/commands/ClientCommands.java | 8 +-- .../jedis/commands/ClusterCommands.java | 4 +- .../jedis/commands/StreamCommands.java | 4 +- .../commands/StreamPipelineCommands.java | 4 +- .../jedis/commands/StringCommands.java | 18 +++---- .../redis/clients/jedis/graph/Record.java | 2 +- .../clients/jedis/graph/ResultSetBuilder.java | 2 +- .../jedis/search/querybuilder/Node.java | 2 +- .../redis/clients/jedis/ACLJedisPoolTest.java | 6 +-- .../redis/clients/jedis/JedisPoolTest.java | 2 +- 16 files changed, 69 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 21abd49869..f0a5d6ae61 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,10 @@ The most recent version of this library supports redis version [5.0](https://git The table below highlights version compatibility of the most-recent library versions and Redis versions. Compatibility means communication features, and Redis command capabilities. -| Library version | Supported redis versions | JDK Compatibility | -|-----------------|-------------------|-------------------| -| 3.9+ | 5.0 and 6.2 Family of releases | 8, 11 | -| >= 4.0 | Version 5.0 to current | 8, 11, 17 | +| Library version | Supported redis versions | JDK Compatibility | +|-----------------|--------------------------------|-------------------| +| 3.9+ | 5.0 and 6.2 Family of releases | 8, 11 | +| >= 4.0 | Version 5.0 to current | 8, 11, 17 | ## Getting started diff --git a/docs/failover.md b/docs/failover.md index c2759b8f47..8414e41376 100644 --- a/docs/failover.md +++ b/docs/failover.md @@ -152,7 +152,7 @@ FailoverReporter reporter = new FailoverReporter(); provider.setClusterFailoverPostProcessor(reporter); ``` -The provider will call your `accept` whenver a faoliver occurs. +The provider will call your `accept` whenever a faoliver occurs. ## Failing back diff --git a/pom.xml b/pom.xml index ecd22f14d5..afd13e8c0a 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ Jedis Mailing List jedis_redis@googlegroups.com - http://groups.google.com/group/jedis_redis + https://groups.google.com/group/jedis_redis @@ -27,14 +27,14 @@ MIT - http://github.com/redis/jedis/raw/master/LICENSE.txt + https://github.com/redis/jedis/blob/master/LICENSE repo github - http://github.com/redis/jedis/issues + https://github.com/redis/jedis/issues diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index e8c15864e3..c024894caa 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -352,7 +352,7 @@ public byte[] ping(final byte[] message) { /** * Select the DB with having the specified zero-based numeric index. For default every new - * connection connection is automatically selected to DB 0. + * connection is automatically selected to DB 0. * @param index * @return OK */ @@ -569,7 +569,7 @@ public long del(final byte[] key) { /** * This command is very similar to DEL: it removes the specified keys. Just like DEL a key is - * ignored if it does not exist. However the command performs the actual memory reclaiming in a + * ignored if it does not exist. However, the command performs the actual memory reclaiming in a * different thread, so it is not blocking, while DEL is. This is where the command name comes * from: the command just unlinks the keys from the keyspace. The actual removal will happen later * asynchronously. @@ -925,7 +925,7 @@ public String setex(final byte[] key, final long seconds, final byte[] value) { } /** - * Set the the respective keys to the respective values. MSET will replace old values with new + * Set the respective keys to the respective values. MSET will replace old values with new * values, while {@link Jedis#msetnx(byte[][]) MSETNX} will not perform any operation at all even * if just a single key already exists. *

@@ -973,10 +973,10 @@ public long msetnx(final byte[]... keysvalues) { * DECRBY work just like {@link Jedis#decr(byte[]) DECR} but instead to decrement by 1 the * decrement is integer. *

- * DECR commands are limited to 64 bit signed integers. + * DECR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -997,10 +997,10 @@ public long decrBy(final byte[] key, final long decrement) { * Decrement the number stored at key by one. If the key does not exist or contains a value of a * wrong type, set the key to the value of "0" before to perform the decrement operation. *

- * DECR commands are limited to 64 bit signed integers. + * DECR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -1020,10 +1020,10 @@ public long decr(final byte[] key) { * INCRBY work just like {@link Jedis#incr(byte[]) INCR} but instead to increment by 1 the * increment is integer. *

- * INCR commands are limited to 64 bit signed integers. + * INCR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -1069,10 +1069,10 @@ public double incrByFloat(final byte[] key, final double increment) { * Increment the number stored at key by one. If the key does not exist or contains a value of a * wrong type, set the key to the value of "0" before to perform the increment operation. *

- * INCR commands are limited to 64 bit signed integers. + * INCR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -1222,7 +1222,7 @@ public List hmget(final byte[] key, final byte[]... fields) { * before applying the operation. Since the value argument is signed you can use this command to * perform both increments and decrements. *

- * The range of values supported by HINCRBY is limited to 64 bit signed integers. + * The range of values supported by HINCRBY is limited to 64-bit signed integers. *

* Time complexity: O(1) * @param key @@ -2646,7 +2646,7 @@ public KeyValue bzpopmin(final double timeout, final byte[]... ke * instructed to require a password before to allow clients to issue commands. This is done using * the requirepass directive in the Redis configuration file. If the password given by the connection * is correct the server replies with an OK status code reply and starts accepting commands from - * the connection. Otherwise an error is returned and the clients needs to try a new password. Note + * the connection. Otherwise, an error is returned and the clients needs to try a new password. Note * that for the high performance nature of Redis it is possible to try a lot of passwords in * parallel in very short time, so make sure to generate a strong and very long password so that * this attack is infeasible. @@ -3617,9 +3617,9 @@ public String configResetStat() { * *

* CONFIG REWRITE is also able to rewrite the configuration file from scratch if the original one - * no longer exists for some reason. However if the server was started without a configuration + * no longer exists for some reason. However, if the server was started without a configuration * file at all, the CONFIG REWRITE will just return an error. - * @return OK when the configuration was rewritten properly. Otherwise an error is returned. + * @return OK when the configuration was rewritten properly. Otherwise, an error is returned. */ @Override public String configRewrite() { @@ -5002,7 +5002,7 @@ public long del(final String key) { /** * This command is very similar to DEL: it removes the specified keys. Just like DEL a key is - * ignored if it does not exist. However the command performs the actual memory reclaiming in a + * ignored if it does not exist. However, the command performs the actual memory reclaiming in a * different thread, so it is not blocking, while DEL is. This is where the command name comes * from: the command just unlinks the keys from the keyspace. The actual removal will happen later * asynchronously. @@ -5362,7 +5362,7 @@ public String setex(final String key, final long seconds, final String value) { } /** - * Set the the respective keys to the respective values. MSET will replace old values with new + * Set the respective keys to the respective values. MSET will replace old values with new * values, while {@link Jedis#msetnx(String...) MSETNX} will not perform any operation at all even * if just a single key already exists. *

@@ -5384,7 +5384,7 @@ public String mset(final String... keysvalues) { } /** - * Set the the respective keys to the respective values. {@link Jedis#mset(String...) MSET} will + * Set the respective keys to the respective values. {@link Jedis#mset(String...) MSET} will * replace old values with new values, while MSETNX will not perform any operation at all even if * just a single key already exists. *

@@ -5409,10 +5409,10 @@ public long msetnx(final String... keysvalues) { * IDECRBY work just like {@link Jedis#decr(String) INCR} but instead to decrement by 1 the * decrement is integer. *

- * INCR commands are limited to 64 bit signed integers. + * INCR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -5433,10 +5433,10 @@ public long decrBy(final String key, final long decrement) { * Decrement the number stored at key by one. If the key does not exist or contains a value of a * wrong type, set the key to the value of "0" before to perform the decrement operation. *

- * INCR commands are limited to 64 bit signed integers. + * INCR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -5456,10 +5456,10 @@ public long decr(final String key) { * INCRBY work just like {@link Jedis#incr(String) INCR} but instead to increment by 1 the * increment is integer. *

- * INCR commands are limited to 64 bit signed integers. + * INCR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -5501,10 +5501,10 @@ public double incrByFloat(final String key, final double increment) { * Increment the number stored at key by one. If the key does not exist or contains a value of a * wrong type, set the key to the value of "0" before to perform the increment operation. *

- * INCR commands are limited to 64 bit signed integers. + * INCR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -5654,7 +5654,7 @@ public List hmget(final String key, final String... fields) { * before applying the operation. Since the value argument is signed you can use this command to * perform both increments and decrements. *

- * The range of values supported by HINCRBY is limited to 64 bit signed integers. + * The range of values supported by HINCRBY is limited to 64-bit signed integers. *

* Time complexity: O(1) * @param key diff --git a/src/main/java/redis/clients/jedis/JedisSentinelPool.java b/src/main/java/redis/clients/jedis/JedisSentinelPool.java index 6f921ddd97..586750540c 100644 --- a/src/main/java/redis/clients/jedis/JedisSentinelPool.java +++ b/src/main/java/redis/clients/jedis/JedisSentinelPool.java @@ -31,8 +31,8 @@ public class JedisSentinelPool extends Pool { private final Object initPoolLock = new Object(); public JedisSentinelPool(String masterName, Set sentinels, - final JedisClientConfig masteClientConfig, final JedisClientConfig sentinelClientConfig) { - this(masterName, sentinels, new JedisFactory(masteClientConfig), sentinelClientConfig); + final JedisClientConfig masterClientConfig, final JedisClientConfig sentinelClientConfig) { + this(masterName, sentinels, new JedisFactory(masterClientConfig), sentinelClientConfig); } public JedisSentinelPool(String masterName, Set sentinels, @@ -167,9 +167,9 @@ public JedisSentinelPool(String masterName, Set sentinels, } public JedisSentinelPool(String masterName, Set sentinels, - final GenericObjectPoolConfig poolConfig, final JedisClientConfig masteClientConfig, + final GenericObjectPoolConfig poolConfig, final JedisClientConfig masterClientConfig, final JedisClientConfig sentinelClientConfig) { - this(masterName, sentinels, poolConfig, new JedisFactory(masteClientConfig), sentinelClientConfig); + this(masterName, sentinels, poolConfig, new JedisFactory(masterClientConfig), sentinelClientConfig); } public JedisSentinelPool(String masterName, Set sentinels, diff --git a/src/main/java/redis/clients/jedis/commands/ClientBinaryCommands.java b/src/main/java/redis/clients/jedis/commands/ClientBinaryCommands.java index 32efb7fe25..ef32730a1a 100644 --- a/src/main/java/redis/clients/jedis/commands/ClientBinaryCommands.java +++ b/src/main/java/redis/clients/jedis/commands/ClientBinaryCommands.java @@ -46,7 +46,7 @@ public interface ClientBinaryCommands { /** * Returns information and statistics about the client connections server - * in a mostly human readable format. + * in a mostly human-readable format. * * @return All clients info connected to redis-server */ @@ -54,7 +54,7 @@ public interface ClientBinaryCommands { /** * Returns information and statistics about the client connections server - * in a mostly human readable format filter by client type. + * in a mostly human-readable format filter by client type. * * @return all clients info connected to redis-server */ @@ -62,7 +62,7 @@ public interface ClientBinaryCommands { /** * Returns information and statistics about the client connections server - * in a mostly human readable format filter by client ids. + * in a mostly human-readable format filter by client ids. * * @param clientIds Unique 64-bit client IDs * @return All clients info connected to redis-server @@ -71,7 +71,7 @@ public interface ClientBinaryCommands { /** * Returns information and statistics about the current client connection - * in a mostly human readable format. + * in a mostly human-readable format. * * @return Information and statistics about the current client connection */ diff --git a/src/main/java/redis/clients/jedis/commands/ClientCommands.java b/src/main/java/redis/clients/jedis/commands/ClientCommands.java index 537fa417d8..edcfbd602e 100644 --- a/src/main/java/redis/clients/jedis/commands/ClientCommands.java +++ b/src/main/java/redis/clients/jedis/commands/ClientCommands.java @@ -46,7 +46,7 @@ public interface ClientCommands { /** * Returns information and statistics about the client connections server - * in a mostly human readable format. + * in a mostly human-readable format. * * @return All clients info connected to redis-server */ @@ -54,7 +54,7 @@ public interface ClientCommands { /** * Returns information and statistics about the client connections server - * in a mostly human readable format filter by client type. + * in a mostly human-readable format filter by client type. * * @return All clients info connected to redis-server */ @@ -62,7 +62,7 @@ public interface ClientCommands { /** * Returns information and statistics about the client connections server - * in a mostly human readable format filter by client ids. + * in a mostly human-readable format filter by client ids. * * @param clientIds Unique 64-bit client IDs * @return All clients info connected to redis-server @@ -71,7 +71,7 @@ public interface ClientCommands { /** * Returns information and statistics about the current client connection - * in a mostly human readable format. + * in a mostly human-readable format. * * @return Information and statistics about the current client connection */ diff --git a/src/main/java/redis/clients/jedis/commands/ClusterCommands.java b/src/main/java/redis/clients/jedis/commands/ClusterCommands.java index 7a052146eb..da0d3fc8e0 100644 --- a/src/main/java/redis/clients/jedis/commands/ClusterCommands.java +++ b/src/main/java/redis/clients/jedis/commands/ClusterCommands.java @@ -108,7 +108,7 @@ public interface ClusterCommands { * Takes a list of slot ranges (specified by start and end slots) to assign to the node * * @param ranges slots range - * @return OK if the command was successful. Otherwise an error is returned. + * @return OK if the command was successful. Otherwise, an error is returned. */ String clusterAddSlotsRange(int... ranges); @@ -116,7 +116,7 @@ public interface ClusterCommands { * Takes a list of slot ranges (specified by start and end slots) to remove to the node. * * @param ranges slots range - * @return OK if the command was successful. Otherwise an error is returned. + * @return OK if the command was successful. Otherwise, an error is returned. */ String clusterDelSlotsRange(int... ranges); } diff --git a/src/main/java/redis/clients/jedis/commands/StreamCommands.java b/src/main/java/redis/clients/jedis/commands/StreamCommands.java index 9e258e4b46..6f1245b136 100644 --- a/src/main/java/redis/clients/jedis/commands/StreamCommands.java +++ b/src/main/java/redis/clients/jedis/commands/StreamCommands.java @@ -226,7 +226,7 @@ Map.Entry> xautoclaimJustId(String key, Strin * @param key Stream name * @param group Group name * @return List of {@link StreamConsumersInfo} containing information about consumers that belong - * to the the group + * to the group * @deprecated Use {@link #xinfoConsumers2(java.lang.String, java.lang.String)}. */ @Deprecated // keep it till at least Jedis 6/7 @@ -237,7 +237,7 @@ Map.Entry> xautoclaimJustId(String key, Strin * @param key Stream name * @param group Group name * @return List of {@link StreamConsumerInfo} containing information about consumers that belong - * to the the group + * to the group */ List xinfoConsumers2(String key, String group); diff --git a/src/main/java/redis/clients/jedis/commands/StreamPipelineCommands.java b/src/main/java/redis/clients/jedis/commands/StreamPipelineCommands.java index 2b11f833dd..e435c02341 100644 --- a/src/main/java/redis/clients/jedis/commands/StreamPipelineCommands.java +++ b/src/main/java/redis/clients/jedis/commands/StreamPipelineCommands.java @@ -219,7 +219,7 @@ Response>> xautoclaimJustId(String * @param key Stream name * @param group Group name * @return List of {@link StreamConsumersInfo} containing information about consumers that belong - * to the the group + * to the group * @deprecated Use {@link #xinfoConsumers2(java.lang.String, java.lang.String)}. */ @Deprecated // keep it till at least Jedis 6/7 @@ -230,7 +230,7 @@ Response>> xautoclaimJustId(String * @param key Stream name * @param group Group name * @return List of {@link StreamConsumerInfo} containing information about consumers that belong - * to the the group + * to the group */ Response> xinfoConsumers2(String key, String group); diff --git a/src/main/java/redis/clients/jedis/commands/StringCommands.java b/src/main/java/redis/clients/jedis/commands/StringCommands.java index 9e30e8489d..0621bc9334 100644 --- a/src/main/java/redis/clients/jedis/commands/StringCommands.java +++ b/src/main/java/redis/clients/jedis/commands/StringCommands.java @@ -172,7 +172,7 @@ public interface StringCommands extends BitCommands { /** * MSet Command - * Set the the respective keys to the respective values. MSET will replace old values with new + * Set the respective keys to the respective values. MSET will replace old values with new * values, while {@link StringCommands#msetnx(String...) MSETNX} will not perform any operation at all even * if just a single key already exists. *

@@ -213,10 +213,10 @@ public interface StringCommands extends BitCommands { * Increment the number stored at key by one. If the key does not exist or contains a value of a * wrong type, set the key to the value of "0" before to perform the increment operation. *

- * INCR commands are limited to 64 bit signed integers. + * INCR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -230,10 +230,10 @@ public interface StringCommands extends BitCommands { * INCRBY work just like {@link StringCommands#incr(String) INCR} but instead to increment by 1 the * increment is integer. *

- * INCR commands are limited to 64 bit signed integers. + * INCR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -267,10 +267,10 @@ public interface StringCommands extends BitCommands { * Decrement the number stored at key by one. If the key does not exist or contains a value of a * wrong type, set the key to the value of "0" before to perform the decrement operation. *

- * DECR commands are limited to 64 bit signed integers. + * DECR commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) @@ -284,10 +284,10 @@ public interface StringCommands extends BitCommands { * DECRBY work just like {@link StringCommands#decr(String) DECR} but instead to decrement by 1 the * decrement is integer. *

- * DECRBY commands are limited to 64 bit signed integers. + * DECRBY commands are limited to 64-bit signed integers. *

* Note: this is actually a string operation, that is, in Redis there are not "integer" types. - * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, + * Simply the string stored at the key is parsed as a base 10 64-bit signed integer, incremented, * and then converted back as a string. *

* Time complexity: O(1) diff --git a/src/main/java/redis/clients/jedis/graph/Record.java b/src/main/java/redis/clients/jedis/graph/Record.java index 46e6abb58d..cbcf78fc96 100644 --- a/src/main/java/redis/clients/jedis/graph/Record.java +++ b/src/main/java/redis/clients/jedis/graph/Record.java @@ -63,7 +63,7 @@ public interface Record { * * @param key header key * - * @return true if the the key exists + * @return true if the key exists */ boolean containsKey(String key); diff --git a/src/main/java/redis/clients/jedis/graph/ResultSetBuilder.java b/src/main/java/redis/clients/jedis/graph/ResultSetBuilder.java index 55839d74c1..6f0f38ebb2 100644 --- a/src/main/java/redis/clients/jedis/graph/ResultSetBuilder.java +++ b/src/main/java/redis/clients/jedis/graph/ResultSetBuilder.java @@ -334,7 +334,7 @@ private static enum ScalarType { UNKNOWN, NULL, STRING, - INTEGER, // 64 bit long. + INTEGER, // 64-bit long. BOOLEAN, DOUBLE, ARRAY, diff --git a/src/main/java/redis/clients/jedis/search/querybuilder/Node.java b/src/main/java/redis/clients/jedis/search/querybuilder/Node.java index 013ac79b6f..12e71e5d69 100644 --- a/src/main/java/redis/clients/jedis/search/querybuilder/Node.java +++ b/src/main/java/redis/clients/jedis/search/querybuilder/Node.java @@ -18,7 +18,7 @@ enum Parenthesize { /** * Never encapsulate. Note that this may be ignored if parentheses are semantically required - * (e.g. {@code @foo:(val1|val2)}. However something like {@code @foo:v1 @bar:v2} need not be + * (e.g. {@code @foo:(val1|val2)}. However, something like {@code @foo:v1 @bar:v2} need not be * parenthesized. */ diff --git a/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java b/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java index 61f2737cf6..36474e12d5 100644 --- a/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java @@ -60,7 +60,7 @@ public void checkResourceIsClosableAndReusable() { config.setBlockWhenExhausted(false); try (JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(), Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, 0 /* infinite */, "acljedis", - "fizzbuzz", Protocol.DEFAULT_DATABASE, "closable-resuable-pool", false, null, null, null)) { + "fizzbuzz", Protocol.DEFAULT_DATABASE, "closable-reusable-pool", false, null, null, null)) { Jedis jedis = pool.getResource(); jedis.set("hello", "jedis"); @@ -79,7 +79,7 @@ public void checkResourceWithConfigIsClosableAndReusable() { config.setMaxTotal(1); config.setBlockWhenExhausted(false); try (JedisPool pool = new JedisPool(config, hnp, DefaultJedisClientConfig.builder() - .user("acljedis").password("fizzbuzz").clientName("closable-resuable-pool") + .user("acljedis").password("fizzbuzz").clientName("closable-reusable-pool") .build())) { Jedis jedis = pool.getResource(); @@ -89,7 +89,7 @@ public void checkResourceWithConfigIsClosableAndReusable() { Jedis jedis2 = pool.getResource(); assertEquals(jedis, jedis2); assertEquals("jedis", jedis2.get("hello")); - assertEquals("closable-resuable-pool", jedis2.clientGetname()); + assertEquals("closable-reusable-pool", jedis2.clientGetname()); jedis2.close(); } } diff --git a/src/test/java/redis/clients/jedis/JedisPoolTest.java b/src/test/java/redis/clients/jedis/JedisPoolTest.java index 18e448c52e..a256abcae0 100644 --- a/src/test/java/redis/clients/jedis/JedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/JedisPoolTest.java @@ -79,7 +79,7 @@ public void checkResourceIsClosableAndReusable() { config.setMaxTotal(1); config.setBlockWhenExhausted(false); try (JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(), 2000, "foobared", 0, - "closable-resuable-pool", false, null, null, null)) { + "closable-reusable-pool", false, null, null, null)) { Jedis jedis = pool.getResource(); jedis.set("hello", "jedis"); From 9a71576b7ca4b0943a2ae96e8fe2a20c90cc9f5b Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Wed, 16 Aug 2023 18:25:31 +0600 Subject: [PATCH 07/23] Support Search commands after RESP3 update (#3464) * Ignore PROFILE LIMITED test due to crash * FT._LIST returns Set * a commit for CONFIG GET * a commit for SPELLCHECK * Search search works * Search aggregation * Ignore pending server update tests * doc breaking changes * fix * ignore ftSearch binary test * breaking doc * comment * FT.PROFILE * assert info * more asserts and edits * FT.SPELLCHECK RESP3 current implementation * 'extra_attributes' as map key for results * Address FT.SPELLCHECK changes * FT.INFO in RESP3 test * FT.PROFILE SEARCH MAXPREFIXEXPANSIONS test * FT.PROFILE SEARCH NOCONTENT test * FT.PROFILE SEARCH with deep reply test * FT.PROFILE SEARCH LIMITED test * Bring back RESP2 tests for last few commits * Remove imports * Remove imports * Fix FT.PROFILE SEARCH NOCONTENT in RESP2 test * Use protocol variable in SearchWithParamsTest --- docs/jedis5-breaking.md | 8 + .../redis/clients/jedis/BuilderFactory.java | 116 ++++++++++--- .../redis/clients/jedis/CommandObjects.java | 89 ++++++---- .../redis/clients/jedis/PipelineBase.java | 5 +- .../redis/clients/jedis/TransactionBase.java | 5 +- .../redis/clients/jedis/UnifiedJedis.java | 11 +- .../redis/clients/jedis/search/Document.java | 103 ++++++++---- .../jedis/search/FtSearchIteration.java | 23 ++- .../jedis/search/RediSearchCommands.java | 7 +- .../search/RediSearchPipelineCommands.java | 5 +- .../jedis/search/SearchBuilderFactory.java | 56 ++++--- .../clients/jedis/search/SearchResult.java | 38 ++++- .../jedis/search/aggr/AggregationResult.java | 99 ++++++++++- .../search/aggr/FtAggregateIteration.java | 3 +- .../modules/RedisModulesPipelineTest.java | 8 +- .../jedis/modules/json/JsonObjects.java | 1 - .../jedis/modules/search/AggregationTest.java | 50 ++++++ .../modules/search/SearchConfigTest.java | 36 ++-- .../jedis/modules/search/SearchTest.java | 112 ++++++++----- .../modules/search/SearchWithParamsTest.java | 157 ++++++++++++------ .../jedis/modules/search/SpellCheckTest.java | 13 +- 21 files changed, 697 insertions(+), 248 deletions(-) diff --git a/docs/jedis5-breaking.md b/docs/jedis5-breaking.md index f9d5df7ad4..7b373b2e77 100644 --- a/docs/jedis5-breaking.md +++ b/docs/jedis5-breaking.md @@ -42,6 +42,10 @@ - `getAgeSeconds()` in `AccessControlLogEntry` now returns `Double` instead of `String`. +- Both `ftConfigGet(String option)` and `ftConfigGet(String indexName, String option)` methods now return `Map` instead of `Map`. + +- `ftList()` method now returns `Set` instead of `List`. + - `graphSlowlog(String graphName)` now returns `List>` (instead of `List>`). - All _payload_ related parameters are removed from _search_ related classes; namely `Document`, `IndexDefinition`, `Query`. @@ -74,6 +78,10 @@ - `getParams()` method is removed from `SortingParams` class. +- Both `SEARCH_AGGREGATION_RESULT` and `SEARCH_AGGREGATION_RESULT_WITH_CURSOR` implementations from `SearchBuilderFactory` class have been moved to `AggregationResult` class. + +- All `AggregationResult` constructors have been made `private`. + - `addCommandEncodedArguments` and `addCommandBinaryArguments` methods have been removed from `FieldName` class. - `getArgs` method is removed from `AggregationBuilder` class. diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 5e5d03a830..20a061d6b9 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -290,52 +290,57 @@ public String toString() { } }; - public static final Builder> ENCODED_OBJECT_MAP = new Builder>() { + public static final Builder> BINARY_MAP = new Builder>() { @Override - public Map build(Object data) { - if (data == null) return null; + @SuppressWarnings("unchecked") + public Map build(Object data) { final List list = (List) data; if (list.isEmpty()) return Collections.emptyMap(); if (list.get(0) instanceof KeyValue) { - final Map map = new HashMap<>(list.size(), 1f); + final Map map = new JedisByteHashMap(); final Iterator iterator = list.iterator(); while (iterator.hasNext()) { KeyValue kv = (KeyValue) iterator.next(); - map.put(STRING.build(kv.getKey()), ENCODED_OBJECT.build(kv.getValue())); + map.put(BINARY.build(kv.getKey()), BINARY.build(kv.getValue())); } return map; } else { - final Map map = new HashMap<>(list.size() / 2, 1f); + final Map map = new JedisByteHashMap(); final Iterator iterator = list.iterator(); while (iterator.hasNext()) { - map.put(STRING.build(iterator.next()), ENCODED_OBJECT.build(iterator.next())); + map.put(BINARY.build(iterator.next()), BINARY.build(iterator.next())); } return map; } } + + @Override + public String toString() { + return "Map"; + } }; - public static final Builder> BINARY_MAP = new Builder>() { + public static final Builder> STRING_MAP = new Builder>() { @Override @SuppressWarnings("unchecked") - public Map build(Object data) { + public Map build(Object data) { final List list = (List) data; if (list.isEmpty()) return Collections.emptyMap(); if (list.get(0) instanceof KeyValue) { - final Map map = new JedisByteHashMap(); + final Map map = new HashMap<>(list.size(), 1f); final Iterator iterator = list.iterator(); while (iterator.hasNext()) { KeyValue kv = (KeyValue) iterator.next(); - map.put(BINARY.build(kv.getKey()), BINARY.build(kv.getValue())); + map.put(STRING.build(kv.getKey()), STRING.build(kv.getValue())); } return map; } else { - final Map map = new JedisByteHashMap(); + final Map map = new HashMap<>(list.size() / 2, 1f); final Iterator iterator = list.iterator(); while (iterator.hasNext()) { - map.put(BINARY.build(iterator.next()), BINARY.build(iterator.next())); + map.put(STRING.build(iterator.next()), STRING.build(iterator.next())); } return map; } @@ -343,38 +348,64 @@ public Map build(Object data) { @Override public String toString() { - return "Map"; + return "Map"; } }; - public static final Builder> STRING_MAP = new Builder>() { + public static final Builder> ENCODED_OBJECT_MAP = new Builder>() { @Override - @SuppressWarnings("unchecked") - public Map build(Object data) { + public Map build(Object data) { + if (data == null) return null; final List list = (List) data; if (list.isEmpty()) return Collections.emptyMap(); if (list.get(0) instanceof KeyValue) { - final Map map = new HashMap<>(list.size(), 1f); + final Map map = new HashMap<>(list.size(), 1f); final Iterator iterator = list.iterator(); while (iterator.hasNext()) { KeyValue kv = (KeyValue) iterator.next(); - map.put(STRING.build(kv.getKey()), STRING.build(kv.getValue())); + map.put(STRING.build(kv.getKey()), ENCODED_OBJECT.build(kv.getValue())); } return map; } else { - final Map map = new HashMap<>(list.size() / 2, 1f); + final Map map = new HashMap<>(list.size() / 2, 1f); final Iterator iterator = list.iterator(); while (iterator.hasNext()) { - map.put(STRING.build(iterator.next()), STRING.build(iterator.next())); + map.put(STRING.build(iterator.next()), ENCODED_OBJECT.build(iterator.next())); } return map; } } + }; + public static final Builder AGGRESSIVE_ENCODED_OBJECT = new Builder() { @Override - public String toString() { - return "Map"; + public Object build(Object data) { + if (data == null) return null; + + if (data instanceof List) { + final List list = (List) data; + if (list.isEmpty()) return Collections.emptyMap(); + + if (list.get(0) instanceof KeyValue) { + return ((List) data).stream() + .filter(kv -> kv != null && kv.getKey() != null && kv.getValue() != null) + .collect(Collectors.toMap(kv -> STRING.build(kv.getKey()), + kv -> this.build(kv.getValue()))); + } else { + return list.stream().map(this::build).collect(Collectors.toList()); + } + } else if (data instanceof byte[]) { + return STRING.build(data); + } + return data; + } + }; + + public static final Builder> AGGRESSIVE_ENCODED_OBJECT_MAP = new Builder>() { + @Override + public Map build(Object data) { + return (Map) AGGRESSIVE_ENCODED_OBJECT.build(data); } }; @@ -1736,7 +1767,15 @@ private void addMatchedPosition(List matchedPositions, Object o @Override @SuppressWarnings("unchecked") public Map build(Object data) { - final List list = (List) data; + final List list = (List) data; + if (list.isEmpty()) return Collections.emptyMap(); + + if (list.get(0) instanceof KeyValue) { + return ((List) list).stream() + .collect(Collectors.toMap(kv -> STRING.build(kv.getKey()), + kv -> STRING.build(kv.getValue()))); + } + final Map map = new HashMap<>(list.size()); for (Object object : list) { if (object == null) continue; @@ -1753,6 +1792,35 @@ public String toString() { } }; + public static final Builder> ENCODED_OBJECT_MAP_FROM_PAIRS = new Builder>() { + @Override + @SuppressWarnings("unchecked") + public Map build(Object data) { + final List list = (List) data; + if (list.isEmpty()) return Collections.emptyMap(); + + if (list.get(0) instanceof KeyValue) { + return ((List) list).stream() + .collect(Collectors.toMap(kv -> STRING.build(kv.getKey()), + kv -> ENCODED_OBJECT.build(kv.getValue()))); + } + + final Map map = new HashMap<>(list.size()); + for (Object object : list) { + if (object == null) continue; + final List flat = (List) object; + if (flat.isEmpty()) continue; + map.put(STRING.build(flat.get(0)), STRING.build(flat.get(1))); + } + return map; + } + + @Override + public String toString() { + return "Map"; + } + }; + public static final Builder> LIBRARY_LIST = new Builder>() { @Override public List build(Object data) { diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 60031520a2..b22cf94d2a 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -5,6 +5,7 @@ import java.util.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; import java.util.stream.Collectors; import org.json.JSONArray; import org.json.JSONObject; @@ -34,10 +35,14 @@ public class CommandObjects { - private RedisProtocol proto; + private RedisProtocol protocol; protected void setProtocol(RedisProtocol proto) { - this.proto = proto; + this.protocol = proto; + } + + protected RedisProtocol getProtocol() { + return protocol; } private volatile JsonObjectMapper jsonObjectMapper; @@ -1094,7 +1099,7 @@ public final CommandObject> hrandfield(String key, long count) { public final CommandObject>> hrandfieldWithValues(String key, long count) { return new CommandObject<>(commandArguments(HRANDFIELD).key(key).add(count).add(WITHVALUES), - proto != RedisProtocol.RESP3 ? BuilderFactory.STRING_PAIR_LIST : BuilderFactory.STRING_PAIR_LIST_FROM_PAIRS); + protocol != RedisProtocol.RESP3 ? BuilderFactory.STRING_PAIR_LIST : BuilderFactory.STRING_PAIR_LIST_FROM_PAIRS); } public final CommandObject> hgetAll(byte[] key) { @@ -1111,7 +1116,7 @@ public final CommandObject> hrandfield(byte[] key, long count) { public final CommandObject>> hrandfieldWithValues(byte[] key, long count) { return new CommandObject<>(commandArguments(HRANDFIELD).key(key).add(count).add(WITHVALUES), - proto != RedisProtocol.RESP3 ? BuilderFactory.BINARY_PAIR_LIST : BuilderFactory.BINARY_PAIR_LIST_FROM_PAIRS); + protocol != RedisProtocol.RESP3 ? BuilderFactory.BINARY_PAIR_LIST : BuilderFactory.BINARY_PAIR_LIST_FROM_PAIRS); } public final CommandObject>> hscan(String key, String cursor, ScanParams params) { @@ -1992,11 +1997,11 @@ public final CommandObject>> bzmpop(double timeout, } private Builder> getTupleListBuilder() { - return proto == RedisProtocol.RESP3 ? BuilderFactory.TUPLE_LIST_RESP3 : BuilderFactory.TUPLE_LIST; + return protocol == RedisProtocol.RESP3 ? BuilderFactory.TUPLE_LIST_RESP3 : BuilderFactory.TUPLE_LIST; } private Builder> getTupleSetBuilder() { - return proto == RedisProtocol.RESP3 ? BuilderFactory.TUPLE_ZSET_RESP3 : BuilderFactory.TUPLE_ZSET; + return protocol == RedisProtocol.RESP3 ? BuilderFactory.TUPLE_ZSET_RESP3 : BuilderFactory.TUPLE_ZSET; } // Sorted Set commands @@ -3190,24 +3195,29 @@ public final CommandObject ftAlter(String indexName, Iterable ftSearch(String indexName, String query) { return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.SEARCH), indexName).add(query), - new SearchResultBuilder(true, false, true)); + getSearchResultBuilder(() -> new SearchResultBuilder(true, false, true))); } public final CommandObject ftSearch(String indexName, String query, FTSearchParams params) { return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.SEARCH), indexName) - .add(query).addParams(params.dialectOptional(searchDialect.get())), new SearchResultBuilder(!params.getNoContent(), params.getWithScores(), true)); + .add(query).addParams(params.dialectOptional(searchDialect.get())), + getSearchResultBuilder(() -> new SearchResultBuilder(!params.getNoContent(), params.getWithScores(), true))); } public final CommandObject ftSearch(String indexName, Query query) { return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.SEARCH), indexName) - .addParams(query.dialectOptional(searchDialect.get())), - new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true)); + .addParams(query.dialectOptional(searchDialect.get())), getSearchResultBuilder(() -> + new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true))); } + @Deprecated public final CommandObject ftSearch(byte[] indexName, Query query) { + if (protocol == RedisProtocol.RESP3) { + throw new UnsupportedOperationException("binary ft.search is not implemented with resp3."); + } return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.SEARCH), indexName) - .addParams(query.dialectOptional(searchDialect.get())), - new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), false)); + .addParams(query.dialectOptional(searchDialect.get())), getSearchResultBuilder(() -> + new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), false))); } public final CommandObject ftExplain(String indexName, Query query) { @@ -3222,14 +3232,14 @@ public final CommandObject> ftExplainCLI(String indexName, Query qu public final CommandObject ftAggregate(String indexName, AggregationBuilder aggr) { return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.AGGREGATE), indexName) - .addParams(aggr.dialectOptional(searchDialect.get())), !aggr.isWithCursor() ? SearchBuilderFactory.SEARCH_AGGREGATION_RESULT - : SearchBuilderFactory.SEARCH_AGGREGATION_RESULT_WITH_CURSOR); + .addParams(aggr.dialectOptional(searchDialect.get())), !aggr.isWithCursor() ? AggregationResult.SEARCH_AGGREGATION_RESULT + : AggregationResult.SEARCH_AGGREGATION_RESULT_WITH_CURSOR); } public final CommandObject ftCursorRead(String indexName, long cursorId, int count) { return new CommandObject<>(commandArguments(SearchCommand.CURSOR).add(SearchKeyword.READ) .add(indexName).add(cursorId).add(SearchKeyword.COUNT).add(count), - SearchBuilderFactory.SEARCH_AGGREGATION_RESULT_WITH_CURSOR); + AggregationResult.SEARCH_AGGREGATION_RESULT_WITH_CURSOR); } public final CommandObject ftCursorDel(String indexName, long cursorId) { @@ -3241,9 +3251,9 @@ public final CommandObject>> ft String indexName, FTProfileParams profileParams, AggregationBuilder aggr) { return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.PROFILE), indexName) .add(SearchKeyword.AGGREGATE).addParams(profileParams).add(SearchKeyword.QUERY) - .addParams(aggr.dialectOptional(searchDialect.get())), new SearchProfileResponseBuilder<>(!aggr.isWithCursor() - ? SearchBuilderFactory.SEARCH_AGGREGATION_RESULT - : SearchBuilderFactory.SEARCH_AGGREGATION_RESULT_WITH_CURSOR)); + .addParams(aggr.dialectOptional(searchDialect.get())), new SearchProfileResponseBuilder<>( + !aggr.isWithCursor() ? AggregationResult.SEARCH_AGGREGATION_RESULT + : AggregationResult.SEARCH_AGGREGATION_RESULT_WITH_CURSOR)); } public final CommandObject>> ftProfileSearch( @@ -3251,7 +3261,7 @@ public final CommandObject>> ftProfi return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.PROFILE), indexName) .add(SearchKeyword.SEARCH).addParams(profileParams).add(SearchKeyword.QUERY) .addParams(query.dialectOptional(searchDialect.get())), new SearchProfileResponseBuilder<>( - new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true))); + getSearchResultBuilder(() -> new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true)))); } public final CommandObject>> ftProfileSearch( @@ -3259,7 +3269,12 @@ public final CommandObject>> ftProfi return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.PROFILE), indexName) .add(SearchKeyword.SEARCH).addParams(profileParams).add(SearchKeyword.QUERY).add(query) .addParams(searchParams.dialectOptional(searchDialect.get())), new SearchProfileResponseBuilder<>( - new SearchResultBuilder(!searchParams.getNoContent(), searchParams.getWithScores(), true))); + getSearchResultBuilder(() -> new SearchResultBuilder(!searchParams.getNoContent(), searchParams.getWithScores(), true)))); + } + + private Builder getSearchResultBuilder(Supplier> resp2) { + if (protocol == RedisProtocol.RESP3) return SearchResult.SEARCH_RESULT_BUILDER; + return resp2.get(); } public final CommandObject ftDropIndex(String indexName) { @@ -3320,7 +3335,7 @@ public final CommandObject>> ftSpellCheck(String public final CommandObject> ftInfo(String indexName) { return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.INFO), indexName), - BuilderFactory.ENCODED_OBJECT_MAP); + protocol == RedisProtocol.RESP3 ? BuilderFactory.AGGRESSIVE_ENCODED_OBJECT_MAP : BuilderFactory.ENCODED_OBJECT_MAP); } public final CommandObject> ftTagVals(String indexName, String fieldName) { @@ -3340,11 +3355,12 @@ public final CommandObject ftAliasDel(String aliasName) { return new CommandObject<>(commandArguments(SearchCommand.ALIASDEL).add(aliasName), BuilderFactory.STRING); } - public final CommandObject> ftConfigGet(String option) { - return new CommandObject<>(commandArguments(SearchCommand.CONFIG).add(SearchKeyword.GET).add(option), BuilderFactory.STRING_MAP_FROM_PAIRS); + public final CommandObject> ftConfigGet(String option) { + return new CommandObject<>(commandArguments(SearchCommand.CONFIG).add(SearchKeyword.GET).add(option), + protocol == RedisProtocol.RESP3 ? BuilderFactory.AGGRESSIVE_ENCODED_OBJECT_MAP : BuilderFactory.ENCODED_OBJECT_MAP_FROM_PAIRS); } - public final CommandObject> ftConfigGet(String indexName, String option) { + public final CommandObject> ftConfigGet(String indexName, String option) { return directSearchCommand(ftConfigGet(option), indexName); } @@ -3396,8 +3412,8 @@ public final CommandObject ftSugLen(String key) { return new CommandObject<>(commandArguments(SearchCommand.SUGLEN).key(key), BuilderFactory.LONG); } - public final CommandObject> ftList() { - return new CommandObject<>(commandArguments(SearchCommand._LIST), BuilderFactory.STRING_LIST); + public final CommandObject> ftList() { + return new CommandObject<>(commandArguments(SearchCommand._LIST), BuilderFactory.STRING_SET); } // RediSearch commands @@ -3829,7 +3845,7 @@ public final CommandObject tsGet(String key, TSGetParams getParams) { public final CommandObject> tsMGet(TSMGetParams multiGetParams, String... filters) { return new CommandObject<>(commandArguments(TimeSeriesCommand.MGET).addParams(multiGetParams) .add(TimeSeriesKeyword.FILTER).addObjects((Object[]) filters), - proto == RedisProtocol.RESP3 ? TimeSeriesBuilderFactory.TIMESERIES_MGET_RESPONSE_RESP3 + protocol == RedisProtocol.RESP3 ? TimeSeriesBuilderFactory.TIMESERIES_MGET_RESPONSE_RESP3 : TimeSeriesBuilderFactory.TIMESERIES_MGET_RESPONSE); } @@ -3864,12 +3880,12 @@ public final CommandObject tsInfoDebug(String key) { } private Builder> getTimeseriesMultiRangeResponseBuilder() { - return proto == RedisProtocol.RESP3 ? TimeSeriesBuilderFactory.TIMESERIES_MRANGE_RESPONSE_RESP3 + return protocol == RedisProtocol.RESP3 ? TimeSeriesBuilderFactory.TIMESERIES_MRANGE_RESPONSE_RESP3 : TimeSeriesBuilderFactory.TIMESERIES_MRANGE_RESPONSE; } private Builder getTimeseriesInfoBuilder() { - return proto == RedisProtocol.RESP3 ? TSInfo.TIMESERIES_INFO_RESP3 : TSInfo.TIMESERIES_INFO; + return protocol == RedisProtocol.RESP3 ? TSInfo.TIMESERIES_INFO_RESP3 : TSInfo.TIMESERIES_INFO; } // RedisTimeSeries commands @@ -4203,6 +4219,8 @@ public void setDefaultSearchDialect(int dialect) { private class SearchProfileResponseBuilder extends Builder>> { + private static final String PROFILE_STR = "profile"; + private final Builder replyBuilder; public SearchProfileResponseBuilder(Builder replyBuilder) { @@ -4211,7 +4229,18 @@ public SearchProfileResponseBuilder(Builder replyBuilder) { @Override public Map.Entry> build(Object data) { - List list = (List) data; + List list = (List) data; + if (list == null || list.isEmpty()) return null; + + if (list.get(0) instanceof KeyValue) { + for (KeyValue keyValue : (List) data) { + if (PROFILE_STR.equals(BuilderFactory.STRING.build(keyValue.getKey()))) { + return KeyValue.of(replyBuilder.build(data), + BuilderFactory.AGGRESSIVE_ENCODED_OBJECT_MAP.build(keyValue.getValue())); + } + } + } + return KeyValue.of(replyBuilder.build(list.get(0)), SearchBuilderFactory.SEARCH_PROFILE_PROFILE.build(list.get(1))); } diff --git a/src/main/java/redis/clients/jedis/PipelineBase.java b/src/main/java/redis/clients/jedis/PipelineBase.java index 4511bfa8a5..b4b077a899 100644 --- a/src/main/java/redis/clients/jedis/PipelineBase.java +++ b/src/main/java/redis/clients/jedis/PipelineBase.java @@ -3299,6 +3299,7 @@ public Response ftSearch(String indexName, Query query) { } @Override + @Deprecated public Response ftSearch(byte[] indexName, Query query) { return appendCommand(commandObjects.ftSearch(indexName, query)); } @@ -3379,12 +3380,12 @@ public Response> ftTagVals(String indexName, String fieldName) { } @Override - public Response> ftConfigGet(String option) { + public Response> ftConfigGet(String option) { return appendCommand(commandObjects.ftConfigGet(option)); } @Override - public Response> ftConfigGet(String indexName, String option) { + public Response> ftConfigGet(String indexName, String option) { return appendCommand(commandObjects.ftConfigGet(indexName, option)); } diff --git a/src/main/java/redis/clients/jedis/TransactionBase.java b/src/main/java/redis/clients/jedis/TransactionBase.java index 2baf02f5c1..03513c2e40 100644 --- a/src/main/java/redis/clients/jedis/TransactionBase.java +++ b/src/main/java/redis/clients/jedis/TransactionBase.java @@ -3466,6 +3466,7 @@ public Response ftSearch(String indexName, Query query) { } @Override + @Deprecated public Response ftSearch(byte[] indexName, Query query) { return appendCommand(commandObjects.ftSearch(indexName, query)); } @@ -3546,12 +3547,12 @@ public Response> ftTagVals(String indexName, String fieldName) { } @Override - public Response> ftConfigGet(String option) { + public Response> ftConfigGet(String option) { return appendCommand(commandObjects.ftConfigGet(option)); } @Override - public Response> ftConfigGet(String indexName, String option) { + public Response> ftConfigGet(String indexName, String option) { return appendCommand(commandObjects.ftConfigGet(indexName, option)); } diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index bf2481f712..2063194290 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -3655,7 +3655,7 @@ public SearchResult ftSearch(String indexName, String query, FTSearchParams para * @return search iteration */ public FtSearchIteration ftSearchIteration(int batchSize, String indexName, String query, FTSearchParams params) { - return new FtSearchIteration(provider, batchSize, indexName, query, params); + return new FtSearchIteration(provider, commandObjects.getProtocol(), batchSize, indexName, query, params); } @Override @@ -3671,10 +3671,11 @@ public SearchResult ftSearch(String indexName, Query query) { * @return search iteration */ public FtSearchIteration ftSearchIteration(int batchSize, String indexName, Query query) { - return new FtSearchIteration(provider, batchSize, indexName, query); + return new FtSearchIteration(provider, commandObjects.getProtocol(), batchSize, indexName, query); } @Override + @Deprecated public SearchResult ftSearch(byte[] indexName, Query query) { return executeCommand(commandObjects.ftSearch(indexName, query)); } @@ -3818,12 +3819,12 @@ public String ftAliasDel(String aliasName) { } @Override - public Map ftConfigGet(String option) { + public Map ftConfigGet(String option) { return executeCommand(commandObjects.ftConfigGet(option)); } @Override - public Map ftConfigGet(String indexName, String option) { + public Map ftConfigGet(String indexName, String option) { return executeCommand(commandObjects.ftConfigGet(indexName, option)); } @@ -3878,7 +3879,7 @@ public long ftSugLen(String key) { } @Override - public List ftList() { + public Set ftList() { return executeCommand(commandObjects.ftList()); } // RediSearch commands diff --git a/src/main/java/redis/clients/jedis/search/Document.java b/src/main/java/redis/clients/jedis/search/Document.java index 9e126b948b..20149e581a 100644 --- a/src/main/java/redis/clients/jedis/search/Document.java +++ b/src/main/java/redis/clients/jedis/search/Document.java @@ -3,9 +3,13 @@ import redis.clients.jedis.util.SafeEncoder; import java.io.Serializable; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import redis.clients.jedis.Builder; +import redis.clients.jedis.BuilderFactory; +import redis.clients.jedis.util.KeyValue; /** * Document represents a single indexed document or entity in the engine @@ -15,29 +19,35 @@ public class Document implements Serializable { private static final long serialVersionUID = 4884173545291367373L; private final String id; - private double score; - private final Map properties; - - public Document(String id, double score) { - this(id, new HashMap<>(), score); - } + private Double score; + private final Map fields; public Document(String id) { this(id, 1.0); } + public Document(String id, double score) { + this(id, new HashMap<>(), score); + } + public Document(String id, Map fields) { this(id, fields, 1.0f); } public Document(String id, Map fields, double score) { this.id = id; - this.properties = fields; + this.fields = fields; + this.score = score; + } + + private Document(String id, Double score, Map fields) { + this.id = id; this.score = score; + this.fields = fields; } public Iterable> getProperties() { - return properties.entrySet(); + return fields.entrySet(); } public static Document load(String id, double score, byte[] payload, List fields) { @@ -58,9 +68,18 @@ public static Document load(String id, double score, List fields, boolea return ret; } - public Document set(String key, Object value) { - properties.put(key, value); - return this; + /** + * @return the document's id + */ + public String getId() { + return id; + } + + /** + * @return the document's score + */ + public Double getScore() { + return score; } /** @@ -71,7 +90,7 @@ public Document set(String key, Object value) { * @return the property value */ public Object get(String key) { - return properties.get(key); + return fields.get(key); } /** @@ -82,18 +101,20 @@ public Object get(String key) { * @return the property value */ public String getString(String key) { - Object value = properties.get(key); + Object value = fields.get(key); if (value instanceof String) { return (String) value; } return value instanceof byte[] ? SafeEncoder.encode((byte[]) value) : value.toString(); } - /** - * @return the document's score - */ - public double getScore() { - return score; + public boolean hasProperty(String key) { + return fields.containsKey(key); + } + + public Document set(String key, Object value) { + fields.put(key, value); + return this; } /** @@ -103,24 +124,46 @@ public double getScore() { * @return the document itself */ public Document setScore(float score) { - this.score = score; + this.score = (double) score; return this; } - /** - * @return the document's id - */ - public String getId() { - return id; - } - - public boolean hasProperty(String key) { - return properties.containsKey(key); - } - @Override public String toString() { return "id:" + this.getId() + ", score: " + this.getScore() + ", properties:" + this.getProperties(); } + + static Builder SEARCH_DOCUMENT = new Builder() { + + private static final String ID_STR = "id"; + private static final String SCORE_STR = "score"; + // private static final String FIELDS_STR = "fields"; + private static final String FIELDS_STR = "extra_attributes"; + + @Override + public Document build(Object data) { + List list = (List) data; + String id = null; + Double score = null; + Map fields = null; + for (KeyValue kv : list) { + String key = BuilderFactory.STRING.build(kv.getKey()); + switch (key) { + case ID_STR: + id = BuilderFactory.STRING.build(kv.getValue()); + break; + case SCORE_STR: + score = BuilderFactory.DOUBLE.build(kv.getValue()); + break; + case FIELDS_STR: + fields = BuilderFactory.ENCODED_OBJECT_MAP.build(kv.getValue()); + break; + } + } +// assert id != null; +// if (fields == null) fields = Collections.emptyMap(); + return new Document(id, score, fields); + } + }; } diff --git a/src/main/java/redis/clients/jedis/search/FtSearchIteration.java b/src/main/java/redis/clients/jedis/search/FtSearchIteration.java index d8686e2186..c856e5d780 100644 --- a/src/main/java/redis/clients/jedis/search/FtSearchIteration.java +++ b/src/main/java/redis/clients/jedis/search/FtSearchIteration.java @@ -4,6 +4,7 @@ import java.util.function.IntFunction; import redis.clients.jedis.CommandArguments; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.providers.ConnectionProvider; import redis.clients.jedis.search.SearchResult.SearchResultBuilder; import redis.clients.jedis.util.JedisCommandIterationBase; @@ -18,7 +19,22 @@ public class FtSearchIteration extends JedisCommandIterationBase new CommandArguments(SearchProtocol.SearchCommand.SEARCH) .add(indexName).add(query).addParams(params.limit(limitFirst, this.batchSize)); @@ -27,8 +43,9 @@ public FtSearchIteration(ConnectionProvider connectionProvider, int batchSize, S /** * {@link Query#limit(java.lang.Integer, java.lang.Integer)} will be ignored. */ - public FtSearchIteration(ConnectionProvider connectionProvider, int batchSize, String indexName, Query query) { - super(connectionProvider, new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true)); + public FtSearchIteration(ConnectionProvider connectionProvider, RedisProtocol protocol, int batchSize, String indexName, Query query) { + super(connectionProvider, protocol == RedisProtocol.RESP3 ? SearchResult.SEARCH_RESULT_BUILDER + : new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true)); this.batchSize = batchSize; this.args = (limitFirst) -> new CommandArguments(SearchProtocol.SearchCommand.SEARCH) .add(indexName).addParams(query.limit(limitFirst, this.batchSize)); diff --git a/src/main/java/redis/clients/jedis/search/RediSearchCommands.java b/src/main/java/redis/clients/jedis/search/RediSearchCommands.java index d128babf83..1e09266ad7 100644 --- a/src/main/java/redis/clients/jedis/search/RediSearchCommands.java +++ b/src/main/java/redis/clients/jedis/search/RediSearchCommands.java @@ -50,6 +50,7 @@ default SearchResult ftSearch(String indexName) { SearchResult ftSearch(String indexName, Query query); + @Deprecated SearchResult ftSearch(byte[] indexName, Query query); String ftExplain(String indexName, Query query); @@ -106,9 +107,9 @@ Map> ftSpellCheck(String index, String query, String ftAliasDel(String aliasName); - Map ftConfigGet(String option); + Map ftConfigGet(String option); - Map ftConfigGet(String indexName, String option); + Map ftConfigGet(String indexName, String option); String ftConfigSet(String option, String value); @@ -130,5 +131,5 @@ Map> ftSpellCheck(String index, String query, long ftSugLen(String key); - List ftList(); + Set ftList(); } diff --git a/src/main/java/redis/clients/jedis/search/RediSearchPipelineCommands.java b/src/main/java/redis/clients/jedis/search/RediSearchPipelineCommands.java index 87a4954a4f..ed633ea35a 100644 --- a/src/main/java/redis/clients/jedis/search/RediSearchPipelineCommands.java +++ b/src/main/java/redis/clients/jedis/search/RediSearchPipelineCommands.java @@ -51,6 +51,7 @@ default Response ftSearch(String indexName) { Response ftSearch(String indexName, Query query); + @Deprecated Response ftSearch(byte[] indexName, Query query); Response ftExplain(String indexName, Query query); @@ -84,9 +85,9 @@ Response>> ftSpellCheck(String index, String que Response> ftTagVals(String indexName, String fieldName); - Response> ftConfigGet(String option); + Response> ftConfigGet(String option); - Response> ftConfigGet(String indexName, String option); + Response> ftConfigGet(String indexName, String option); Response ftConfigSet(String option, String value); diff --git a/src/main/java/redis/clients/jedis/search/SearchBuilderFactory.java b/src/main/java/redis/clients/jedis/search/SearchBuilderFactory.java index e4490efdfb..8702b4a307 100644 --- a/src/main/java/redis/clients/jedis/search/SearchBuilderFactory.java +++ b/src/main/java/redis/clients/jedis/search/SearchBuilderFactory.java @@ -3,34 +3,21 @@ import static redis.clients.jedis.BuilderFactory.STRING; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import redis.clients.jedis.Builder; import redis.clients.jedis.BuilderFactory; -import redis.clients.jedis.search.aggr.AggregationResult; import redis.clients.jedis.util.DoublePrecision; +import redis.clients.jedis.util.KeyValue; import redis.clients.jedis.util.SafeEncoder; public final class SearchBuilderFactory { - public static final Builder SEARCH_AGGREGATION_RESULT = new Builder() { - @Override - public AggregationResult build(Object data) { - return new AggregationResult(data); - } - }; - - public static final Builder SEARCH_AGGREGATION_RESULT_WITH_CURSOR = new Builder() { - @Override - public AggregationResult build(Object data) { - List list = (List) data; - return new AggregationResult(list.get(0), (long) list.get(1)); - } - }; - public static final Builder> SEARCH_PROFILE_PROFILE = new Builder>() { private final String ITERATORS_PROFILE_STR = "Iterators profile"; @@ -131,7 +118,14 @@ private Object parseIterators(Object data) { public static final Builder>> SEARCH_SYNONYM_GROUPS = new Builder>>() { @Override public Map> build(Object data) { - List list = (List) data; + List list = (List) data; + if (list.isEmpty()) return Collections.emptyMap(); + + if (list.get(0) instanceof KeyValue) { + return ((List) data).stream().collect(Collectors.toMap( + kv -> STRING.build(kv.getKey()), kv -> BuilderFactory.STRING_LIST.build(kv.getValue()))); + } + Map> dump = new HashMap<>(list.size() / 2, 1f); for (int i = 0; i < list.size(); i += 2) { dump.put(STRING.build(list.get(i)), BuilderFactory.STRING_LIST.build(list.get(i + 1))); @@ -143,15 +137,33 @@ public Map> build(Object data) { public static final Builder>> SEARCH_SPELLCHECK_RESPONSE = new Builder>>() { - private final String TERM = "TERM"; + private static final String TERM = "TERM"; + private static final String RESULTS = "results"; @Override public Map> build(Object data) { - List rawTerms = (List) data; - Map> returnTerms = new LinkedHashMap<>(rawTerms.size()); + List rawDataList = (List) data; + if (rawDataList.isEmpty()) return Collections.emptyMap(); + + if (rawDataList.get(0) instanceof KeyValue) { + KeyValue rawData = (KeyValue) rawDataList.get(0); + String header = STRING.build(rawData.getKey()); + if (!RESULTS.equals(header)) { + throw new IllegalStateException("Unrecognized header: " + header); + } + + return ((List) rawData.getValue()).stream().collect(Collectors.toMap( + rawTerm -> STRING.build(rawTerm.getKey()), + rawTerm -> ((List>) rawTerm.getValue()).stream() + .collect(Collectors.toMap(entry -> STRING.build(entry.get(0).getKey()), + entry -> BuilderFactory.DOUBLE.build(entry.get(0).getValue()))), + (x, y) -> x, LinkedHashMap::new)); + } + + Map> returnTerms = new LinkedHashMap<>(rawDataList.size()); - for (Object rawTerm : rawTerms) { - List rawElements = (List) rawTerm; + for (Object rawData : rawDataList) { + List rawElements = (List) rawData; String header = STRING.build(rawElements.get(0)); if (!TERM.equals(header)) { diff --git a/src/main/java/redis/clients/jedis/search/SearchResult.java b/src/main/java/redis/clients/jedis/search/SearchResult.java index e756a54e6a..cc28cc942a 100644 --- a/src/main/java/redis/clients/jedis/search/SearchResult.java +++ b/src/main/java/redis/clients/jedis/search/SearchResult.java @@ -1,9 +1,12 @@ package redis.clients.jedis.search; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import redis.clients.jedis.Builder; import redis.clients.jedis.BuilderFactory; +import redis.clients.jedis.util.KeyValue; /** * SearchResult encapsulates the returned result from a search query. It contains publicly @@ -25,7 +28,13 @@ public long getTotalResults() { } public List getDocuments() { - return documents; + return Collections.unmodifiableList(documents); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{Total results:" + totalResults + + ", Documents:" + documents + "}"; } public static class SearchResultBuilder extends Builder { @@ -72,4 +81,31 @@ public SearchResult build(Object data) { return new SearchResult(totalResults, documents); } } + + public static Builder SEARCH_RESULT_BUILDER = new Builder() { + + private static final String TOTAL_RESULTS_STR = "total_results"; + private static final String RESULTS_STR = "results"; + + @Override + public SearchResult build(Object data) { + List list = (List) data; + long totalResults = -1; + List results = null; + for (KeyValue kv : list) { + String key = BuilderFactory.STRING.build(kv.getKey()); + switch (key) { + case TOTAL_RESULTS_STR: + totalResults = BuilderFactory.LONG.build(kv.getValue()); + break; + case RESULTS_STR: + results = ((List) kv.getValue()).stream() + .map(Document.SEARCH_DOCUMENT::build) + .collect(Collectors.toList()); + break; + } + } + return new SearchResult(totalResults, results); + } + }; } diff --git a/src/main/java/redis/clients/jedis/search/aggr/AggregationResult.java b/src/main/java/redis/clients/jedis/search/aggr/AggregationResult.java index 67133c5f18..cec65f9cd9 100644 --- a/src/main/java/redis/clients/jedis/search/aggr/AggregationResult.java +++ b/src/main/java/redis/clients/jedis/search/aggr/AggregationResult.java @@ -1,12 +1,16 @@ package redis.clients.jedis.search.aggr; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import redis.clients.jedis.Builder; +import redis.clients.jedis.BuilderFactory; import redis.clients.jedis.exceptions.JedisDataException; +import redis.clients.jedis.util.KeyValue; import redis.clients.jedis.util.SafeEncoder; public class AggregationResult { @@ -15,14 +19,14 @@ public class AggregationResult { private final List> results; - private long cursorId = -1; + private Long cursorId = -1L; - public AggregationResult(Object resp, long cursorId) { + private AggregationResult(Object resp, long cursorId) { this(resp); this.cursorId = cursorId; } - public AggregationResult(Object resp) { + private AggregationResult(Object resp) { List list = (List) SafeEncoder.encodeObject(resp); // the first element is always the number of results @@ -43,12 +47,25 @@ public AggregationResult(Object resp) { } } + private AggregationResult(long totalResults, List> results) { + this.totalResults = totalResults; + this.results = results; + } + + private void setCursorId(Long cursorId) { + this.cursorId = cursorId; + } + + public Long getCursorId() { + return cursorId; + } + public long getTotalResults() { return totalResults; } public List> getResults() { - return results; + return Collections.unmodifiableList(results); } /** @@ -63,7 +80,75 @@ public Row getRow(int index) { return new Row(results.get(index)); } - public long getCursorId() { - return cursorId; - } + public static final Builder SEARCH_AGGREGATION_RESULT = new Builder() { + + private static final String TOTAL_RESULTS_STR = "total_results"; + private static final String RESULTS_STR = "results"; + // private static final String FIELDS_STR = "fields"; + private static final String FIELDS_STR = "extra_attributes"; + + @Override + public AggregationResult build(Object data) { + // return new AggregationResult(data); + List list = (List) data; + + if (list.get(0) instanceof KeyValue) { + List kvList = (List) data; + long totalResults = -1; + List> results = null; + for (KeyValue kv : kvList) { + String key = BuilderFactory.STRING.build(kv.getKey()); + switch (key) { + case TOTAL_RESULTS_STR: + totalResults = BuilderFactory.LONG.build(kv.getValue()); + break; + case RESULTS_STR: + List> resList = (List>) kv.getValue(); + results = new ArrayList<>(resList.size()); + for (List rikv : resList) { + for (KeyValue ikv : rikv) { + if (FIELDS_STR.equals(BuilderFactory.STRING.build(ikv.getKey()))) { + results.add(BuilderFactory.ENCODED_OBJECT_MAP.build(ikv.getValue())); + break; + } + } + } + break; + } + } + return new AggregationResult(totalResults, results); + } + + list = (List) SafeEncoder.encodeObject(data); + + // the first element is always the number of results + long totalResults = (Long) list.get(0); + List> results = new ArrayList<>(list.size() - 1); + + for (int i = 1; i < list.size(); i++) { + List mapList = (List) list.get(i); + Map map = new HashMap<>(mapList.size() / 2, 1f); + for (int j = 0; j < mapList.size(); j += 2) { + Object r = mapList.get(j); + if (r instanceof JedisDataException) { + throw (JedisDataException) r; + } + map.put((String) r, mapList.get(j + 1)); + } + results.add(map); + } + return new AggregationResult(totalResults, results); + } + }; + + public static final Builder SEARCH_AGGREGATION_RESULT_WITH_CURSOR = new Builder() { + @Override + public AggregationResult build(Object data) { + List list = (List) data; + // return new AggregationResult(list.get(0), (long) list.get(1)); + AggregationResult r = SEARCH_AGGREGATION_RESULT.build(list.get(0)); + r.setCursorId((Long) list.get(1)); + return r; + } + }; } diff --git a/src/main/java/redis/clients/jedis/search/aggr/FtAggregateIteration.java b/src/main/java/redis/clients/jedis/search/aggr/FtAggregateIteration.java index f35100af09..931834ed49 100644 --- a/src/main/java/redis/clients/jedis/search/aggr/FtAggregateIteration.java +++ b/src/main/java/redis/clients/jedis/search/aggr/FtAggregateIteration.java @@ -4,7 +4,6 @@ import redis.clients.jedis.CommandArguments; import redis.clients.jedis.providers.ConnectionProvider; -import redis.clients.jedis.search.SearchBuilderFactory; import redis.clients.jedis.search.SearchProtocol; import redis.clients.jedis.util.JedisCommandIterationBase; @@ -20,7 +19,7 @@ public class FtAggregateIteration extends JedisCommandIterationBase searchResult = p.ftSearch(index, new Query("hello world")); - Response searchBytesResult = p.ftSearch(index.getBytes(), new Query("hello world")); +// Response searchBytesResult = p.ftSearch(index.getBytes(), new Query("hello world")); // not RESP3 supported Response aggregateResult = p.ftAggregate(index, new AggregationBuilder().groupBy("@title")); Response explain = p.ftExplain(index, new Query("@title:title_val")); Response> explainCLI = p.ftExplainCLI(index, new Query("@title:title_val")); Response> info = p.ftInfo(index); Response configSet = p.ftConfigSet("timeout", "100"); - Response> configGet = p.ftConfigGet("*"); + Response> configGet = p.ftConfigGet("*"); Response configSetIndex = p.ftConfigSet(index, "timeout", "100"); - Response> configGetIndex = p.ftConfigGet(index, "*"); + Response> configGetIndex = p.ftConfigGet(index, "*"); Response synUpdate = p.ftSynUpdate(index, "foo", "bar"); Response>> synDump = p.ftSynDump(index); @@ -71,7 +71,7 @@ public void search() { assertEquals("OK", alter.get()); assertEquals("OK", alter.get()); assertEquals(2, searchResult.get().getTotalResults()); - assertEquals(2, searchBytesResult.get().getTotalResults()); +// assertEquals(2, searchBytesResult.get().getTotalResults()); assertEquals(1, aggregateResult.get().getTotalResults()); assertNotNull(explain.get()); assertNotNull(explainCLI.get().get(0)); diff --git a/src/test/java/redis/clients/jedis/modules/json/JsonObjects.java b/src/test/java/redis/clients/jedis/modules/json/JsonObjects.java index f605ca973f..f67cfe8637 100644 --- a/src/test/java/redis/clients/jedis/modules/json/JsonObjects.java +++ b/src/test/java/redis/clients/jedis/modules/json/JsonObjects.java @@ -2,7 +2,6 @@ import java.time.Instant; import java.util.List; -import java.util.Map; import java.util.Objects; public class JsonObjects { diff --git a/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java b/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java index 14f210ae8a..b594f28dd1 100644 --- a/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java @@ -11,11 +11,14 @@ import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.search.Document; import redis.clients.jedis.search.FieldName; @@ -27,6 +30,7 @@ import redis.clients.jedis.search.aggr.Row; import redis.clients.jedis.search.aggr.SortedField; import redis.clients.jedis.modules.RedisModuleCommandsTestBase; +import redis.clients.jedis.search.FTProfileParams; import redis.clients.jedis.search.aggr.FtAggregateIteration; import redis.clients.jedis.search.schemafields.NumericField; import redis.clients.jedis.search.schemafields.TextField; @@ -123,6 +127,52 @@ public void testAggregations2() { assertEquals("10", rows.get(1).get("sum")); } + @Test + public void testAggregations2Profile() { + Schema sc = new Schema(); + sc.addSortableTextField("name", 1.0); + sc.addSortableNumericField("count"); + client.ftCreate(index, IndexOptions.defaultOptions(), sc); + + addDocument(new Document("data1").set("name", "abc").set("count", 10)); + addDocument(new Document("data2").set("name", "def").set("count", 5)); + addDocument(new Document("data3").set("name", "def").set("count", 25)); + + AggregationBuilder aggr = new AggregationBuilder() + .groupBy("@name", Reducers.sum("@count").as("sum")) + .sortBy(10, SortedField.desc("@sum")); + + Map.Entry> reply + = client.ftProfileAggregate(index, FTProfileParams.profileParams(), aggr); + + // actual search + AggregationResult result = reply.getKey(); + assertEquals(2, result.getTotalResults()); + + List rows = result.getRows(); + assertEquals("def", rows.get(0).get("name")); + assertEquals("30", rows.get(0).get("sum")); + assertNull(rows.get(0).get("nosuchcol")); + + assertEquals("abc", rows.get(1).get("name")); + assertEquals("10", rows.get(1).get("sum")); + + // profile + Map profile = reply.getValue(); + + assertEquals(Arrays.asList("Index", "Grouper", "Sorter"), + ((List>) profile.get("Result processors profile")).stream() + .map(map -> map.get("Type")).collect(Collectors.toList())); + + if (protocol != RedisProtocol.RESP3) { + assertEquals("WILDCARD", ((Map) profile.get("Iterators profile")).get("Type")); + } else { + assertEquals(Arrays.asList("WILDCARD"), + ((List>) profile.get("Iterators profile")).stream() + .map(map -> map.get("Type")).collect(Collectors.toList())); + } + } + @Test public void testAggregationBuilderVerbatim() { Schema sc = new Schema(); diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchConfigTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchConfigTest.java index b180711cc7..bda3cbe4d1 100644 --- a/src/test/java/redis/clients/jedis/modules/search/SearchConfigTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/SearchConfigTest.java @@ -5,10 +5,8 @@ import java.util.Collections; import java.util.Map; - import org.junit.BeforeClass; import org.junit.Test; - import redis.clients.jedis.modules.RedisModuleCommandsTestBase; public class SearchConfigTest extends RedisModuleCommandsTestBase { @@ -25,12 +23,14 @@ public static void prepare() { @Test public void config() { - Map map = client.ftConfigGet("TIMEOUT"); + Map map = client.ftConfigGet("TIMEOUT"); assertEquals(1, map.size()); - String value = map.get("TIMEOUT"); - assertNotNull(value); - - assertEquals("OK", client.ftConfigSet("timeout", value)); + String value = (String) map.get("TIMEOUT"); + try { + assertNotNull(value); + } finally { + assertEquals("OK", client.ftConfigSet("timeout", value)); + } } @Test @@ -38,11 +38,14 @@ public void configOnTimeout() { // confirm default assertEquals(Collections.singletonMap("ON_TIMEOUT", "return"), client.ftConfigGet("ON_TIMEOUT")); - assertEquals("OK", client.ftConfigSet("ON_TIMEOUT", "fail")); - assertEquals(Collections.singletonMap("ON_TIMEOUT", "fail"), client.ftConfigGet("ON_TIMEOUT")); + try { + assertEquals("OK", client.ftConfigSet("ON_TIMEOUT", "fail")); + assertEquals(Collections.singletonMap("ON_TIMEOUT", "fail"), client.ftConfigGet("ON_TIMEOUT")); - // restore to default - assertEquals("OK", client.ftConfigSet("ON_TIMEOUT", "return")); + } finally { + // restore to default + assertEquals("OK", client.ftConfigSet("ON_TIMEOUT", "return")); + } } @Test @@ -50,10 +53,13 @@ public void dialectConfig() { // confirm default assertEquals(Collections.singletonMap("DEFAULT_DIALECT", "1"), client.ftConfigGet("DEFAULT_DIALECT")); - assertEquals("OK", client.ftConfigSet("DEFAULT_DIALECT", "2")); - assertEquals(Collections.singletonMap("DEFAULT_DIALECT", "2"), client.ftConfigGet("DEFAULT_DIALECT")); + try { + assertEquals("OK", client.ftConfigSet("DEFAULT_DIALECT", "2")); + assertEquals(Collections.singletonMap("DEFAULT_DIALECT", "2"), client.ftConfigGet("DEFAULT_DIALECT")); - // restore to default - assertEquals("OK", client.ftConfigSet("DEFAULT_DIALECT", "1")); + } finally { + // restore to default + assertEquals("OK", client.ftConfigSet("DEFAULT_DIALECT", "1")); + } } } diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchTest.java index c36c3db2ca..b8656ff344 100644 --- a/src/test/java/redis/clients/jedis/modules/search/SearchTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/SearchTest.java @@ -3,10 +3,13 @@ import static org.junit.Assert.*; import java.util.*; +import java.util.stream.Collectors; import org.hamcrest.Matchers; +import org.junit.Assume; import org.junit.BeforeClass; import org.junit.Test; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.json.Path; import redis.clients.jedis.search.*; @@ -155,11 +158,6 @@ public void alterAdd() throws Exception { } SearchResult res2 = client.ftSearch(index, new Query("@tags:{tagA}")); assertEquals(100, res2.getTotalResults()); - - Map info = client.ftInfo(index); - assertEquals(index, info.get("index_name")); - assertEquals("identifier", ((List) ((List) info.get("attributes")).get(1)).get(0)); - assertEquals("attribute", ((List) ((List) info.get("attributes")).get(1)).get(2)); } @Test @@ -373,8 +371,13 @@ public void testQueryFlags() throws Exception { res = client.ftSearch(index, q); for (Document d : res.getDocuments()) { assertTrue(d.getId().startsWith("doc")); - assertEquals(1.0, d.getScore(), 0); - assertNull(d.get("title")); + if (protocol != RedisProtocol.RESP3) { + assertEquals(1.0, d.getScore(), 0); + assertNull(d.get("title")); + } else { + assertNull(d.getScore()); + assertThrows(NullPointerException.class, () -> d.get("title")); + } } // test verbatim vs. stemming @@ -644,8 +647,13 @@ public void info() throws Exception { Map info = client.ftInfo(index); assertEquals(index, info.get("index_name")); assertEquals(6, ((List) info.get("attributes")).size()); - assertEquals("global_idle", ((List) info.get("cursor_stats")).get(0)); - assertEquals(0L, ((List) info.get("cursor_stats")).get(1)); + if (protocol != RedisProtocol.RESP3) { + assertEquals("global_idle", ((List) info.get("cursor_stats")).get(0)); + assertEquals(0L, ((List) info.get("cursor_stats")).get(1)); + } else { + assertEquals(0L, ((Map) info.get("cursor_stats")).get("global_idle")); + assertEquals(128L, ((Map) info.get("cursor_stats")).get("index_capacity")); + } } @Test @@ -892,6 +900,8 @@ public void inKeys() throws Exception { @Test public void blobField() throws Exception { + Assume.assumeFalse(protocol == RedisProtocol.RESP3); // not supporting + Schema sc = new Schema().addTextField("field1", 1.0); assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions(), sc)); @@ -1123,6 +1133,43 @@ public void testDialectsWithFTExplain() throws Exception { assertTrue("Should contain '{K=10 nearest vector'", client.ftExplain(index, query).contains("{K=10 nearest vector")); } + @Test + public void searchProfile() { + Schema sc = new Schema().addTextField("t1", 1.0).addTextField("t2", 1.0); + assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions(), sc)); + + Map hash = new HashMap<>(); + hash.put("t1", "foo"); + hash.put("t2", "bar"); + client.hset("doc1", hash); + + Map.Entry> reply = client.ftProfileSearch(index, + FTProfileParams.profileParams(), new Query("foo")); + + SearchResult result = reply.getKey(); + assertEquals(1, result.getTotalResults()); + assertEquals(Collections.singletonList("doc1"), result.getDocuments().stream().map(Document::getId).collect(Collectors.toList())); + + Map profile = reply.getValue(); + Map iteratorsProfile; + if (protocol != RedisProtocol.RESP3) { + iteratorsProfile = (Map) profile.get("Iterators profile"); + } else { + List iteratorsProfileList = (List) profile.get("Iterators profile"); + assertEquals(1, iteratorsProfileList.size()); + iteratorsProfile = (Map) iteratorsProfileList.get(0); + } + assertEquals("TEXT", iteratorsProfile.get("Type")); + assertEquals("foo", iteratorsProfile.get("Term")); + assertEquals(1L, iteratorsProfile.get("Counter")); + assertEquals(1L, iteratorsProfile.get("Size")); + assertSame(Double.class, iteratorsProfile.get("Time").getClass()); + + assertEquals(Arrays.asList("Index", "Scorer", "Sorter", "Loader"), + ((List>) profile.get("Result processors profile")).stream() + .map(map -> map.get("Type")).collect(Collectors.toList())); + } + @Test public void testHNSWVVectorSimilarity() { Map attr = new HashMap<>(); @@ -1147,13 +1194,18 @@ public void testHNSWVVectorSimilarity() { assertEquals("0", doc1.get("__v_score")); // profile - Map.Entry> profile + Map.Entry> reply = client.ftProfileSearch(index, FTProfileParams.profileParams(), query); - doc1 = profile.getKey().getDocuments().get(0); + doc1 = reply.getKey().getDocuments().get(0); assertEquals("a", doc1.getId()); assertEquals("0", doc1.get("__v_score")); - Map iteratorsProfile = (Map) profile.getValue().get("Iterators profile"); - assertEquals("VECTOR", iteratorsProfile.get("Type")); + if (protocol != RedisProtocol.RESP3) { + assertEquals("VECTOR", ((Map) reply.getValue().get("Iterators profile")).get("Type")); + } else { + assertEquals(Arrays.asList("VECTOR"), + ((List>) reply.getValue().get("Iterators profile")).stream() + .map(map -> map.get("Type")).collect(Collectors.toList())); + } } @Test @@ -1180,34 +1232,18 @@ public void testFlatVectorSimilarity() { assertEquals("0", doc1.get("__v_score")); // profile - Map.Entry> profile + Map.Entry> reply = client.ftProfileSearch(index, FTProfileParams.profileParams(), query); - doc1 = profile.getKey().getDocuments().get(0); + doc1 = reply.getKey().getDocuments().get(0); assertEquals("a", doc1.getId()); assertEquals("0", doc1.get("__v_score")); - Map iteratorsProfile = (Map) profile.getValue().get("Iterators profile"); - assertEquals("VECTOR", iteratorsProfile.get("Type")); - } - - @Test - public void searchProfile() { - Schema sc = new Schema().addTextField("t1", 1.0).addTextField("t2", 1.0); - assertEquals("OK", client.ftCreate(index, IndexOptions.defaultOptions(), sc)); - - Map map = new HashMap<>(); - map.put("t1", "foo"); - map.put("t2", "bar"); - client.hset("doc1", map); - - Map.Entry> profile = client.ftProfileSearch(index, - FTProfileParams.profileParams(), new Query("foo")); - // Iterators profile={Type=TEXT, Time=0.0, Term=foo, Counter=1, Size=1} - Map iteratorsProfile = (Map) profile.getValue().get("Iterators profile"); - assertEquals("TEXT", iteratorsProfile.get("Type")); - assertEquals("foo", iteratorsProfile.get("Term")); - assertEquals(1L, iteratorsProfile.get("Counter")); - assertEquals(1L, iteratorsProfile.get("Size")); - assertSame(Double.class, iteratorsProfile.get("Time").getClass()); + if (protocol != RedisProtocol.RESP3) { + assertEquals("VECTOR", ((Map) reply.getValue().get("Iterators profile")).get("Type")); + } else { + assertEquals(Arrays.asList("VECTOR"), + ((List>) reply.getValue().get("Iterators profile")).stream() + .map(map -> map.get("Type")).collect(Collectors.toList())); + } } @Test diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java index bcdee83679..98bc5968e8 100644 --- a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java @@ -10,6 +10,7 @@ import org.junit.Test; import redis.clients.jedis.GeoCoordinate; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.GeoUnit; import redis.clients.jedis.args.SortingOrder; import redis.clients.jedis.exceptions.JedisDataException; @@ -163,11 +164,6 @@ public void alterAdd() { } SearchResult res2 = client.ftSearch(index, "@tags:{tagA}"); assertEquals(100, res2.getTotalResults()); - - Map info = client.ftInfo(index); - assertEquals(index, info.get("index_name")); - assertEquals("identifier", ((List) ((List) info.get("attributes")).get(1)).get(0)); - assertEquals("attribute", ((List) ((List) info.get("attributes")).get(1)).get(2)); } @Test @@ -371,8 +367,13 @@ public void testQueryFlags() { FTSearchParams.searchParams().noContent()); for (Document d : res.getDocuments()) { assertTrue(d.getId().startsWith("doc")); - assertEquals(1.0, d.getScore(), 0); - assertNull(d.get("title")); + if (protocol != RedisProtocol.RESP3) { + assertEquals(1.0, d.getScore(), 0); + assertNull(d.get("title")); + } else { + assertNull(d.getScore()); + assertThrows(NullPointerException.class, () -> d.get("title")); + } } // test verbatim vs. stemming @@ -566,8 +567,12 @@ public void info() { Map info = client.ftInfo(index); assertEquals(index, info.get("index_name")); assertEquals(6, ((List) info.get("attributes")).size()); - assertEquals("global_idle", ((List) info.get("cursor_stats")).get(0)); - assertEquals(0L, ((List) info.get("cursor_stats")).get(1)); + if (protocol != RedisProtocol.RESP3) { + assertEquals("global_idle", ((List) info.get("cursor_stats")).get(0)); + assertEquals(0L, ((List) info.get("cursor_stats")).get(1)); + } else { + assertEquals(0L, ((Map) info.get("cursor_stats")).get("global_idle")); + } } @Test @@ -945,20 +950,36 @@ public void testFlatVectorSimilarity() { public void searchProfile() { assertOK(client.ftCreate(index, TextField.of("t1"), TextField.of("t2"))); - Map map = new HashMap<>(); - map.put("t1", "foo"); - map.put("t2", "bar"); - client.hset("doc1", map); + Map hash = new HashMap<>(); + hash.put("t1", "foo"); + hash.put("t2", "bar"); + client.hset("doc1", hash); - Map.Entry> profile = client.ftProfileSearch(index, + Map.Entry> reply = client.ftProfileSearch(index, FTProfileParams.profileParams(), "foo", FTSearchParams.searchParams()); - // Iterators profile={Type=TEXT, Time=0.0, Term=foo, Counter=1, Size=1} - Map iteratorsProfile = (Map) profile.getValue().get("Iterators profile"); + + SearchResult result = reply.getKey(); + assertEquals(1, result.getTotalResults()); + assertEquals(Collections.singletonList("doc1"), result.getDocuments().stream().map(Document::getId).collect(Collectors.toList())); + + Map profile = reply.getValue(); + Map iteratorsProfile; + if (protocol != RedisProtocol.RESP3) { + iteratorsProfile = (Map) profile.get("Iterators profile"); + } else { + List iteratorsProfileList = (List) profile.get("Iterators profile"); + assertEquals(1, iteratorsProfileList.size()); + iteratorsProfile = (Map) iteratorsProfileList.get(0); + } assertEquals("TEXT", iteratorsProfile.get("Type")); assertEquals("foo", iteratorsProfile.get("Term")); assertEquals(1L, iteratorsProfile.get("Counter")); assertEquals(1L, iteratorsProfile.get("Size")); assertSame(Double.class, iteratorsProfile.get("Time").getClass()); + + assertEquals(Arrays.asList("Index", "Scorer", "Sorter", "Loader"), + ((List>) profile.get("Result processors profile")).stream() + .map(map -> map.get("Type")).collect(Collectors.toList())); } @Test @@ -976,44 +997,59 @@ public void vectorSearchProfile() { FTSearchParams searchParams = FTSearchParams.searchParams().addParam("vec", "aaaaaaaa") .sortBy("__v_score", SortingOrder.ASC).noContent().dialect(2); - Map.Entry> profile = client.ftProfileSearch(index, + Map.Entry> reply = client.ftProfileSearch(index, FTProfileParams.profileParams(), "*=>[KNN 3 @v $vec]", searchParams); - assertEquals(3, profile.getKey().getTotalResults()); + assertEquals(3, reply.getKey().getTotalResults()); - assertEquals(Arrays.asList(4, 2, 1).toString(), profile.getKey().getDocuments() + assertEquals(Arrays.asList(4, 2, 1).toString(), reply.getKey().getDocuments() .stream().map(Document::getId).collect(Collectors.toList()).toString()); - Map iteratorsProfile = (Map) profile.getValue().get("Iterators profile"); - assertEquals("VECTOR", iteratorsProfile.get("Type")); - assertEquals(3L, iteratorsProfile.get("Counter")); + Map profile = reply.getValue(); - List> resultProcessorsProfile = (List>) profile.getValue().get("Result processors profile"); - // assertEquals("Vector Similarity Scores Loader", resultProcessorsProfile.get(1).get("Type")); // Changed to "Metrics Applier" - assertEquals(3l, resultProcessorsProfile.get(1).get("Counter")); + if (protocol != RedisProtocol.RESP3) { + assertEquals("VECTOR", ((Map) profile.get("Iterators profile")).get("Type")); + } else { + assertEquals(Arrays.asList("VECTOR"), + ((List>) profile.get("Iterators profile")).stream() + .map(map -> map.get("Type")).collect(Collectors.toList())); + } + + List> resultProcessorsProfile + = (List>) reply.getValue().get("Result processors profile"); + assertEquals(3, resultProcessorsProfile.size()); + assertEquals("Index", resultProcessorsProfile.get(0).get("Type")); + assertEquals("Sorter", resultProcessorsProfile.get(2).get("Type")); } @Test public void maxPrefixExpansionSearchProfile() { final String configParam = "MAXPREFIXEXPANSIONS"; - String configValue = client.ftConfigGet(configParam).get(configParam); - client.ftConfigSet(configParam, "2"); - - assertOK(client.ftCreate(index, TextField.of("t"))); - client.hset("1", Collections.singletonMap("t", "foo1")); - client.hset("2", Collections.singletonMap("t", "foo2")); - client.hset("3", Collections.singletonMap("t", "foo3")); - - Map.Entry> profile = client.ftProfileSearch(index, - FTProfileParams.profileParams(), "foo*", FTSearchParams.searchParams().limit(0, 0)); - // Warning=Max prefix expansion reached - Map iteratorsProfile = (Map) profile.getValue().get("Iterators profile"); - assertEquals("Max prefix expansion reached", iteratorsProfile.get("Warning")); - - client.ftConfigSet(configParam, configValue); + String configValue = (String) client.ftConfigGet(configParam).get(configParam); + try { + client.ftConfigSet(configParam, "2"); + + assertOK(client.ftCreate(index, TextField.of("t"))); + client.hset("1", Collections.singletonMap("t", "foo1")); + client.hset("2", Collections.singletonMap("t", "foo2")); + client.hset("3", Collections.singletonMap("t", "foo3")); + + Map.Entry> reply = client.ftProfileSearch(index, + FTProfileParams.profileParams(), "foo*", FTSearchParams.searchParams().limit(0, 0)); + // Warning=Max prefix expansion reached + if (protocol != RedisProtocol.RESP3) { + assertEquals("Max prefix expansion reached", + ((Map) reply.getValue().get("Iterators profile")).get("Warning")); + } else { + assertEquals("Max prefix expansion reached", + ((Map) ((List) reply.getValue().get("Iterators profile")).get(0)).get("Warning")); + } + } finally { + client.ftConfigSet(configParam, configValue); + } } @Test - public void notIteratorSearchProfile() { + public void noContentSearchProfile() { assertOK(client.ftCreate(index, TextField.of("t"))); client.hset("1", Collections.singletonMap("t", "foo")); client.hset("2", Collections.singletonMap("t", "bar")); @@ -1021,15 +1057,22 @@ public void notIteratorSearchProfile() { Map.Entry> profile = client.ftProfileSearch(index, FTProfileParams.profileParams(), "foo -@t:baz", FTSearchParams.searchParams().noContent()); - Map depth0 = (Map) profile.getValue().get("Iterators profile"); + Map depth0 = protocol != RedisProtocol.RESP3 + ? (Map) profile.getValue().get("Iterators profile") + : ((List>) profile.getValue().get("Iterators profile")).get(0); + assertEquals("INTERSECT", depth0.get("Type")); List> depth0_children = (List>) depth0.get("Child iterators"); assertEquals("TEXT", depth0_children.get(0).get("Type")); Map depth1 = depth0_children.get(1); assertEquals("NOT", depth1.get("Type")); - List> depth1_children = (List>) depth1.get("Child iterators"); - assertEquals(1, depth1_children.size()); - assertEquals("EMPTY", depth1_children.get(0).get("Type")); + if (protocol != RedisProtocol.RESP3) { + List> depth1_children = (List>) depth1.get("Child iterators"); + assertEquals(1, depth1_children.size()); + assertEquals("EMPTY", depth1_children.get(0).get("Type")); + } else { + assertEquals("EMPTY", ((Map) depth1.get("Child iterator")).get("Type")); + } } @Test @@ -1042,7 +1085,10 @@ public void deepReplySearchProfile() { = client.ftProfileSearch(index, FTProfileParams.profileParams(), "hello(hello(hello(hello(hello(hello)))))", FTSearchParams.searchParams().noContent()); - Map depth0 = (Map) profile.getValue().get("Iterators profile"); + Map depth0 = protocol != RedisProtocol.RESP3 + ? (Map) profile.getValue().get("Iterators profile") + : ((List>) profile.getValue().get("Iterators profile")).get(0); + assertEquals("INTERSECT", depth0.get("Type")); List> depth0_children = (List>) depth0.get("Child iterators"); assertEquals("TEXT", depth0_children.get(0).get("Type")); @@ -1078,7 +1124,10 @@ public void limitedSearchProfile() { Map.Entry> profile = client.ftProfileSearch(index, FTProfileParams.profileParams().limited(), "%hell% hel*", FTSearchParams.searchParams().noContent()); - Map depth0 = (Map) profile.getValue().get("Iterators profile"); + Map depth0 = protocol != RedisProtocol.RESP3 + ? (Map) profile.getValue().get("Iterators profile") + : ((List>) profile.getValue().get("Iterators profile")).get(0); + assertEquals("INTERSECT", depth0.get("Type")); assertEquals(3L, depth0.get("Counter")); @@ -1087,15 +1136,19 @@ public void limitedSearchProfile() { for (Map depth1 : depth0_children) { assertEquals("UNION", depth1.get("Type")); assertNotNull(depth1.get("Query type")); - List depth1_children = (List) depth1.get("Child iterators"); - assertEquals(1, depth1_children.size()); - assertSame(String.class, depth1_children.get(0).getClass()); + if (protocol != RedisProtocol.RESP3) { + List depth1_children = (List) depth1.get("Child iterators"); + assertEquals(1, depth1_children.size()); + assertSame(String.class, depth1_children.get(0).getClass()); + } else { + assertSame(String.class, depth1.get("Child iterators").getClass()); + } } } @Test public void list() { - assertEquals(Collections.emptyList(), client.ftList()); + assertEquals(Collections.emptySet(), client.ftList()); final int count = 20; Set names = new HashSet<>(); @@ -1104,7 +1157,7 @@ public void list() { assertOK(client.ftCreate(name, TextField.of("t" + i))); names.add(name); } - assertEquals(names, new HashSet<>(client.ftList())); + assertEquals(names, client.ftList()); } @Test diff --git a/src/test/java/redis/clients/jedis/modules/search/SpellCheckTest.java b/src/test/java/redis/clients/jedis/modules/search/SpellCheckTest.java index c551b59d39..508ff4441a 100644 --- a/src/test/java/redis/clients/jedis/modules/search/SpellCheckTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/SpellCheckTest.java @@ -52,7 +52,8 @@ public void dictionary() { @Test public void dictionaryBySampleKey() { assertEquals(3L, client.ftDictAddBySampleKey(index, "dict", "foo", "bar", "hello world")); - assertEquals(new HashSet<>(Arrays.asList("foo", "bar", "hello world")), client.ftDictDumpBySampleKey(index, "dict")); + assertEquals(new HashSet<>(Arrays.asList("foo", "bar", "hello world")), + client.ftDictDumpBySampleKey(index, "dict")); assertEquals(3L, client.ftDictDelBySampleKey(index, "dict", "foo", "bar", "hello world")); assertEquals(Collections.emptySet(), client.ftDictDumpBySampleKey(index, "dict")); } @@ -61,8 +62,8 @@ public void dictionaryBySampleKey() { public void basicSpellCheck() { client.ftCreate(index, TextField.of("name"), TextField.of("body")); client.hset("doc1", toMap("name", "name1", "body", "body1")); - client.hset("doc1", toMap("name", "name2", "body", "body2")); - client.hset("doc1", toMap("name", "name2", "body", "name2")); + client.hset("doc2", toMap("name", "name2", "body", "body2")); + client.hset("doc3", toMap("name", "name2", "body", "name2")); Map> reply = client.ftSpellCheck(index, "name"); assertEquals(Collections.singleton("name"), reply.keySet()); @@ -74,7 +75,8 @@ public void crossTermDictionary() { client.ftCreate(index, TextField.of("report")); client.ftDictAdd("slang", "timmies", "toque", "toonie", "serviette", "kerfuffle", "chesterfield"); - Map> expected = Collections.singletonMap("tooni", Collections.singletonMap("toonie", 0d)); + Map> expected = Collections.singletonMap("tooni", + Collections.singletonMap("toonie", 0d)); assertEquals(expected, client.ftSpellCheck(index, "Tooni toque kerfuffle", FTSpellCheckParams.spellCheckParams().includeTerm("slang").excludeTerm("slang"))); } @@ -92,6 +94,7 @@ public void dialectBound() { JedisDataException error = Assert.assertThrows(JedisDataException.class, () -> client.ftSpellCheck(index, "Tooni toque kerfuffle", FTSpellCheckParams.spellCheckParams().dialect(0))); - MatcherAssert.assertThat(error.getMessage(), Matchers.containsString("DIALECT requires a non negative integer")); + MatcherAssert.assertThat(error.getMessage(), + Matchers.containsString("DIALECT requires a non negative integer")); } } From 29a8d34942f4e1606dd270690d4db2d86b145265 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Wed, 16 Aug 2023 19:13:51 +0600 Subject: [PATCH 08/23] Support Json commands after RESP3 update (#3460) * JSON.GET v2 RESP3 * JSON.NUMINCRBY v2 RESP3 * JSON.TYPE v2 RESP3 * cleanup prints * edit * Use interface in RedisJsonV1Test * JSON v1 commands with RESP3 * Comment out RedisJSON v1 with RESP3 * more * pipeline test * pipeline commands * Allow RESP3 in existing methods even though there are newer methods suffixed with 'Resp3' * cleanup commented codes * remove more commented codes * breaking changes list * rephrase doc * Address json module changes * Comment unused code * CLEANUP commented implementations * merge fix --- docs/jedis5-breaking.md | 4 ++ .../redis/clients/jedis/CommandObjects.java | 18 ++++-- .../redis/clients/jedis/PipelineBase.java | 2 +- .../redis/clients/jedis/TransactionBase.java | 2 +- .../redis/clients/jedis/UnifiedJedis.java | 2 +- .../jedis/json/JsonBuilderFactory.java | 26 ++++++++- .../json/commands/RedisJsonV2Commands.java | 2 +- .../commands/RedisJsonV2PipelineCommands.java | 2 +- .../modules/RedisModulesPipelineTest.java | 5 ++ .../jedis/modules/json/JsonObjects.java | 10 ++++ .../jedis/modules/json/RedisJsonV1Test.java | 57 +++++++++---------- .../jedis/modules/json/RedisJsonV2Test.java | 41 ++++++++++++- 12 files changed, 127 insertions(+), 44 deletions(-) diff --git a/docs/jedis5-breaking.md b/docs/jedis5-breaking.md index 7b373b2e77..6f5b50247f 100644 --- a/docs/jedis5-breaking.md +++ b/docs/jedis5-breaking.md @@ -40,6 +40,10 @@ - `tsMRevRange(long fromTimestamp, long toTimestamp, String... filters)` - `tsMRevRange(TSMRangeParams multiRangeParams)` +- `jsonNumIncrBy(String key, Path2 path, double value)` method now returns `Object` instead of `JSONArray`. + - Previously when it was returning JSONArray, returned would still be JSONArray. So simple type casting should be enough to handle this change. + - The returning object will be `List` when running under RESP3 protocol. + - `getAgeSeconds()` in `AccessControlLogEntry` now returns `Double` instead of `String`. - Both `ftConfigGet(String option)` and `ftConfigGet(String indexName, String option)` methods now return `Map` instead of `Map`. diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index b22cf94d2a..c96c4ede1b 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -3460,7 +3460,8 @@ public final CommandObject jsonMerge(String key, Path path, Object pojo) } public final CommandObject jsonGet(String key) { - return new CommandObject<>(commandArguments(JsonCommand.GET).key(key), new JsonObjectBuilder<>(Object.class)); + return new CommandObject<>(commandArguments(JsonCommand.GET).key(key), + protocol != RedisProtocol.RESP3 ? JSON_GENERIC_OBJECT : JsonBuilderFactory.JSON_OBJECT); } public final CommandObject jsonGet(String key, Class clazz) { @@ -3472,7 +3473,7 @@ public final CommandObject jsonGet(String key, Path2... paths) { } public final CommandObject jsonGet(String key, Path... paths) { - return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).addObjects((Object[]) paths), new JsonObjectBuilder<>(Object.class)); + return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).addObjects((Object[]) paths), JSON_GENERIC_OBJECT); } public final CommandObject jsonGetAsPlainString(String key, Path path) { @@ -3528,7 +3529,8 @@ public final CommandObject> jsonType(String key) { } public final CommandObject>> jsonType(String key, Path2 path) { - return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path), JsonBuilderFactory.JSON_TYPE_LIST); + return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path), + protocol != RedisProtocol.RESP3 ? JsonBuilderFactory.JSON_TYPE_LIST : JsonBuilderFactory.JSON_TYPE_RESPONSE_RESP3_COMPATIBLE); } public final CommandObject> jsonType(String key, Path path) { @@ -3562,8 +3564,9 @@ public final CommandObject jsonStrLen(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.STRLEN).key(key).add(path), BuilderFactory.LONG); } - public final CommandObject jsonNumIncrBy(String key, Path2 path, double value) { - return new CommandObject<>(commandArguments(JsonCommand.NUMINCRBY).key(key).add(path).add(value), JsonBuilderFactory.JSON_ARRAY); + public final CommandObject jsonNumIncrBy(String key, Path2 path, double value) { + return new CommandObject<>(commandArguments(JsonCommand.NUMINCRBY).key(key).add(path).add(value), + JsonBuilderFactory.JSON_ARRAY_OR_DOUBLE_LIST); } public final CommandObject jsonNumIncrBy(String key, Path path, double value) { @@ -4260,6 +4263,11 @@ public T build(Object data) { } } + /** + * {@link JsonObjectBuilder} for {@code Object.class}. + */ + private final Builder JSON_GENERIC_OBJECT = new JsonObjectBuilder<>(Object.class); + private class JsonObjectListBuilder extends Builder> { private final Class clazz; diff --git a/src/main/java/redis/clients/jedis/PipelineBase.java b/src/main/java/redis/clients/jedis/PipelineBase.java index b4b077a899..4c95e187d4 100644 --- a/src/main/java/redis/clients/jedis/PipelineBase.java +++ b/src/main/java/redis/clients/jedis/PipelineBase.java @@ -3607,7 +3607,7 @@ public Response jsonStrLen(String key, Path path) { } @Override - public Response jsonNumIncrBy(String key, Path2 path, double value) { + public Response jsonNumIncrBy(String key, Path2 path, double value) { return appendCommand(commandObjects.jsonNumIncrBy(key, path, value)); } diff --git a/src/main/java/redis/clients/jedis/TransactionBase.java b/src/main/java/redis/clients/jedis/TransactionBase.java index 03513c2e40..2c02316f59 100644 --- a/src/main/java/redis/clients/jedis/TransactionBase.java +++ b/src/main/java/redis/clients/jedis/TransactionBase.java @@ -3775,7 +3775,7 @@ public Response jsonStrLen(String key, Path path) { } @Override - public Response jsonNumIncrBy(String key, Path2 path, double value) { + public Response jsonNumIncrBy(String key, Path2 path, double value) { return appendCommand(commandObjects.jsonNumIncrBy(key, path, value)); } diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index 2063194290..e896dc882f 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -4056,7 +4056,7 @@ public Long jsonStrLen(String key, Path path) { } @Override - public JSONArray jsonNumIncrBy(String key, Path2 path, double value) { + public Object jsonNumIncrBy(String key, Path2 path, double value) { return executeCommand(commandObjects.jsonNumIncrBy(key, path, value)); } diff --git a/src/main/java/redis/clients/jedis/json/JsonBuilderFactory.java b/src/main/java/redis/clients/jedis/json/JsonBuilderFactory.java index 8b4ec686bc..e4c00f7045 100644 --- a/src/main/java/redis/clients/jedis/json/JsonBuilderFactory.java +++ b/src/main/java/redis/clients/jedis/json/JsonBuilderFactory.java @@ -9,6 +9,7 @@ import org.json.JSONException; import org.json.JSONObject; import redis.clients.jedis.Builder; +import redis.clients.jedis.BuilderFactory; import redis.clients.jedis.exceptions.JedisException; public final class JsonBuilderFactory { @@ -60,6 +61,21 @@ public List> build(Object data) { } }; + public static final Builder>>> JSON_TYPE_RESPONSE_RESP3 = new Builder>>>() { + @Override + public List>> build(Object data) { + return ((List) data).stream().map(JSON_TYPE_LIST::build).collect(Collectors.toList()); + } + }; + + public static final Builder>> JSON_TYPE_RESPONSE_RESP3_COMPATIBLE = new Builder>>() { + @Override + public List> build(Object data) { + List>> fullReply = JSON_TYPE_RESPONSE_RESP3.build(data); + return fullReply == null ? null : fullReply.get(0); + } + }; + public static final Builder JSON_OBJECT = new Builder() { @Override public Object build(Object data) { @@ -70,7 +86,6 @@ public Object build(Object data) { if (!(data instanceof byte[])) { return data; } - String str = STRING.build(data); if (str.charAt(0) == '{') { try { @@ -103,6 +118,15 @@ public JSONArray build(Object data) { } }; + public static final Builder JSON_ARRAY_OR_DOUBLE_LIST = new Builder() { + @Override + public Object build(Object data) { + if (data == null) return null; + if (data instanceof List) return BuilderFactory.DOUBLE_LIST.build(data); + return JSON_ARRAY.build(data); + } + }; + public static final Builder> JSON_ARRAY_LIST = new Builder>() { @Override public List build(Object data) { diff --git a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2Commands.java b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2Commands.java index 4cdc21c14f..95ff38aa34 100644 --- a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2Commands.java +++ b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2Commands.java @@ -59,7 +59,7 @@ default List jsonMGet(String... keys) { List jsonStrLen(String key, Path2 path); - JSONArray jsonNumIncrBy(String key, Path2 path, double value); + Object jsonNumIncrBy(String key, Path2 path, double value); List jsonArrAppend(String key, Path2 path, Object... objects); diff --git a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2PipelineCommands.java b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2PipelineCommands.java index 40d0542333..c6fbbac6b3 100644 --- a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2PipelineCommands.java +++ b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2PipelineCommands.java @@ -60,7 +60,7 @@ default Response> jsonMGet(String... keys) { Response> jsonStrLen(String key, Path2 path); - Response jsonNumIncrBy(String key, Path2 path, double value); + Response jsonNumIncrBy(String key, Path2 path, double value); Response> jsonArrAppend(String key, Path2 path, Object... objects); diff --git a/src/test/java/redis/clients/jedis/modules/RedisModulesPipelineTest.java b/src/test/java/redis/clients/jedis/modules/RedisModulesPipelineTest.java index 9b0c65eed5..50b48854da 100644 --- a/src/test/java/redis/clients/jedis/modules/RedisModulesPipelineTest.java +++ b/src/test/java/redis/clients/jedis/modules/RedisModulesPipelineTest.java @@ -14,16 +14,19 @@ import java.util.Collections; import org.json.JSONArray; import org.json.JSONObject; +import org.junit.Assume; import org.junit.BeforeClass; import org.junit.Test; import redis.clients.jedis.Pipeline; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.Response; import redis.clients.jedis.json.JsonSetParams; import redis.clients.jedis.json.Path; import redis.clients.jedis.json.Path2; import redis.clients.jedis.search.*; import redis.clients.jedis.search.aggr.*; +import redis.clients.jedis.util.RedisProtocolUtil; public class RedisModulesPipelineTest extends RedisModuleCommandsTestBase { @@ -88,6 +91,8 @@ public void search() { @Test public void jsonV1() { + Assume.assumeFalse(RedisProtocolUtil.getRedisProtocol() == RedisProtocol.RESP3); + Map hm1 = new HashMap<>(); hm1.put("hello", "world"); hm1.put("oh", "snap"); diff --git a/src/test/java/redis/clients/jedis/modules/json/JsonObjects.java b/src/test/java/redis/clients/jedis/modules/json/JsonObjects.java index f67cfe8637..dbe44ab3f8 100644 --- a/src/test/java/redis/clients/jedis/modules/json/JsonObjects.java +++ b/src/test/java/redis/clients/jedis/modules/json/JsonObjects.java @@ -17,6 +17,16 @@ public IRLObject() { this.str = "string"; this.bool = true; } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + final IRLObject other = (IRLObject) obj; + return Objects.equals(str, other.str) + && Objects.equals(bool, other.bool); + } } @SuppressWarnings("unused") diff --git a/src/test/java/redis/clients/jedis/modules/json/RedisJsonV1Test.java b/src/test/java/redis/clients/jedis/modules/json/RedisJsonV1Test.java index 856878ce68..6a672a0ede 100644 --- a/src/test/java/redis/clients/jedis/modules/json/RedisJsonV1Test.java +++ b/src/test/java/redis/clients/jedis/modules/json/RedisJsonV1Test.java @@ -16,16 +16,19 @@ import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; +import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.json.JsonSetParams; import redis.clients.jedis.json.Path; import redis.clients.jedis.json.commands.RedisJsonV1Commands; import redis.clients.jedis.modules.RedisModuleCommandsTestBase; import redis.clients.jedis.util.JsonObjectMapperTestUtil; +import redis.clients.jedis.util.RedisProtocolUtil; public class RedisJsonV1Test extends RedisModuleCommandsTestBase { @@ -35,6 +38,7 @@ public class RedisJsonV1Test extends RedisModuleCommandsTestBase { @BeforeClass public static void prepare() { + Assume.assumeFalse(RedisProtocolUtil.getRedisProtocol() == RedisProtocol.RESP3); RedisModuleCommandsTestBase.prepare(); } @@ -51,7 +55,7 @@ public void basicSetGetShouldSucceed() { // naive set with a path // jsonClient.jsonSet("null", null, ROOT_PATH); jsonClient.jsonSet("null", ROOT_PATH, (Object) null); - assertNull(client.jsonGet("null", String.class, ROOT_PATH)); + assertNull(jsonClient.jsonGet("null", String.class, ROOT_PATH)); // real scalar value and no path jsonClient.jsonSet("str", ROOT_PATH, "strong"); @@ -61,7 +65,7 @@ public void basicSetGetShouldSucceed() { IRLObject obj = new IRLObject(); jsonClient.jsonSet("obj", ROOT_PATH, obj); Object expected = gson.fromJson(gson.toJson(obj), Object.class); - assertTrue(expected.equals(client.jsonGet("obj"))); + assertTrue(expected.equals(jsonClient.jsonGet("obj"))); // check an update Path p = Path.of(".str"); @@ -97,14 +101,14 @@ public void setWithoutAPathDefaultsToRootPath() { public void setExistingPathOnlyIfNotExistsShouldFail() { jsonClient.jsonSet("obj", ROOT_PATH, new IRLObject()); Path p = Path.of(".str"); - assertNull(client.jsonSet("obj", p, "strangle", JsonSetParams.jsonSetParams().nx())); + assertNull(jsonClient.jsonSet("obj", p, "strangle", JsonSetParams.jsonSetParams().nx())); } @Test public void setNonExistingPathOnlyIfExistsShouldFail() { jsonClient.jsonSet("obj", ROOT_PATH, new IRLObject()); Path p = Path.of(".none"); - assertNull(client.jsonSet("obj", p, "strangle", JsonSetParams.jsonSetParams().xx())); + assertNull(jsonClient.jsonSet("obj", p, "strangle", JsonSetParams.jsonSetParams().xx())); } @Test(expected = JedisDataException.class) @@ -119,16 +123,7 @@ public void getMultiplePathsShouldSucceed() { IRLObject obj = new IRLObject(); jsonClient.jsonSetLegacy("obj", obj); Object expected = gson.fromJson(gson.toJson(obj), Object.class); - assertTrue(expected.equals(client.jsonGet("obj", Object.class, Path.of("bool"), Path.of("str")))); - } - - @Test - public void getMultiplePathsShouldSucceedWithLegacy() { - // check multiple paths - IRLObject obj = new IRLObject(); - jsonClient.jsonSetLegacy("obj", obj); - Object expected = gson.fromJson(gson.toJson(obj), Object.class); - assertTrue(expected.equals(client.jsonGet("obj", Object.class, Path.of("bool"), Path.of("str")))); + assertTrue(expected.equals(jsonClient.jsonGet("obj", Object.class, Path.of("bool"), Path.of("str")))); } @Test @@ -139,15 +134,15 @@ public void toggle() { Path pbool = Path.of(".bool"); // check initial value - assertTrue(client.jsonGet("obj", Boolean.class, pbool)); + assertTrue(jsonClient.jsonGet("obj", Boolean.class, pbool)); // true -> false jsonClient.jsonToggle("obj", pbool); - assertFalse(client.jsonGet("obj", Boolean.class, pbool)); + assertFalse(jsonClient.jsonGet("obj", Boolean.class, pbool)); // false -> true jsonClient.jsonToggle("obj", pbool); - assertTrue(client.jsonGet("obj", Boolean.class, pbool)); + assertTrue(jsonClient.jsonGet("obj", Boolean.class, pbool)); // ignore non-boolean field Path pstr = Path.of(".str"); @@ -186,7 +181,7 @@ public void delNonExistingPathsAreIgnored() { @Test public void typeChecksShouldSucceed() { - assertNull(client.jsonType("foobar")); + assertNull(jsonClient.jsonType("foobar")); jsonClient.jsonSet("foobar", ROOT_PATH, new FooBarObject()); assertSame(Object.class, jsonClient.jsonType("foobar")); assertSame(Object.class, jsonClient.jsonType("foobar", ROOT_PATH)); @@ -195,7 +190,7 @@ public void typeChecksShouldSucceed() { assertSame(float.class, jsonClient.jsonType("foobar", Path.of(".fooF"))); assertSame(List.class, jsonClient.jsonType("foobar", Path.of(".fooArr"))); assertSame(boolean.class, jsonClient.jsonType("foobar", Path.of(".fooB"))); - assertNull(client.jsonType("foobar", Path.of(".fooErr"))); + assertNull(jsonClient.jsonType("foobar", Path.of(".fooErr"))); } @Test @@ -270,7 +265,7 @@ public void arrLen() { @Test public void arrLenDefaultPath() { - assertNull(client.jsonArrLen("array")); + assertNull(jsonClient.jsonArrLen("array")); jsonClient.jsonSetLegacy("array", new int[]{1, 2, 3}); assertEquals(Long.valueOf(3), jsonClient.jsonArrLen("array")); } @@ -450,7 +445,7 @@ public void strAppend() { @Test public void strLen() { - assertNull(client.jsonStrLen("str")); + assertNull(jsonClient.jsonStrLen("str")); jsonClient.jsonSet("str", ROOT_PATH, "foo"); assertEquals(Long.valueOf(3), jsonClient.jsonStrLen("str")); assertEquals(Long.valueOf(3), jsonClient.jsonStrLen("str", ROOT_PATH)); @@ -464,10 +459,10 @@ public void numIncrBy() { @Test public void obj() { - assertNull(client.jsonObjLen("doc")); - assertNull(client.jsonObjKeys("doc")); - assertNull(client.jsonObjLen("doc", ROOT_PATH)); - assertNull(client.jsonObjKeys("doc", ROOT_PATH)); + assertNull(jsonClient.jsonObjLen("doc")); + assertNull(jsonClient.jsonObjKeys("doc")); + assertNull(jsonClient.jsonObjLen("doc", ROOT_PATH)); + assertNull(jsonClient.jsonObjKeys("doc", ROOT_PATH)); String json = "{\"a\":[3], \"nested\": {\"a\": {\"b\":2, \"c\": 1}}}"; jsonClient.jsonSetWithPlainString("doc", ROOT_PATH, json); @@ -500,8 +495,8 @@ public void plainString() { @Test public void resp() { - assertNull(client.jsonResp("resp")); - assertNull(client.jsonResp("resp", ROOT_PATH)); + assertNull(jsonClient.jsonResp("resp")); + assertNull(jsonClient.jsonResp("resp", ROOT_PATH)); String json = "{\"foo\": {\"hello\":\"world\"}, \"bar\": [null, 3, 2.5, true]}"; jsonClient.jsonSetWithPlainString("resp", ROOT_PATH, json); @@ -545,14 +540,14 @@ public void testJsonGsonParser() { @Test public void testDefaultJsonGsonParserStringsMustBeDifferent() { - Tick person = new Tick("foo", Instant.now()); + Tick tick = new Tick("foo", Instant.now()); // using the default json gson parser which is automatically configured - jsonClient.jsonSet(person.getId(), ROOT_PATH, person); + jsonClient.jsonSet(tick.getId(), ROOT_PATH, tick); - Object valueExpected = jsonClient.jsonGet(person.getId(), Path.of(".created")); - assertNotEquals(valueExpected, person.getCreated().toString()); + Object valueExpected = jsonClient.jsonGet(tick.getId(), Path.of(".created")); + assertNotEquals(valueExpected, tick.getCreated().toString()); } @Test diff --git a/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java b/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java index d63fd4d663..959e950914 100644 --- a/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java +++ b/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java @@ -13,15 +13,18 @@ import org.hamcrest.Matchers; import org.json.JSONArray; import org.json.JSONObject; +import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.json.JsonSetParams; import redis.clients.jedis.json.Path2; import redis.clients.jedis.json.commands.RedisJsonV2Commands; import redis.clients.jedis.modules.RedisModuleCommandsTestBase; +import redis.clients.jedis.util.RedisProtocolUtil; public class RedisJsonV2Test extends RedisModuleCommandsTestBase { @@ -43,9 +46,9 @@ public void setUp() { @Test public void basicSetGetShouldSucceed() { + Assume.assumeFalse(RedisProtocolUtil.getRedisProtocol() == RedisProtocol.RESP3); // naive set with a path -// jsonClient.jsonSet("null", null, ROOT_PATH); jsonClient.jsonSetWithEscape("null", ROOT_PATH, (Object) null); assertJsonArrayEquals(jsonArray((Object) null), jsonClient.jsonGet("null", ROOT_PATH)); @@ -65,6 +68,29 @@ public void basicSetGetShouldSucceed() { assertJsonArrayEquals(jsonArray("strung"), jsonClient.jsonGet("obj", p)); } + @Test + public void basicSetGetShouldSucceedResp3() { + Assume.assumeTrue(RedisProtocolUtil.getRedisProtocol() == RedisProtocol.RESP3); + + // naive set with a path + jsonClient.jsonSetWithEscape("null", ROOT_PATH, (Object) null); + assertJsonArrayEquals(jsonArray((Object) null), jsonClient.jsonGet("null", ROOT_PATH)); + + // real scalar value and no path + jsonClient.jsonSetWithEscape("str", "strong"); + assertJsonArrayEquals(jsonArray("strong"), jsonClient.jsonGet("str")); + + // a slightly more complex object + IRLObject obj = new IRLObject(); + jsonClient.jsonSetWithEscape("obj", obj); + assertJsonArrayEquals(jsonArray(new JSONObject(gson.toJson(obj))), jsonClient.jsonGet("obj")); + + // check an update + Path2 p = Path2.of(".str"); + jsonClient.jsonSet("obj", p, gson.toJson("strung")); + assertJsonArrayEquals(jsonArray("strung"), jsonClient.jsonGet("obj", p)); + } + @Test public void setExistingPathOnlyIfExistsShouldSucceed() { jsonClient.jsonSetWithEscape("obj", new IRLObject()); @@ -432,7 +458,7 @@ public void strAppend() { // jsonClient.jsonSet("str", ROOT_PATH, "foo"); jsonClient.jsonSet("str", ROOT_PATH, gson.toJson("foo")); assertEquals(singletonList(6L), jsonClient.jsonStrAppend("str", ROOT_PATH, "bar")); - assertEquals("foobar", jsonClient.jsonGet("str")); + assertJsonArrayEquals(jsonArray("foobar"), jsonClient.jsonGet("str", ROOT_PATH)); } @Test @@ -443,6 +469,7 @@ public void strLen() { @Test public void numIncrBy() { + Assume.assumeFalse(RedisProtocolUtil.getRedisProtocol() == RedisProtocol.RESP3); jsonClient.jsonSet("doc", "{\"a\":\"b\",\"b\":[{\"a\":2}, {\"a\":5}, {\"a\":\"c\"}]}"); assertJsonArrayEquals(jsonArray((Object) null), jsonClient.jsonNumIncrBy("doc", Path2.of(".a"), 1d)); assertJsonArrayEquals(jsonArray(null, 4, 7, null), jsonClient.jsonNumIncrBy("doc", Path2.of("..a"), 2d)); @@ -450,6 +477,16 @@ public void numIncrBy() { assertJsonArrayEquals(jsonArray(), jsonClient.jsonNumIncrBy("doc", Path2.of("..c"), 0d)); } + @Test + public void numIncrByResp3() { + Assume.assumeTrue(RedisProtocolUtil.getRedisProtocol() == RedisProtocol.RESP3); + jsonClient.jsonSet("doc", "{\"a\":\"b\",\"b\":[{\"a\":2}, {\"a\":5}, {\"a\":\"c\"}]}"); + assertEquals(singletonList((Object) null), jsonClient.jsonNumIncrBy("doc", Path2.of(".a"), 1d)); + assertEquals(Arrays.asList(null, 4d, 7d, null), jsonClient.jsonNumIncrBy("doc", Path2.of("..a"), 2d)); + assertEquals(singletonList((Object) null), jsonClient.jsonNumIncrBy("doc", Path2.of("..b"), 0d)); + assertEquals(Collections.emptyList(), jsonClient.jsonNumIncrBy("doc", Path2.of("..c"), 0d)); + } + @Test public void obj() { String json = "{\"a\":[3], \"nested\": {\"a\": {\"b\":2, \"c\": 1}}}"; From 3d874e1c546711091652660205845b4fea26b207 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Thu, 17 Aug 2023 16:24:15 +0600 Subject: [PATCH 09/23] Remove JSON.RESP command support (#3502) * Remove JSON.RESP command support * breaking change list --- docs/jedis5-breaking.md | 5 +++ .../redis/clients/jedis/CommandObjects.java | 12 ------- .../redis/clients/jedis/UnifiedJedis.java | 15 --------- .../json/commands/RedisJsonV1Commands.java | 4 --- .../json/commands/RedisJsonV2Commands.java | 2 -- .../jedis/modules/json/RedisJsonV1Test.java | 32 ------------------- .../jedis/modules/json/RedisJsonV2Test.java | 26 --------------- 7 files changed, 5 insertions(+), 91 deletions(-) diff --git a/docs/jedis5-breaking.md b/docs/jedis5-breaking.md index 6f5b50247f..f287b3e0c4 100644 --- a/docs/jedis5-breaking.md +++ b/docs/jedis5-breaking.md @@ -67,6 +67,11 @@ - `BINARY_MAP_FROM_PAIRS` - `STRING_ORDERED_SET` +- Following methods supporting JSON.RESP command have been removed: + - `jsonResp(String key)` + - `jsonResp(String key, Path path)` + - `jsonResp(String key, Path2 path)` + - `RedisJsonCommands` and `RedisJsonPipelineCommands` interfaces have been moved into `redis.clients.jedis.json.commands` package. - `Queable` class is removed. diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index c96c4ede1b..79ec632882 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -3724,18 +3724,6 @@ public final CommandObject jsonDebugMemory(String key, Path path) { public final CommandObject> jsonDebugMemory(String key, Path2 path) { return new CommandObject<>(commandArguments(JsonCommand.DEBUG).add("MEMORY").key(key).add(path), BuilderFactory.LONG_LIST); } - - public final CommandObject> jsonResp(String key) { - return new CommandObject<>(commandArguments(JsonCommand.RESP).key(key), BuilderFactory.ENCODED_OBJECT_LIST); - } - - public final CommandObject> jsonResp(String key, Path path) { - return new CommandObject<>(commandArguments(JsonCommand.RESP).key(key).add(path), BuilderFactory.ENCODED_OBJECT_LIST); - } - - public final CommandObject>> jsonResp(String key, Path2 path) { - return new CommandObject<>(commandArguments(JsonCommand.RESP).key(key).add(path), BuilderFactory.ENCODED_OBJECT_LIST_LIST); - } // RedisJSON commands // RedisTimeSeries commands diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index e896dc882f..ccfb99461f 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -4219,21 +4219,6 @@ public long jsonDebugMemory(String key, Path path) { public List jsonDebugMemory(String key, Path2 path) { return executeCommand(commandObjects.jsonDebugMemory(key, path)); } - - @Override - public List jsonResp(String key) { - return executeCommand(commandObjects.jsonResp(key)); - } - - @Override - public List jsonResp(String key, Path path) { - return executeCommand(commandObjects.jsonResp(key, path)); - } - - @Override - public List> jsonResp(String key, Path2 path) { - return executeCommand(commandObjects.jsonResp(key, path)); - } // RedisJSON commands // RedisTimeSeries commands diff --git a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1Commands.java b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1Commands.java index 4d2e96fec9..60d3318640 100644 --- a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1Commands.java +++ b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1Commands.java @@ -97,8 +97,4 @@ default List jsonMGet(Class clazz, String... keys) { long jsonDebugMemory(String key); long jsonDebugMemory(String key, Path path); - - List jsonResp(String key); - - List jsonResp(String key, Path path); } diff --git a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2Commands.java b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2Commands.java index 95ff38aa34..2e5f400650 100644 --- a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2Commands.java +++ b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV2Commands.java @@ -86,6 +86,4 @@ default List jsonMGet(String... keys) { List> jsonObjKeys(String key, Path2 path); List jsonDebugMemory(String key, Path2 path); - - List> jsonResp(String key, Path2 path); } diff --git a/src/test/java/redis/clients/jedis/modules/json/RedisJsonV1Test.java b/src/test/java/redis/clients/jedis/modules/json/RedisJsonV1Test.java index 6a672a0ede..cc9dcfdc05 100644 --- a/src/test/java/redis/clients/jedis/modules/json/RedisJsonV1Test.java +++ b/src/test/java/redis/clients/jedis/modules/json/RedisJsonV1Test.java @@ -493,38 +493,6 @@ public void plainString() { assertEquals(json, jsonClient.jsonGetAsPlainString("plain", ROOT_PATH)); } - @Test - public void resp() { - assertNull(jsonClient.jsonResp("resp")); - assertNull(jsonClient.jsonResp("resp", ROOT_PATH)); - - String json = "{\"foo\": {\"hello\":\"world\"}, \"bar\": [null, 3, 2.5, true]}"; - jsonClient.jsonSetWithPlainString("resp", ROOT_PATH, json); - - List resp = jsonClient.jsonResp("resp"); - assertEquals("{", resp.get(0)); - - assertEquals("foo", resp.get(1)); - assertEquals(Arrays.asList("{", "hello", "world"), resp.get(2)); - - assertEquals("bar", resp.get(3)); - List arr = (List) resp.get(4); - assertEquals("[", arr.get(0)); - assertNull(arr.get(1)); - assertEquals(Long.valueOf(3), arr.get(2)); - //assertEquals("2.5", arr.get(3)); - MatcherAssert.assertThat(arr.get(3), Matchers.isOneOf("2.5", 2.5)); - assertEquals("true", arr.get(4)); - - arr = jsonClient.jsonResp("resp", Path.of(".bar")); - assertEquals("[", arr.get(0)); - assertNull(arr.get(1)); - assertEquals(Long.valueOf(3), arr.get(2)); - //assertEquals("2.5", arr.get(3)); - MatcherAssert.assertThat(arr.get(3), Matchers.isOneOf("2.5", 2.5)); - assertEquals("true", arr.get(4)); - } - @Test public void testJsonGsonParser() { Tick person = new Tick("foo", Instant.now()); diff --git a/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java b/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java index 959e950914..bc9c34edb6 100644 --- a/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java +++ b/src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java @@ -507,32 +507,6 @@ public void debugMemory() { assertEquals(1, jsonClient.jsonDebugMemory("json", Path2.of("$..bar")).size()); } - @Test - public void resp() { - assertNull(jsonClient.jsonResp("resp", ROOT_PATH)); - - String json = "{\"foo\": {\"hello\":\"world\"}, \"bar\": [null, 3, 2.5, true]}"; - jsonClient.jsonSet("resp", ROOT_PATH, json); - - List> fullResp = jsonClient.jsonResp("resp", ROOT_PATH); - assertEquals(1, fullResp.size()); - - List resp = fullResp.get(0); - assertEquals("{", resp.get(0)); - - assertEquals("foo", resp.get(1)); - assertEquals(Arrays.asList("{", "hello", "world"), resp.get(2)); - - assertEquals("bar", resp.get(3)); - List arr = (List) resp.get(4); - assertEquals("[", arr.get(0)); - assertNull(arr.get(1)); - assertEquals(Long.valueOf(3), arr.get(2)); - //assertEquals("2.5", arr.get(3)); - MatcherAssert.assertThat(arr.get(3), Matchers.isOneOf("2.5", 2.5)); - assertEquals("true", arr.get(4)); - } - private void assertJsonArrayEquals(JSONArray a, Object _b) { if (!(_b instanceof JSONArray)) { fail("Actual value is not JSONArray."); From c9f4dee461b9c0d5f0e9d79443bab74770b74cb5 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Thu, 17 Aug 2023 21:54:22 +0600 Subject: [PATCH 10/23] Deprecate RedisJSON v1 support (#3503) * Deprecate RedisJSON v1 support * in CommandObjects --- .../redis/clients/jedis/CommandObjects.java | 37 ++++++++++++++++ .../redis/clients/jedis/UnifiedJedis.java | 37 ++++++++++++++++ .../java/redis/clients/jedis/json/Path.java | 4 +- .../java/redis/clients/jedis/json/Path2.java | 2 +- .../json/commands/RedisJsonV1Commands.java | 44 +++++++++++++++++++ .../commands/RedisJsonV1PipelineCommands.java | 39 +++++++++++++++- 6 files changed, 160 insertions(+), 3 deletions(-) diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 79ec632882..94fed19d57 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -3427,11 +3427,13 @@ public final CommandObject jsonSetWithEscape(String key, Path2 path, Obj getJsonObjectMapper().toJson(object)), BuilderFactory.STRING); } + @Deprecated public final CommandObject jsonSet(String key, Path path, Object pojo) { return new CommandObject<>(commandArguments(JsonCommand.SET).key(key).add(path).add( getJsonObjectMapper().toJson(pojo)), BuilderFactory.STRING); } + @Deprecated public final CommandObject jsonSetWithPlainString(String key, Path path, String string) { return new CommandObject<>(commandArguments(JsonCommand.SET).key(key).add(path).add(string), BuilderFactory.STRING); } @@ -3445,6 +3447,7 @@ public final CommandObject jsonSetWithEscape(String key, Path2 path, Obj getJsonObjectMapper().toJson(object)).addParams(params), BuilderFactory.STRING); } + @Deprecated public final CommandObject jsonSet(String key, Path path, Object pojo, JsonSetParams params) { return new CommandObject<>(commandArguments(JsonCommand.SET).key(key).add(path).add( getJsonObjectMapper().toJson(pojo)).addParams(params), BuilderFactory.STRING); @@ -3454,6 +3457,7 @@ public final CommandObject jsonMerge(String key, Path2 path, Object obje return new CommandObject<>(commandArguments(JsonCommand.MERGE).key(key).add(path).add(object), BuilderFactory.STRING); } + @Deprecated public final CommandObject jsonMerge(String key, Path path, Object pojo) { return new CommandObject<>(commandArguments(JsonCommand.MERGE).key(key).add(path).add( getJsonObjectMapper().toJson(pojo)), BuilderFactory.STRING); @@ -3464,6 +3468,7 @@ public final CommandObject jsonGet(String key) { protocol != RedisProtocol.RESP3 ? JSON_GENERIC_OBJECT : JsonBuilderFactory.JSON_OBJECT); } + @Deprecated public final CommandObject jsonGet(String key, Class clazz) { return new CommandObject<>(commandArguments(JsonCommand.GET).key(key), new JsonObjectBuilder<>(clazz)); } @@ -3472,14 +3477,17 @@ public final CommandObject jsonGet(String key, Path2... paths) { return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).addObjects((Object[]) paths), JsonBuilderFactory.JSON_OBJECT); } + @Deprecated public final CommandObject jsonGet(String key, Path... paths) { return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).addObjects((Object[]) paths), JSON_GENERIC_OBJECT); } + @Deprecated public final CommandObject jsonGetAsPlainString(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).add(path), BuilderFactory.STRING); } + @Deprecated public final CommandObject jsonGet(String key, Class clazz, Path... paths) { return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).addObjects((Object[]) paths), new JsonObjectBuilder<>(clazz)); } @@ -3488,6 +3496,7 @@ public final CommandObject> jsonMGet(Path2 path, String... keys) return new CommandObject<>(commandArguments(JsonCommand.MGET).keys((Object[]) keys).add(path), JsonBuilderFactory.JSON_ARRAY_LIST); } + @Deprecated public final CommandObject> jsonMGet(Path path, Class clazz, String... keys) { return new CommandObject<>(commandArguments(JsonCommand.MGET).keys((Object[]) keys).add(path), new JsonObjectListBuilder<>(clazz)); } @@ -3500,6 +3509,7 @@ public final CommandObject jsonDel(String key, Path2 path) { return new CommandObject<>(commandArguments(JsonCommand.DEL).key(key).add(path), BuilderFactory.LONG); } + @Deprecated public final CommandObject jsonDel(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.DEL).key(key).add(path), BuilderFactory.LONG); } @@ -3512,6 +3522,7 @@ public final CommandObject jsonClear(String key, Path2 path) { return new CommandObject<>(commandArguments(JsonCommand.CLEAR).key(key).add(path), BuilderFactory.LONG); } + @Deprecated public final CommandObject jsonClear(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.CLEAR).key(key).add(path), BuilderFactory.LONG); } @@ -3520,10 +3531,12 @@ public final CommandObject> jsonToggle(String key, Path2 path) { return new CommandObject<>(commandArguments(JsonCommand.TOGGLE).key(key).add(path), BuilderFactory.BOOLEAN_LIST); } + @Deprecated public final CommandObject jsonToggle(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.TOGGLE).key(key).add(path), BuilderFactory.STRING); } + @Deprecated public final CommandObject> jsonType(String key) { return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key), JsonBuilderFactory.JSON_TYPE); } @@ -3533,10 +3546,12 @@ public final CommandObject>> jsonType(String key, Path2 path) { protocol != RedisProtocol.RESP3 ? JsonBuilderFactory.JSON_TYPE_LIST : JsonBuilderFactory.JSON_TYPE_RESPONSE_RESP3_COMPATIBLE); } + @Deprecated public final CommandObject> jsonType(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path), JsonBuilderFactory.JSON_TYPE); } + @Deprecated public final CommandObject jsonStrAppend(String key, Object string) { return new CommandObject<>(commandArguments(JsonCommand.STRAPPEND).key(key).add( getJsonObjectMapper().toJson(string)), BuilderFactory.LONG); @@ -3547,11 +3562,13 @@ public final CommandObject> jsonStrAppend(String key, Path2 path, Obj getJsonObjectMapper().toJson(string)), BuilderFactory.LONG_LIST); } + @Deprecated public final CommandObject jsonStrAppend(String key, Path path, Object string) { return new CommandObject<>(commandArguments(JsonCommand.STRAPPEND).key(key).add(path).add( getJsonObjectMapper().toJson(string)), BuilderFactory.LONG); } + @Deprecated public final CommandObject jsonStrLen(String key) { return new CommandObject<>(commandArguments(JsonCommand.STRLEN).key(key), BuilderFactory.LONG); } @@ -3560,6 +3577,7 @@ public final CommandObject> jsonStrLen(String key, Path2 path) { return new CommandObject<>(commandArguments(JsonCommand.STRLEN).key(key).add(path), BuilderFactory.LONG_LIST); } + @Deprecated public final CommandObject jsonStrLen(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.STRLEN).key(key).add(path), BuilderFactory.LONG); } @@ -3569,6 +3587,7 @@ public final CommandObject jsonNumIncrBy(String key, Path2 path, double JsonBuilderFactory.JSON_ARRAY_OR_DOUBLE_LIST); } + @Deprecated public final CommandObject jsonNumIncrBy(String key, Path path, double value) { return new CommandObject<>(commandArguments(JsonCommand.NUMINCRBY).key(key).add(path).add(value), BuilderFactory.DOUBLE); } @@ -3594,6 +3613,7 @@ public final CommandObject> jsonArrAppendWithEscape(String key, Path2 return new CommandObject<>(args, BuilderFactory.LONG_LIST); } + @Deprecated public final CommandObject jsonArrAppend(String key, Path path, Object... pojos) { CommandArguments args = commandArguments(JsonCommand.ARRAPPEND).key(key).add(path); for (Object pojo : pojos) { @@ -3611,6 +3631,7 @@ public final CommandObject> jsonArrIndexWithEscape(String key, Path2 getJsonObjectMapper().toJson(scalar)), BuilderFactory.LONG_LIST); } + @Deprecated public final CommandObject jsonArrIndex(String key, Path path, Object scalar) { return new CommandObject<>(commandArguments(JsonCommand.ARRINDEX).key(key).add(path).add( getJsonObjectMapper().toJson(scalar)), BuilderFactory.LONG); @@ -3629,6 +3650,7 @@ public final CommandObject> jsonArrInsertWithEscape(String key, Path2 return new CommandObject<>(args, BuilderFactory.LONG_LIST); } + @Deprecated public final CommandObject jsonArrInsert(String key, Path path, int index, Object... pojos) { CommandArguments args = commandArguments(JsonCommand.ARRINSERT).key(key).add(path).add(index); for (Object pojo : pojos) { @@ -3637,10 +3659,12 @@ public final CommandObject jsonArrInsert(String key, Path path, int index, return new CommandObject<>(args, BuilderFactory.LONG); } + @Deprecated public final CommandObject jsonArrPop(String key) { return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key), new JsonObjectBuilder<>(Object.class)); } + @Deprecated public final CommandObject jsonArrPop(String key, Class clazz) { return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key), new JsonObjectBuilder<>(clazz)); } @@ -3649,10 +3673,12 @@ public final CommandObject> jsonArrPop(String key, Path2 path) { return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path), new JsonObjectListBuilder<>(Object.class)); } + @Deprecated public final CommandObject jsonArrPop(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path), new JsonObjectBuilder<>(Object.class)); } + @Deprecated public final CommandObject jsonArrPop(String key, Class clazz, Path path) { return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path), new JsonObjectBuilder<>(clazz)); } @@ -3661,14 +3687,17 @@ public final CommandObject> jsonArrPop(String key, Path2 path, int return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path).add(index), new JsonObjectListBuilder<>(Object.class)); } + @Deprecated public final CommandObject jsonArrPop(String key, Path path, int index) { return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path).add(index), new JsonObjectBuilder<>(Object.class)); } + @Deprecated public final CommandObject jsonArrPop(String key, Class clazz, Path path, int index) { return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path).add(index), new JsonObjectBuilder<>(clazz)); } + @Deprecated public final CommandObject jsonArrLen(String key) { return new CommandObject<>(commandArguments(JsonCommand.ARRLEN).key(key), BuilderFactory.LONG); } @@ -3677,6 +3706,7 @@ public final CommandObject> jsonArrLen(String key, Path2 path) { return new CommandObject<>(commandArguments(JsonCommand.ARRLEN).key(key).add(path), BuilderFactory.LONG_LIST); } + @Deprecated public final CommandObject jsonArrLen(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.ARRLEN).key(key).add(path), BuilderFactory.LONG); } @@ -3685,14 +3715,17 @@ public final CommandObject> jsonArrTrim(String key, Path2 path, int s return new CommandObject<>(commandArguments(JsonCommand.ARRTRIM).key(key).add(path).add(start).add(stop), BuilderFactory.LONG_LIST); } + @Deprecated public final CommandObject jsonArrTrim(String key, Path path, int start, int stop) { return new CommandObject<>(commandArguments(JsonCommand.ARRTRIM).key(key).add(path).add(start).add(stop), BuilderFactory.LONG); } + @Deprecated public final CommandObject jsonObjLen(String key) { return new CommandObject<>(commandArguments(JsonCommand.OBJLEN).key(key), BuilderFactory.LONG); } + @Deprecated public final CommandObject jsonObjLen(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.OBJLEN).key(key).add(path), BuilderFactory.LONG); } @@ -3701,10 +3734,12 @@ public final CommandObject> jsonObjLen(String key, Path2 path) { return new CommandObject<>(commandArguments(JsonCommand.OBJLEN).key(key).add(path), BuilderFactory.LONG_LIST); } + @Deprecated public final CommandObject> jsonObjKeys(String key) { return new CommandObject<>(commandArguments(JsonCommand.OBJKEYS).key(key), BuilderFactory.STRING_LIST); } + @Deprecated public final CommandObject> jsonObjKeys(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.OBJKEYS).key(key).add(path), BuilderFactory.STRING_LIST); } @@ -3713,10 +3748,12 @@ public final CommandObject>> jsonObjKeys(String key, Path2 pat return new CommandObject<>(commandArguments(JsonCommand.OBJKEYS).key(key).add(path), BuilderFactory.STRING_LIST_LIST); } + @Deprecated public final CommandObject jsonDebugMemory(String key) { return new CommandObject<>(commandArguments(JsonCommand.DEBUG).add("MEMORY").key(key), BuilderFactory.LONG); } + @Deprecated public final CommandObject jsonDebugMemory(String key, Path path) { return new CommandObject<>(commandArguments(JsonCommand.DEBUG).add("MEMORY").key(key).add(path), BuilderFactory.LONG); } diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index ccfb99461f..b62156cd98 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -3896,11 +3896,13 @@ public String jsonSetWithEscape(String key, Path2 path, Object object) { } @Override + @Deprecated public String jsonSet(String key, Path path, Object pojo) { return executeCommand(commandObjects.jsonSet(key, path, pojo)); } @Override + @Deprecated public String jsonSetWithPlainString(String key, Path path, String string) { return executeCommand(commandObjects.jsonSetWithPlainString(key, path, string)); } @@ -3916,6 +3918,7 @@ public String jsonSetWithEscape(String key, Path2 path, Object pojo, JsonSetPara } @Override + @Deprecated public String jsonSet(String key, Path path, Object pojo, JsonSetParams params) { return executeCommand(commandObjects.jsonSet(key, path, pojo, params)); } @@ -3926,6 +3929,7 @@ public String jsonMerge(String key, Path2 path, Object object) { } @Override + @Deprecated public String jsonMerge(String key, Path path, Object pojo) { return executeCommand(commandObjects.jsonMerge(key, path, pojo)); } @@ -3936,6 +3940,7 @@ public Object jsonGet(String key) { } @Override + @Deprecated public T jsonGet(String key, Class clazz) { return executeCommand(commandObjects.jsonGet(key, clazz)); } @@ -3946,16 +3951,19 @@ public Object jsonGet(String key, Path2... paths) { } @Override + @Deprecated public Object jsonGet(String key, Path... paths) { return executeCommand(commandObjects.jsonGet(key, paths)); } @Override + @Deprecated public String jsonGetAsPlainString(String key, Path path) { return executeCommand(commandObjects.jsonGetAsPlainString(key, path)); } @Override + @Deprecated public T jsonGet(String key, Class clazz, Path... paths) { return executeCommand(commandObjects.jsonGet(key, clazz, paths)); } @@ -3966,6 +3974,7 @@ public List jsonMGet(Path2 path, String... keys) { } @Override + @Deprecated public List jsonMGet(Path path, Class clazz, String... keys) { return executeCommand(commandObjects.jsonMGet(path, clazz, keys)); } @@ -3981,6 +3990,7 @@ public long jsonDel(String key, Path2 path) { } @Override + @Deprecated public long jsonDel(String key, Path path) { return executeCommand(commandObjects.jsonDel(key, path)); } @@ -3996,6 +4006,7 @@ public long jsonClear(String key, Path2 path) { } @Override + @Deprecated public long jsonClear(String key, Path path) { return executeCommand(commandObjects.jsonClear(key, path)); } @@ -4006,11 +4017,13 @@ public List jsonToggle(String key, Path2 path) { } @Override + @Deprecated public String jsonToggle(String key, Path path) { return executeCommand(commandObjects.jsonToggle(key, path)); } @Override + @Deprecated public Class jsonType(String key) { return executeCommand(commandObjects.jsonType(key)); } @@ -4021,11 +4034,13 @@ public List> jsonType(String key, Path2 path) { } @Override + @Deprecated public Class jsonType(String key, Path path) { return executeCommand(commandObjects.jsonType(key, path)); } @Override + @Deprecated public long jsonStrAppend(String key, Object string) { return executeCommand(commandObjects.jsonStrAppend(key, string)); } @@ -4036,11 +4051,13 @@ public List jsonStrAppend(String key, Path2 path, Object string) { } @Override + @Deprecated public long jsonStrAppend(String key, Path path, Object string) { return executeCommand(commandObjects.jsonStrAppend(key, path, string)); } @Override + @Deprecated public Long jsonStrLen(String key) { return executeCommand(commandObjects.jsonStrLen(key)); } @@ -4051,6 +4068,7 @@ public List jsonStrLen(String key, Path2 path) { } @Override + @Deprecated public Long jsonStrLen(String key, Path path) { return executeCommand(commandObjects.jsonStrLen(key, path)); } @@ -4061,6 +4079,7 @@ public Object jsonNumIncrBy(String key, Path2 path, double value) { } @Override + @Deprecated public double jsonNumIncrBy(String key, Path path, double value) { return executeCommand(commandObjects.jsonNumIncrBy(key, path, value)); } @@ -4076,6 +4095,7 @@ public List jsonArrAppendWithEscape(String key, Path2 path, Object... obje } @Override + @Deprecated public Long jsonArrAppend(String key, Path path, Object... pojos) { return executeCommand(commandObjects.jsonArrAppend(key, path, pojos)); } @@ -4091,6 +4111,7 @@ public List jsonArrIndexWithEscape(String key, Path2 path, Object scalar) } @Override + @Deprecated public long jsonArrIndex(String key, Path path, Object scalar) { return executeCommand(commandObjects.jsonArrIndex(key, path, scalar)); } @@ -4106,16 +4127,19 @@ public List jsonArrInsertWithEscape(String key, Path2 path, int index, Obj } @Override + @Deprecated public long jsonArrInsert(String key, Path path, int index, Object... pojos) { return executeCommand(commandObjects.jsonArrInsert(key, path, index, pojos)); } @Override + @Deprecated public Object jsonArrPop(String key) { return executeCommand(commandObjects.jsonArrPop(key)); } @Override + @Deprecated public T jsonArrPop(String key, Class clazz) { return executeCommand(commandObjects.jsonArrPop(key, clazz)); } @@ -4126,11 +4150,13 @@ public List jsonArrPop(String key, Path2 path) { } @Override + @Deprecated public Object jsonArrPop(String key, Path path) { return executeCommand(commandObjects.jsonArrPop(key, path)); } @Override + @Deprecated public T jsonArrPop(String key, Class clazz, Path path) { return executeCommand(commandObjects.jsonArrPop(key, clazz, path)); } @@ -4141,16 +4167,19 @@ public List jsonArrPop(String key, Path2 path, int index) { } @Override + @Deprecated public Object jsonArrPop(String key, Path path, int index) { return executeCommand(commandObjects.jsonArrPop(key, path, index)); } @Override + @Deprecated public T jsonArrPop(String key, Class clazz, Path path, int index) { return executeCommand(commandObjects.jsonArrPop(key, clazz, path, index)); } @Override + @Deprecated public Long jsonArrLen(String key) { return executeCommand(commandObjects.jsonArrLen(key)); } @@ -4161,6 +4190,7 @@ public List jsonArrLen(String key, Path2 path) { } @Override + @Deprecated public Long jsonArrLen(String key, Path path) { return executeCommand(commandObjects.jsonArrLen(key, path)); } @@ -4171,16 +4201,19 @@ public List jsonArrTrim(String key, Path2 path, int start, int stop) { } @Override + @Deprecated public Long jsonArrTrim(String key, Path path, int start, int stop) { return executeCommand(commandObjects.jsonArrTrim(key, path, start, stop)); } @Override + @Deprecated public Long jsonObjLen(String key) { return executeCommand(commandObjects.jsonObjLen(key)); } @Override + @Deprecated public Long jsonObjLen(String key, Path path) { return executeCommand(commandObjects.jsonObjLen(key, path)); } @@ -4191,11 +4224,13 @@ public List jsonObjLen(String key, Path2 path) { } @Override + @Deprecated public List jsonObjKeys(String key) { return executeCommand(commandObjects.jsonObjKeys(key)); } @Override + @Deprecated public List jsonObjKeys(String key, Path path) { return executeCommand(commandObjects.jsonObjKeys(key, path)); } @@ -4206,11 +4241,13 @@ public List> jsonObjKeys(String key, Path2 path) { } @Override + @Deprecated public long jsonDebugMemory(String key) { return executeCommand(commandObjects.jsonDebugMemory(key)); } @Override + @Deprecated public long jsonDebugMemory(String key, Path path) { return executeCommand(commandObjects.jsonDebugMemory(key, path)); } diff --git a/src/main/java/redis/clients/jedis/json/Path.java b/src/main/java/redis/clients/jedis/json/Path.java index e361cab2ea..d225626e89 100644 --- a/src/main/java/redis/clients/jedis/json/Path.java +++ b/src/main/java/redis/clients/jedis/json/Path.java @@ -1,8 +1,10 @@ package redis.clients.jedis.json; /** - * Path is a ReJSON path, representing a valid path into an object + * Path is a RedisJSON (v1) path, representing a valid path into an object. + * @deprecated RedisJSON (v1) support is deprecated. */ +@Deprecated public class Path { public static final Path ROOT_PATH = new Path("."); diff --git a/src/main/java/redis/clients/jedis/json/Path2.java b/src/main/java/redis/clients/jedis/json/Path2.java index 28211bb470..27c2698689 100644 --- a/src/main/java/redis/clients/jedis/json/Path2.java +++ b/src/main/java/redis/clients/jedis/json/Path2.java @@ -1,7 +1,7 @@ package redis.clients.jedis.json; /** - * Path is a ReJSON path, representing a valid path into an object + * Path is a RedisJSON v2 path, representing a valid path or a multi-path into an object. */ public class Path2 { diff --git a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1Commands.java b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1Commands.java index 60d3318640..5d7fe0d8e7 100644 --- a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1Commands.java +++ b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1Commands.java @@ -4,97 +4,141 @@ import redis.clients.jedis.json.JsonSetParams; import redis.clients.jedis.json.Path; +/** + * @deprecated RedisJSON (v1) support is deprecated. + */ +@Deprecated public interface RedisJsonV1Commands { + @Deprecated default String jsonSetLegacy(String key, Object pojo) { return jsonSet(key, Path.ROOT_PATH, pojo); } + @Deprecated default String jsonSetLegacy(String key, Object pojo, JsonSetParams params) { return jsonSet(key, Path.ROOT_PATH, pojo, params); } + @Deprecated String jsonSet(String key, Path path, Object pojo); + @Deprecated String jsonSetWithPlainString(String key, Path path, String string); + @Deprecated String jsonSet(String key, Path path, Object pojo, JsonSetParams params); + @Deprecated String jsonMerge(String key, Path path, Object pojo); Object jsonGet(String key); // both ver + @Deprecated T jsonGet(String key, Class clazz); + @Deprecated Object jsonGet(String key, Path... paths); + @Deprecated String jsonGetAsPlainString(String key, Path path); + @Deprecated T jsonGet(String key, Class clazz, Path... paths); + @Deprecated default List jsonMGet(Class clazz, String... keys) { return jsonMGet(Path.ROOT_PATH, clazz, keys); } + @Deprecated List jsonMGet(Path path, Class clazz, String... keys); long jsonDel(String key); // both ver + @Deprecated long jsonDel(String key, Path path); long jsonClear(String key); // no test + @Deprecated long jsonClear(String key, Path path); + @Deprecated String jsonToggle(String key, Path path); + @Deprecated Class jsonType(String key); + @Deprecated Class jsonType(String key, Path path); + @Deprecated long jsonStrAppend(String key, Object string); + @Deprecated long jsonStrAppend(String key, Path path, Object string); + @Deprecated Long jsonStrLen(String key); + @Deprecated Long jsonStrLen(String key, Path path); + @Deprecated double jsonNumIncrBy(String key, Path path, double value); + @Deprecated Long jsonArrAppend(String key, Path path, Object... pojos); + @Deprecated long jsonArrIndex(String key, Path path, Object scalar); + @Deprecated long jsonArrInsert(String key, Path path, int index, Object... pojos); + @Deprecated Object jsonArrPop(String key); + @Deprecated T jsonArrPop(String key, Class clazz); + @Deprecated Object jsonArrPop(String key, Path path); + @Deprecated T jsonArrPop(String key, Class clazz, Path path); + @Deprecated Object jsonArrPop(String key, Path path, int index); + @Deprecated T jsonArrPop(String key, Class clazz, Path path, int index); + @Deprecated Long jsonArrLen(String key); + @Deprecated Long jsonArrLen(String key, Path path); + @Deprecated Long jsonArrTrim(String key, Path path, int start, int stop); + @Deprecated Long jsonObjLen(String key); + @Deprecated Long jsonObjLen(String key, Path path); + @Deprecated List jsonObjKeys(String key); + @Deprecated List jsonObjKeys(String key, Path path); + @Deprecated long jsonDebugMemory(String key); + @Deprecated long jsonDebugMemory(String key, Path path); } diff --git a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1PipelineCommands.java b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1PipelineCommands.java index 5d0be5bce7..b447a1e508 100644 --- a/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1PipelineCommands.java +++ b/src/main/java/redis/clients/jedis/json/commands/RedisJsonV1PipelineCommands.java @@ -5,81 +5,118 @@ import redis.clients.jedis.json.JsonSetParams; import redis.clients.jedis.json.Path; -public interface RedisJsonV1PipelineCommands extends RedisJsonV2PipelineCommands { +/** + * @deprecated RedisJSON (v1) support is deprecated. + */ +@Deprecated +public interface RedisJsonV1PipelineCommands { + @Deprecated default Response jsonSetLegacy(String key, Object pojo) { return jsonSet(key, Path.ROOT_PATH, pojo); } + @Deprecated default Response jsonSetLegacy(String key, Object pojo, JsonSetParams params) { return jsonSet(key, Path.ROOT_PATH, pojo, params); } + @Deprecated Response jsonSet(String key, Path path, Object pojo); + @Deprecated Response jsonSet(String key, Path path, Object pojo, JsonSetParams params); + @Deprecated Response jsonMerge(String key, Path path, Object pojo); Response jsonGet(String key); // both ver + @Deprecated Response jsonGet(String key, Class clazz); + @Deprecated Response jsonGet(String key, Path... paths); + @Deprecated Response jsonGet(String key, Class clazz, Path... paths); + @Deprecated default Response> jsonMGet(Class clazz, String... keys) { return jsonMGet(Path.ROOT_PATH, clazz, keys); } + @Deprecated Response> jsonMGet(Path path, Class clazz, String... keys); Response jsonDel(String key); // both ver + @Deprecated Response jsonDel(String key, Path path); + @Deprecated Response jsonClear(String key); // no test + @Deprecated Response jsonClear(String key, Path path); + @Deprecated Response jsonToggle(String key, Path path); + @Deprecated Response> jsonType(String key); + @Deprecated Response> jsonType(String key, Path path); + @Deprecated Response jsonStrAppend(String key, Object string); + @Deprecated Response jsonStrAppend(String key, Path path, Object string); + @Deprecated Response jsonStrLen(String key); + @Deprecated Response jsonStrLen(String key, Path path); + @Deprecated Response jsonNumIncrBy(String key, Path path, double value); + @Deprecated Response jsonArrAppend(String key, Path path, Object... pojos); + @Deprecated Response jsonArrIndex(String key, Path path, Object scalar); + @Deprecated Response jsonArrInsert(String key, Path path, int index, Object... pojos); + @Deprecated Response jsonArrPop(String key); + @Deprecated Response jsonArrPop(String key, Class clazz); + @Deprecated Response jsonArrPop(String key, Path path); + @Deprecated Response jsonArrPop(String key, Class clazz, Path path); + @Deprecated Response jsonArrPop(String key, Path path, int index); + @Deprecated Response jsonArrPop(String key, Class clazz, Path path, int index); + @Deprecated Response jsonArrLen(String key); + @Deprecated Response jsonArrLen(String key, Path path); + @Deprecated Response jsonArrTrim(String key, Path path, int start, int stop); } From 155acfdffb48f58817905b3a3ca1ce997cf74206 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Thu, 17 Aug 2023 22:13:21 +0600 Subject: [PATCH 11/23] Deprecate RedisGraph support (#3504) * Deprecate Redis Graph support * in RedisGraphPipelineCommands --- .../redis/clients/jedis/CommandObjects.java | 6 ++++ .../redis/clients/jedis/UnifiedJedis.java | 15 +++++++++ .../redis/clients/jedis/graph/GraphCache.java | 2 ++ .../jedis/graph/GraphCommandObjects.java | 4 +++ .../clients/jedis/graph/GraphProtocol.java | 3 ++ .../clients/jedis/graph/GraphQueryParams.java | 7 ++-- .../redis/clients/jedis/graph/Header.java | 4 ++- .../redis/clients/jedis/graph/Record.java | 3 ++ .../jedis/graph/RedisGraphCommands.java | 32 +++++++++++++++++++ .../graph/RedisGraphPipelineCommands.java | 14 ++++++++ .../jedis/graph/RedisGraphQueryUtil.java | 6 ++++ .../redis/clients/jedis/graph/ResultSet.java | 4 ++- .../clients/jedis/graph/ResultSetBuilder.java | 4 +++ .../redis/clients/jedis/graph/Statistics.java | 4 +++ .../clients/jedis/graph/entities/Edge.java | 6 ++-- .../jedis/graph/entities/GraphEntity.java | 2 ++ .../clients/jedis/graph/entities/Node.java | 2 ++ .../clients/jedis/graph/entities/Path.java | 2 ++ .../clients/jedis/graph/entities/Point.java | 2 ++ .../jedis/graph/entities/Property.java | 2 ++ 20 files changed, 117 insertions(+), 7 deletions(-) diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 94fed19d57..14b042f3a1 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -4187,26 +4187,32 @@ public final CommandObject> tdigestByRevRank(String key, long... ra // RedisBloom commands // RedisGraph commands + @Deprecated public final CommandObject> graphList() { return new CommandObject<>(commandArguments(GraphCommand.LIST), BuilderFactory.STRING_LIST); } + @Deprecated public final CommandObject> graphProfile(String graphName, String query) { return new CommandObject<>(commandArguments(GraphCommand.PROFILE).key(graphName).add(query), BuilderFactory.STRING_LIST); } + @Deprecated public final CommandObject> graphExplain(String graphName, String query) { return new CommandObject<>(commandArguments(GraphCommand.EXPLAIN).key(graphName).add(query), BuilderFactory.STRING_LIST); } + @Deprecated public final CommandObject>> graphSlowlog(String graphName) { return new CommandObject<>(commandArguments(GraphCommand.SLOWLOG).key(graphName), BuilderFactory.ENCODED_OBJECT_LIST_LIST); } + @Deprecated public final CommandObject graphConfigSet(String configName, Object value) { return new CommandObject<>(commandArguments(GraphCommand.CONFIG).add(GraphKeyword.SET).add(configName).add(value), BuilderFactory.STRING); } + @Deprecated public final CommandObject> graphConfigGet(String configName) { return new CommandObject<>(commandArguments(GraphCommand.CONFIG).add(GraphKeyword.GET).add(configName), BuilderFactory.ENCODED_OBJECT_MAP); } diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index b62156cd98..86758bd421 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -4699,76 +4699,91 @@ public List tdigestByRevRank(String key, long... ranks) { // RedisGraph commands @Override + @Deprecated public ResultSet graphQuery(String name, String query) { return executeCommand(graphCommandObjects.graphQuery(name, query)); } @Override + @Deprecated public ResultSet graphReadonlyQuery(String name, String query) { return executeCommand(graphCommandObjects.graphReadonlyQuery(name, query)); } @Override + @Deprecated public ResultSet graphQuery(String name, String query, long timeout) { return executeCommand(graphCommandObjects.graphQuery(name, query, timeout)); } @Override + @Deprecated public ResultSet graphReadonlyQuery(String name, String query, long timeout) { return executeCommand(graphCommandObjects.graphReadonlyQuery(name, query, timeout)); } @Override + @Deprecated public ResultSet graphQuery(String name, String query, Map params) { return executeCommand(graphCommandObjects.graphQuery(name, query, params)); } @Override + @Deprecated public ResultSet graphReadonlyQuery(String name, String query, Map params) { return executeCommand(graphCommandObjects.graphReadonlyQuery(name, query, params)); } @Override + @Deprecated public ResultSet graphQuery(String name, String query, Map params, long timeout) { return executeCommand(graphCommandObjects.graphQuery(name, query, params, timeout)); } @Override + @Deprecated public ResultSet graphReadonlyQuery(String name, String query, Map params, long timeout) { return executeCommand(graphCommandObjects.graphReadonlyQuery(name, query, params, timeout)); } @Override + @Deprecated public String graphDelete(String name) { return executeCommand(graphCommandObjects.graphDelete(name)); } @Override + @Deprecated public List graphList() { return executeCommand(commandObjects.graphList()); } @Override + @Deprecated public List graphProfile(String graphName, String query) { return executeCommand(commandObjects.graphProfile(graphName, query)); } @Override + @Deprecated public List graphExplain(String graphName, String query) { return executeCommand(commandObjects.graphExplain(graphName, query)); } @Override + @Deprecated public List> graphSlowlog(String graphName) { return executeCommand(commandObjects.graphSlowlog(graphName)); } @Override + @Deprecated public String graphConfigSet(String configName, Object value) { return executeCommand(commandObjects.graphConfigSet(configName, value)); } @Override + @Deprecated public Map graphConfigGet(String configName) { return executeCommand(commandObjects.graphConfigGet(configName)); } diff --git a/src/main/java/redis/clients/jedis/graph/GraphCache.java b/src/main/java/redis/clients/jedis/graph/GraphCache.java index 5ee78def0b..e168e3ee4c 100644 --- a/src/main/java/redis/clients/jedis/graph/GraphCache.java +++ b/src/main/java/redis/clients/jedis/graph/GraphCache.java @@ -3,7 +3,9 @@ /** * Store a local cache in the client, for a specific graph. Holds the labels, property names and * relationship types. + * @deprecated Redis Graph support is deprecated. */ +@Deprecated interface GraphCache { /** diff --git a/src/main/java/redis/clients/jedis/graph/GraphCommandObjects.java b/src/main/java/redis/clients/jedis/graph/GraphCommandObjects.java index 905f4bb24d..a9a49c9081 100644 --- a/src/main/java/redis/clients/jedis/graph/GraphCommandObjects.java +++ b/src/main/java/redis/clients/jedis/graph/GraphCommandObjects.java @@ -19,6 +19,10 @@ import redis.clients.jedis.graph.GraphProtocol.GraphCommand; import redis.clients.jedis.providers.ConnectionProvider; +/** + * @deprecated Redis Graph support is deprecated. + */ +@Deprecated public class GraphCommandObjects { private final RedisGraphCommands graph; diff --git a/src/main/java/redis/clients/jedis/graph/GraphProtocol.java b/src/main/java/redis/clients/jedis/graph/GraphProtocol.java index 0e06eb0bc8..6884466c10 100644 --- a/src/main/java/redis/clients/jedis/graph/GraphProtocol.java +++ b/src/main/java/redis/clients/jedis/graph/GraphProtocol.java @@ -4,8 +4,10 @@ import redis.clients.jedis.commands.ProtocolCommand; import redis.clients.jedis.util.SafeEncoder; +@Deprecated public class GraphProtocol { + @Deprecated public enum GraphCommand implements ProtocolCommand { QUERY, @@ -29,6 +31,7 @@ public byte[] getRaw() { } } + @Deprecated public enum GraphKeyword implements Rawable { CYPHER, diff --git a/src/main/java/redis/clients/jedis/graph/GraphQueryParams.java b/src/main/java/redis/clients/jedis/graph/GraphQueryParams.java index 82738d2485..f670c1e5c1 100644 --- a/src/main/java/redis/clients/jedis/graph/GraphQueryParams.java +++ b/src/main/java/redis/clients/jedis/graph/GraphQueryParams.java @@ -2,15 +2,16 @@ import java.util.HashMap; import java.util.Map; -import java.util.function.Function; import redis.clients.jedis.CommandArguments; -import redis.clients.jedis.commands.ProtocolCommand; import redis.clients.jedis.exceptions.JedisException; -import redis.clients.jedis.graph.GraphProtocol.GraphCommand; import redis.clients.jedis.graph.GraphProtocol.GraphKeyword; import redis.clients.jedis.params.IParams; +/** + * @deprecated Redis Graph support is deprecated. + */ +@Deprecated public class GraphQueryParams implements IParams { private boolean readonly; diff --git a/src/main/java/redis/clients/jedis/graph/Header.java b/src/main/java/redis/clients/jedis/graph/Header.java index f69b16df09..a9ed7e0314 100644 --- a/src/main/java/redis/clients/jedis/graph/Header.java +++ b/src/main/java/redis/clients/jedis/graph/Header.java @@ -3,8 +3,10 @@ import java.util.List; /** - * Query response header interface. Represents the response schema (column names and types) + * Query response header interface. Represents the response schema (column names and types). + * @deprecated Redis Graph support is deprecated. */ +@Deprecated public interface Header { List getSchemaTypes(); diff --git a/src/main/java/redis/clients/jedis/graph/Record.java b/src/main/java/redis/clients/jedis/graph/Record.java index cbcf78fc96..9e02fd9849 100644 --- a/src/main/java/redis/clients/jedis/graph/Record.java +++ b/src/main/java/redis/clients/jedis/graph/Record.java @@ -6,7 +6,10 @@ * Container for RedisGraph result values. * * List records are returned from RedisGraph statement execution, contained within a ResultSet. + * + * @deprecated Redis Graph support is deprecated. */ +@Deprecated public interface Record { /** diff --git a/src/main/java/redis/clients/jedis/graph/RedisGraphCommands.java b/src/main/java/redis/clients/jedis/graph/RedisGraphCommands.java index 07f78b7b8d..45115a7bfa 100644 --- a/src/main/java/redis/clients/jedis/graph/RedisGraphCommands.java +++ b/src/main/java/redis/clients/jedis/graph/RedisGraphCommands.java @@ -3,6 +3,10 @@ import java.util.List; import java.util.Map; +/** + * @deprecated Redis Graph support is deprecated. + */ +@Deprecated public interface RedisGraphCommands { /** @@ -11,7 +15,9 @@ public interface RedisGraphCommands { * @param name a graph to perform the query on * @param query Cypher query * @return a result set + * @deprecated Redis Graph support is deprecated. */ + @Deprecated ResultSet graphQuery(String name, String query); /** @@ -20,7 +26,9 @@ public interface RedisGraphCommands { * @param name a graph to perform the query on * @param query Cypher query * @return a result set + * @deprecated Redis Graph support is deprecated. */ + @Deprecated ResultSet graphReadonlyQuery(String name, String query); /** @@ -30,7 +38,9 @@ public interface RedisGraphCommands { * @param query Cypher query * @param timeout * @return a result set + * @deprecated Redis Graph support is deprecated. */ + @Deprecated ResultSet graphQuery(String name, String query, long timeout); /** @@ -40,7 +50,9 @@ public interface RedisGraphCommands { * @param query Cypher query * @param timeout * @return a result set + * @deprecated Redis Graph support is deprecated. */ + @Deprecated ResultSet graphReadonlyQuery(String name, String query, long timeout); /** @@ -50,7 +62,9 @@ public interface RedisGraphCommands { * @param query Cypher query. * @param params parameters map. * @return a result set. + * @deprecated Redis Graph support is deprecated. */ + @Deprecated ResultSet graphQuery(String name, String query, Map params); /** @@ -60,7 +74,9 @@ public interface RedisGraphCommands { * @param query Cypher query. * @param params parameters map. * @return a result set. + * @deprecated Redis Graph support is deprecated. */ + @Deprecated ResultSet graphReadonlyQuery(String name, String query, Map params); /** @@ -71,7 +87,9 @@ public interface RedisGraphCommands { * @param params parameters map. * @param timeout * @return a result set. + * @deprecated Redis Graph support is deprecated. */ + @Deprecated ResultSet graphQuery(String name, String query, Map params, long timeout); /** @@ -82,7 +100,9 @@ public interface RedisGraphCommands { * @param params parameters map. * @param timeout * @return a result set. + * @deprecated Redis Graph support is deprecated. */ + @Deprecated ResultSet graphReadonlyQuery(String name, String query, Map params, long timeout); /** @@ -90,32 +110,44 @@ public interface RedisGraphCommands { * * @param name graph to delete * @return delete running time statistics + * @deprecated Redis Graph support is deprecated. */ + @Deprecated String graphDelete(String name); /** * Lists all graph keys in the keyspace. * @return graph keys + * @deprecated Redis Graph support is deprecated. */ + @Deprecated List graphList(); /** * Executes a query and produces an execution plan augmented with metrics for each operation's execution. + * @deprecated Redis Graph support is deprecated. */ + @Deprecated List graphProfile(String graphName, String query); /** * Constructs a query execution plan but does not run it. Inspect this execution plan to better understand how your * query will get executed. + * @deprecated Redis Graph support is deprecated. */ + @Deprecated List graphExplain(String graphName, String query); /** * Returns a list containing up to 10 of the slowest queries issued against the given graph ID. + * @deprecated Redis Graph support is deprecated. */ + @Deprecated List> graphSlowlog(String graphName); + @Deprecated String graphConfigSet(String configName, Object value); + @Deprecated Map graphConfigGet(String configName); } diff --git a/src/main/java/redis/clients/jedis/graph/RedisGraphPipelineCommands.java b/src/main/java/redis/clients/jedis/graph/RedisGraphPipelineCommands.java index ecc97a6c8f..b270fc79c8 100644 --- a/src/main/java/redis/clients/jedis/graph/RedisGraphPipelineCommands.java +++ b/src/main/java/redis/clients/jedis/graph/RedisGraphPipelineCommands.java @@ -4,25 +4,39 @@ import java.util.Map; import redis.clients.jedis.Response; +/** + * @deprecated Redis Graph support is deprecated. + */ +@Deprecated public interface RedisGraphPipelineCommands { + @Deprecated Response graphQuery(String name, String query); + @Deprecated Response graphReadonlyQuery(String name, String query); + @Deprecated Response graphQuery(String name, String query, long timeout); + @Deprecated Response graphReadonlyQuery(String name, String query, long timeout); + @Deprecated Response graphQuery(String name, String query, Map params); + @Deprecated Response graphReadonlyQuery(String name, String query, Map params); + @Deprecated Response graphQuery(String name, String query, Map params, long timeout); + @Deprecated Response graphReadonlyQuery(String name, String query, Map params, long timeout); + @Deprecated Response graphDelete(String name); + @Deprecated Response> graphProfile(String graphName, String query); } diff --git a/src/main/java/redis/clients/jedis/graph/RedisGraphQueryUtil.java b/src/main/java/redis/clients/jedis/graph/RedisGraphQueryUtil.java index a98cb49745..d762dc47f6 100644 --- a/src/main/java/redis/clients/jedis/graph/RedisGraphQueryUtil.java +++ b/src/main/java/redis/clients/jedis/graph/RedisGraphQueryUtil.java @@ -6,6 +6,10 @@ import java.util.Map; import java.util.stream.Collectors; +/** + * @deprecated Redis Graph support is deprecated. + */ +@Deprecated public class RedisGraphQueryUtil { public static final List DUMMY_LIST = Collections.emptyList(); @@ -22,7 +26,9 @@ private RedisGraphQueryUtil() { * @param query - query * @param params - query parameters * @return query with parameters header + * @deprecated Redis Graph support is deprecated. */ + @Deprecated public static String prepareQuery(String query, Map params) { StringBuilder sb = new StringBuilder("CYPHER "); for (Map.Entry entry : params.entrySet()) { diff --git a/src/main/java/redis/clients/jedis/graph/ResultSet.java b/src/main/java/redis/clients/jedis/graph/ResultSet.java index da0a5bcce1..795afa207a 100644 --- a/src/main/java/redis/clients/jedis/graph/ResultSet.java +++ b/src/main/java/redis/clients/jedis/graph/ResultSet.java @@ -1,8 +1,10 @@ package redis.clients.jedis.graph; /** - * Hold a query result + * Hold a query result. + * @deprecated Redis Graph support is deprecated. */ +@Deprecated public interface ResultSet extends Iterable { public enum ColumnType { diff --git a/src/main/java/redis/clients/jedis/graph/ResultSetBuilder.java b/src/main/java/redis/clients/jedis/graph/ResultSetBuilder.java index 6f0f38ebb2..9269331cb4 100644 --- a/src/main/java/redis/clients/jedis/graph/ResultSetBuilder.java +++ b/src/main/java/redis/clients/jedis/graph/ResultSetBuilder.java @@ -17,6 +17,10 @@ import redis.clients.jedis.graph.entities.*; import redis.clients.jedis.util.SafeEncoder; +/** + * @deprecated Redis Graph support is deprecated. + */ +@Deprecated class ResultSetBuilder extends Builder { private final GraphCache graphCache; diff --git a/src/main/java/redis/clients/jedis/graph/Statistics.java b/src/main/java/redis/clients/jedis/graph/Statistics.java index f6ad5240f9..332e426bfc 100644 --- a/src/main/java/redis/clients/jedis/graph/Statistics.java +++ b/src/main/java/redis/clients/jedis/graph/Statistics.java @@ -1,5 +1,9 @@ package redis.clients.jedis.graph; +/** + * @deprecated Redis Graph support is deprecated. + */ +@Deprecated public interface Statistics { int nodesCreated(); diff --git a/src/main/java/redis/clients/jedis/graph/entities/Edge.java b/src/main/java/redis/clients/jedis/graph/entities/Edge.java index c02d810000..9595ee8168 100644 --- a/src/main/java/redis/clients/jedis/graph/entities/Edge.java +++ b/src/main/java/redis/clients/jedis/graph/entities/Edge.java @@ -3,9 +3,11 @@ import java.util.Objects; /** - * A class represent an edge (graph entity). In addition to the base class id and properties, an edge shows its source, - * destination and relationship type + * A class represent an edge (graph entity). In addition to the base class id and properties, an + * edge shows its source, destination and relationship type. + * @deprecated Redis Graph support is deprecated. */ +@Deprecated public class Edge extends GraphEntity { //members diff --git a/src/main/java/redis/clients/jedis/graph/entities/GraphEntity.java b/src/main/java/redis/clients/jedis/graph/entities/GraphEntity.java index e075a670d3..8a6b40ad36 100644 --- a/src/main/java/redis/clients/jedis/graph/entities/GraphEntity.java +++ b/src/main/java/redis/clients/jedis/graph/entities/GraphEntity.java @@ -5,7 +5,9 @@ /** * This is an abstract class for representing a graph entity. A graph entity has an id and a set of * properties. The properties are mapped and accessed by their names. + * @deprecated Redis Graph support is deprecated. */ +@Deprecated public abstract class GraphEntity { protected long id; diff --git a/src/main/java/redis/clients/jedis/graph/entities/Node.java b/src/main/java/redis/clients/jedis/graph/entities/Node.java index 68e6015f4c..7265c8202c 100644 --- a/src/main/java/redis/clients/jedis/graph/entities/Node.java +++ b/src/main/java/redis/clients/jedis/graph/entities/Node.java @@ -6,7 +6,9 @@ /** * * A class represent an node (graph entity). In addition to the base class id and properties, a node has labels. + * @deprecated Redis Graph support is deprecated. */ +@Deprecated public class Node extends GraphEntity { //members diff --git a/src/main/java/redis/clients/jedis/graph/entities/Path.java b/src/main/java/redis/clients/jedis/graph/entities/Path.java index ff6471a3db..2efecb309f 100644 --- a/src/main/java/redis/clients/jedis/graph/entities/Path.java +++ b/src/main/java/redis/clients/jedis/graph/entities/Path.java @@ -5,7 +5,9 @@ /** * This class represents a path in the graph. + * @deprecated Redis Graph support is deprecated. */ +@Deprecated public final class Path { private final List nodes; diff --git a/src/main/java/redis/clients/jedis/graph/entities/Point.java b/src/main/java/redis/clients/jedis/graph/entities/Point.java index 552d141c52..a5edd513c4 100644 --- a/src/main/java/redis/clients/jedis/graph/entities/Point.java +++ b/src/main/java/redis/clients/jedis/graph/entities/Point.java @@ -5,7 +5,9 @@ /** * This class represents a (geographical) point in the graph. + * @deprecated Redis Graph support is deprecated. */ +@Deprecated public final class Point { private static final double EPSILON = 1e-5; diff --git a/src/main/java/redis/clients/jedis/graph/entities/Property.java b/src/main/java/redis/clients/jedis/graph/entities/Property.java index cb02899cd1..1f23ad978f 100644 --- a/src/main/java/redis/clients/jedis/graph/entities/Property.java +++ b/src/main/java/redis/clients/jedis/graph/entities/Property.java @@ -4,7 +4,9 @@ /** * A Graph entity property. Has a name, type, and value. + * @deprecated Redis Graph support is deprecated. */ +@Deprecated public class Property { private final String name; From 2c609cfb3adab13ae843aacc862389cca454951a Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Sat, 19 Aug 2023 08:35:12 +0600 Subject: [PATCH 12/23] Fix flakyness of JedisPooledTest (#3506) --- .../redis/clients/jedis/JedisPooledTest.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/test/java/redis/clients/jedis/JedisPooledTest.java b/src/test/java/redis/clients/jedis/JedisPooledTest.java index cdae9a5965..6036062f5b 100644 --- a/src/test/java/redis/clients/jedis/JedisPooledTest.java +++ b/src/test/java/redis/clients/jedis/JedisPooledTest.java @@ -1,10 +1,10 @@ package redis.clients.jedis; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anything; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -22,6 +22,7 @@ public class JedisPooledTest { private static final HostAndPort hnp = HostAndPorts.getRedisServers().get(7); + private static final HostAndPort pwp = HostAndPorts.getRedisServers().get(1); // password protected @Test public void checkCloseableConnections() { @@ -177,9 +178,8 @@ public void testResetValidCredentials() { DefaultRedisCredentialsProvider credentialsProvider = new DefaultRedisCredentialsProvider(new DefaultRedisCredentials(null, "bad password")); - try (JedisPooled pool = new JedisPooled(HostAndPorts.getRedisServers().get(0), - DefaultJedisClientConfig.builder().credentialsProvider(credentialsProvider) - .clientName("my_shiny_client_name").build())) { + try (JedisPooled pool = new JedisPooled(pwp, DefaultJedisClientConfig.builder() + .credentialsProvider(credentialsProvider).build())) { try { pool.get("foo"); fail("Should not get resource from pool"); @@ -187,7 +187,7 @@ public void testResetValidCredentials() { assertEquals(0, pool.getPool().getNumActive()); credentialsProvider.setCredentials(new DefaultRedisCredentials(null, "foobared")); - assertNull(pool.get("foo")); + assertThat(pool.get("foo"), anything()); } } @@ -238,9 +238,8 @@ public void cleanUp() { GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig<>(); poolConfig.setMaxTotal(1); poolConfig.setTestOnBorrow(true); - try (JedisPooled pool = new JedisPooled(HostAndPorts.getRedisServers().get(0), - DefaultJedisClientConfig.builder().credentialsProvider(credentialsProvider) - .build(), poolConfig)) { + try (JedisPooled pool = new JedisPooled(pwp, DefaultJedisClientConfig.builder() + .credentialsProvider(credentialsProvider).build(), poolConfig)) { try { pool.get("foo"); fail("Should not get resource from pool"); @@ -251,7 +250,7 @@ public void cleanUp() { assertThat(cleanupCount.getAndSet(0), greaterThanOrEqualTo(1)); validPassword.set(true); - assertNull(pool.get("foo")); + assertThat(pool.get("foo"), anything()); assertThat(prepareCount.get(), equalTo(1)); assertThat(cleanupCount.get(), equalTo(1)); } From 71204c52ec992fedcbaa54638f8865e910cc3d49 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:25:11 +0600 Subject: [PATCH 13/23] Use RedisCredentials with HELLO command (#3507) * Use RedisCredentials with HELLO command * fix * CLIENT SETNAME separately * remove comment --- .../java/redis/clients/jedis/Connection.java | 124 ++++++++---------- 1 file changed, 57 insertions(+), 67 deletions(-) diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index a0a342e8ab..9cdbfdbd7c 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -1,5 +1,7 @@ package redis.clients.jedis; +import static redis.clients.jedis.util.SafeEncoder.encode; + import java.io.Closeable; import java.io.IOException; import java.net.Socket; @@ -9,7 +11,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.function.Supplier; import redis.clients.jedis.Protocol.Command; @@ -25,7 +26,6 @@ import redis.clients.jedis.util.JedisMetaInfo; import redis.clients.jedis.util.RedisInputStream; import redis.clients.jedis.util.RedisOutputStream; -import redis.clients.jedis.util.SafeEncoder; public class Connection implements Closeable { @@ -270,14 +270,14 @@ public String getStatusCodeReply() { if (null == resp) { return null; } else { - return SafeEncoder.encode(resp); + return encode(resp); } } public String getBulkReply() { final byte[] result = getBinaryBulkReply(); if (null != result) { - return SafeEncoder.encode(result); + return encode(result); } else { return null; } @@ -391,44 +391,27 @@ private static boolean validateClientInfo(String info) { private void initializeFromClientConfig(JedisClientConfig config) { try { connect(); - protocol = config.getRedisProtocol(); - - boolean doClientName = true; - - /// HELLO and AUTH --> - if (protocol == RedisProtocol.RESP3 && config.getUser() != null) { - - hello(protocol, config.getUser(), config.getPassword(), config.getClientName()); - doClientName = false; - } else { - - Supplier credentialsProvider = config.getCredentialsProvider(); - if (credentialsProvider instanceof RedisCredentialsProvider) { - try { - ((RedisCredentialsProvider) credentialsProvider).prepare(); - auth(credentialsProvider); - } finally { - ((RedisCredentialsProvider) credentialsProvider).cleanUp(); - } - } else { - auth(credentialsProvider); - } + protocol = config.getRedisProtocol(); - if (protocol != null) { - hello(protocol); + final Supplier credentialsProvider = config.getCredentialsProvider(); + if (credentialsProvider instanceof RedisCredentialsProvider) { + final RedisCredentialsProvider redisCredentialsProvider = (RedisCredentialsProvider) credentialsProvider; + try { + redisCredentialsProvider.prepare(); + helloOrAuth(protocol, redisCredentialsProvider.get()); + } finally { + redisCredentialsProvider.cleanUp(); } - } - - int dbIndex = config.getDatabase(); - if (dbIndex > 0) { - select(dbIndex); + } else { + helloOrAuth(protocol, credentialsProvider != null ? credentialsProvider.get() + : new DefaultRedisCredentials(config.getUser(), config.getPassword())); } List fireAndForgetMsg = new ArrayList<>(); String clientName = config.getClientName(); - if (doClientName && clientName != null && validateClientInfo(clientName)) { + if (clientName != null && validateClientInfo(clientName)) { fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETNAME).add(clientName)); } @@ -448,6 +431,12 @@ private void initializeFromClientConfig(JedisClientConfig config) { sendCommand(arg); } getMany(fireAndForgetMsg.size()); + + int dbIndex = config.getDatabase(); + if (dbIndex > 0) { + select(dbIndex); + } + } catch (JedisException je) { try { disconnect(); @@ -458,58 +447,59 @@ private void initializeFromClientConfig(JedisClientConfig config) { } } - private Map hello(final RedisProtocol protocol) { - sendCommand(Protocol.Command.HELLO, String.valueOf(protocol.version())); - Map reply = BuilderFactory.ENCODED_OBJECT_MAP.build(getOne()); - // LoggerFactory.getLogger(Connection.class).info("HELLO reply: {}", reply); - return reply; - } + private void helloOrAuth(final RedisProtocol protocol, final RedisCredentials credentials) { - private Map hello(final RedisProtocol protocol, final String user, final String password, - final String clientName) { - if (clientName == null) { - sendCommand(Protocol.Command.HELLO, String.valueOf(protocol.version()), - Protocol.Keyword.AUTH.name(), user, password); - } else { - sendCommand(Protocol.Command.HELLO, String.valueOf(protocol.version()), - Protocol.Keyword.AUTH.name(), user, password, - Protocol.Keyword.SETNAME.name(), clientName); + if (credentials == null || credentials.getPassword() == null) { + if (protocol != null) { + sendCommand(Command.HELLO, encode(protocol.version())); + getOne(); + } + return; } - Map reply = BuilderFactory.ENCODED_OBJECT_MAP.build(getOne()); - // LoggerFactory.getLogger(Connection.class).info("HELLO reply: {}", reply); - return reply; - } - - private void auth(final Supplier credentialsProvider) { - RedisCredentials credentials = credentialsProvider.get(); - if (credentials == null || credentials.getPassword() == null) return; // Source: https://stackoverflow.com/a/9670279/4021802 ByteBuffer passBuf = Protocol.CHARSET.encode(CharBuffer.wrap(credentials.getPassword())); byte[] rawPass = Arrays.copyOfRange(passBuf.array(), passBuf.position(), passBuf.limit()); Arrays.fill(passBuf.array(), (byte) 0); // clear sensitive data - if (credentials.getUser() != null) { - sendCommand(Protocol.Command.AUTH, SafeEncoder.encode(credentials.getUser()), rawPass); - } else { - sendCommand(Protocol.Command.AUTH, rawPass); - } + try { + /// actual HELLO or AUTH --> + if (protocol != null) { + if (credentials.getUser() != null) { + sendCommand(Command.HELLO, encode(protocol.version()), + Keyword.AUTH.getRaw(), encode(credentials.getUser()), rawPass); + getOne(); // Map + } else { + sendCommand(Command.AUTH, rawPass); + getStatusCodeReply(); // OK + sendCommand(Command.HELLO, encode(protocol.version())); + getOne(); // Map + } + } else { // protocol == null + if (credentials.getUser() != null) { + sendCommand(Command.AUTH, encode(credentials.getUser()), rawPass); + } else { + sendCommand(Command.AUTH, rawPass); + } + getStatusCodeReply(); // OK + } + /// <-- actual HELLO or AUTH + } finally { - Arrays.fill(rawPass, (byte) 0); // clear sensitive data + Arrays.fill(rawPass, (byte) 0); // clear sensitive data + } // clearing 'char[] credentials.getPassword()' should be // handled in RedisCredentialsProvider.cleanUp() - - getStatusCodeReply(); // OK } public String select(final int index) { - sendCommand(Protocol.Command.SELECT, Protocol.toByteArray(index)); + sendCommand(Command.SELECT, Protocol.toByteArray(index)); return getStatusCodeReply(); } public boolean ping() { - sendCommand(Protocol.Command.PING); + sendCommand(Command.PING); String status = getStatusCodeReply(); if (!"PONG".equals(status)) { throw new JedisException(status); From bbba9bf23d0c3a6f952003c8de673774d596c20b Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Tue, 22 Aug 2023 18:53:25 +0600 Subject: [PATCH 14/23] Rename jedis5-breaking.md to breaking-5.md --- docs/{jedis5-breaking.md => breaking-5.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{jedis5-breaking.md => breaking-5.md} (100%) diff --git a/docs/jedis5-breaking.md b/docs/breaking-5.md similarity index 100% rename from docs/jedis5-breaking.md rename to docs/breaking-5.md From 7af02d595b59c304f52756290da7741afac2e164 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Tue, 22 Aug 2023 19:42:57 +0600 Subject: [PATCH 15/23] Refactor Jedis 5 breaking changes list --- docs/breaking-5.md | 98 ++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/docs/breaking-5.md b/docs/breaking-5.md index f287b3e0c4..195b08eecc 100644 --- a/docs/breaking-5.md +++ b/docs/breaking-5.md @@ -1,5 +1,24 @@ # Jedis 5 Breaking Changes +- All variants of `blmpop` and `bzmpop` methods now take `double timeout` parameter instead of `long timeout` parameter. + This is breaking ONLY IF you are using `Long` for timeout. + +- `Reducer` abstract class is refactored: + - **`Reducer(String field)` constructor is removed; `Reducer(String name, String field)` constructor is added.** + - **`Reducer(String name)` constructor is added; it will cause runtime error with older `Reducer(String field)` constructor.** + - `getName` method is removed. + - `getAlias` method is removed. + - `setAlias` method is removed; use `as` method. + - `setAliasAsField` method is removed. + - `getOwnArgs` method is now abstract. + - `getArgs` method is removed. + +- `quit()` method has been removed from `Connection` and `ServerCommands` interface and implementations. + +- `updatePassword(String password)` method has been removed from `JedisClientConfig` and implementations. + +- `setPassword(String password)` method has been removed from both `JedisFactory` and `ConnectionFactory` classes. + - Both `bzpopmax(double timeout, String... keys)` and `bzpopmin(double timeout, String... keys)` now return `KeyValue` (instead of `KeyedZSetElement`). - Both `bzpopmax(double timeout, byte[]... keys)` and `bzpopmin(double timeout, byte[]... keys)` now return `KeyValue` (instead of `List`). @@ -41,7 +60,7 @@ - `tsMRevRange(TSMRangeParams multiRangeParams)` - `jsonNumIncrBy(String key, Path2 path, double value)` method now returns `Object` instead of `JSONArray`. - - Previously when it was returning JSONArray, returned would still be JSONArray. So simple type casting should be enough to handle this change. + - The returning object would still be JSONArray for all previous cases. So simple type casting is enough to handle this change. - The returning object will be `List` when running under RESP3 protocol. - `getAgeSeconds()` in `AccessControlLogEntry` now returns `Double` instead of `String`. @@ -52,7 +71,23 @@ - `graphSlowlog(String graphName)` now returns `List>` (instead of `List>`). -- All _payload_ related parameters are removed from _search_ related classes; namely `Document`, `IndexDefinition`, `Query`. +- `CommandListFilterByParams` now throws `IllegalArgumentException` (instead of `JedisDataException`) in case of unfulfilling filter. + +- `FailoverParams` now throws `IllegalArgumentException` (instead of `IllegalStateException`) in case of unfulfilling optional arguments. + +- `XPendingParams` now throws `IllegalArgumentException` (instead of `IllegalStateException`) in case of unfulfilling optional arguments. + +- `get()` option has been removed from `SetParams`. Following methods have been added in Jedis/UnifiedJedis for convenience: + - `setGet(String key, String value)` method has been added in `StringCommands` interface. + - `setGet(byte[] key, byte[] value)` method has been added in `StringBinaryCommands` interface. + +- `xpending(String key, String groupName, StreamEntryID start, StreamEntryID end, int count, String consumerName)` method has been removed from everywhere. + - Use `xpending(java.lang.String, java.lang.String, redis.clients.jedis.params.XPendingParams)` instead. + +- `xpending(byte[] key, byte[] groupName, byte[] start, byte[] end, int count, byte[] consumerName)` method has been removed from everywhere. + - Use `xpending(byte[], byte[], redis.clients.jedis.params.XPendingParams)` instead. + +- `retentionTime(long retentionTime)` method in `TSAlterParams` has been removed. Use `retention(long)` method instead. - Following classes have been removed: - `KeyedZSetElement` @@ -67,6 +102,10 @@ - `BINARY_MAP_FROM_PAIRS` - `STRING_ORDERED_SET` +- All _payload_ related parameters are removed from _search_ related classes; namely `Document`, `IndexDefinition`, `Query`. + +- `topkCount(String key, String... items)` method has been removed from everywhere. + - Following methods supporting JSON.RESP command have been removed: - `jsonResp(String key)` - `jsonResp(String key, Path path)` @@ -79,56 +118,21 @@ - `Params` abstract class is removed. - `toString()` support used by its sub-classes is now unavailable. -- `CommandListFilterByParams` now throws `IllegalArgumentException` (instead of `JedisDataException`) in case of unfulfilling filter. - -- `FailoverParams` now throws `IllegalArgumentException` (instead of `IllegalStateException`) in case of unfulfilling optional arguments. - -- `XPendingParams` now throws `IllegalArgumentException` (instead of `IllegalStateException`) in case of unfulfilling optional arguments. - - `getParams()` method is removed from `SortingParams` class. - Both `SEARCH_AGGREGATION_RESULT` and `SEARCH_AGGREGATION_RESULT_WITH_CURSOR` implementations from `SearchBuilderFactory` class have been moved to `AggregationResult` class. - All `AggregationResult` constructors have been made `private`. -- `addCommandEncodedArguments` and `addCommandBinaryArguments` methods have been removed from `FieldName` class. - -- `getArgs` method is removed from `AggregationBuilder` class. - -- `limit` and `getArgs` methods have been removed from `Group` class. - -- `Reducer` abstract class is refactored: - - `Reducer(String field)` constructor is removed; `Reducer(String name, String field)` constructor is added. - - `Reducer(String name)` constructor is added; it will cause runtime error with older `Reducer(String field)` constructor. - - `getName` method is removed. - - `getAlias` method is removed. - - `setAlias` method is removed; use `as` method. - - `setAliasAsField` method is removed. - - `getOwnArgs` method is now abstract. - - `getArgs` method is removed. - -- All variants of `blmpop` and `bzmpop` methods now take `double timeout` parameter instead of `long timeout` parameter. - This is breaking ONLY IF you are using `Long` for timeout. - - - -- `quit()` method has been removed from `Connection` and `ServerCommands` interface and implementations. - -- `updatePassword(String password)` method has been removed from `JedisClientConfig` and implementations. - -- `setPassword(String password)` method has been removed from both `JedisFactory` and `ConnectionFactory` classes. +- `getArgs()`, `getArgsString()` and `serializeRedisArgs(List redisArgs)` methods have been removed from `AggregationBuilder`. -- `get()` option has been removed from `SetParams`. Following methods have been added in Jedis/UnifiedJedis for convenience: - - `setGet(String key, String value)` method has been added in `StringCommands` interface. - - `setGet(byte[] key, byte[] value)` method has been added in `StringBinaryCommands` interface. +- `totalResults` variable in `AggregationResult` has been made private. Use `getTotalResults()` method instead. -- `xpending(String key, String groupName, StreamEntryID start, StreamEntryID end, int count, String consumerName)` method has been removed from everywhere. - - Use `xpending(java.lang.String, java.lang.String, redis.clients.jedis.params.XPendingParams)` instead. +- `getArgs()` and `limit(Limit limit)` methods have been removed from `Group` class. -- `xpending(byte[] key, byte[] groupName, byte[] start, byte[] end, int count, byte[] consumerName)` method has been removed from everywhere. - - Use `xpending(byte[], byte[], redis.clients.jedis.params.XPendingParams)` instead. +- `addCommandEncodedArguments` and `addCommandBinaryArguments` methods have been removed from `FieldName` class. -- `topkCount(String key, String... items)` method has been removed from everywhere. +- `addObjects(int[] ints)` method has been removed from `CommandArguments`. - Following methods have been removed: - `strAlgoLCSStrings(String strA, String strB, StrAlgoLCSParams params)` @@ -136,7 +140,7 @@ - `strAlgoLCSKeys(String keyA, String keyB, StrAlgoLCSParams params)` - `strAlgoLCSKeys(byte[] keyA, byte[] keyB, StrAlgoLCSParams params)` -- `StrAlgoLCSParams` has been removed. +- `StrAlgoLCSParams` class has been removed. - Following methods have been removed from all Pipeline classes: - `ftCursorRead(String indexName, long cursorId, int count)` @@ -147,14 +151,6 @@ - `ftAliasUpdate(String aliasName, String indexName)` - `ftAliasDel(String aliasName)` -- `addObjects(int[] ints)` method has been removed from `CommandArguments`. - -- `getArgsString()` and `serializeRedisArgs(List redisArgs)` methods have been removed from `AggregationBuilder`. - -- `totalResults` variable in `AggregationResult` has been made private. Use `getTotalResults()` method instead. - -- `retentionTime(long retentionTime)` method in `TSAlterParams` has been removed. Use `retention(long)` method instead. - - `JedisSentineled(String masterName, Set sentinels, JedisClientConfig masterClientConfig, JedisClientConfig sentinelClientConfig)` and `JedisSentineled(String masterName, Set sentinels, GenericObjectPoolConfig poolConfig, JedisClientConfig masterClientConfig, JedisClientConfig sentinelClientConfig)` constructors have been removed. From c920bb371ebc471268bd11a45fc791a7e04e4228 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Wed, 30 Aug 2023 17:16:39 +0600 Subject: [PATCH 16/23] Remove unused AbortedTransactionException (#3514) --- docs/breaking-5.md | 2 ++ .../AbortedTransactionException.java | 16 ----------- .../jedis/exceptions/ExceptionsTest.java | 27 ------------------- 3 files changed, 2 insertions(+), 43 deletions(-) delete mode 100644 src/main/java/redis/clients/jedis/exceptions/AbortedTransactionException.java diff --git a/docs/breaking-5.md b/docs/breaking-5.md index 195b08eecc..4a013c3800 100644 --- a/docs/breaking-5.md +++ b/docs/breaking-5.md @@ -113,6 +113,8 @@ - `RedisJsonCommands` and `RedisJsonPipelineCommands` interfaces have been moved into `redis.clients.jedis.json.commands` package. +- `AbortedTransactionException` is removed. + - `Queable` class is removed. - `Params` abstract class is removed. diff --git a/src/main/java/redis/clients/jedis/exceptions/AbortedTransactionException.java b/src/main/java/redis/clients/jedis/exceptions/AbortedTransactionException.java deleted file mode 100644 index 25f857a6c0..0000000000 --- a/src/main/java/redis/clients/jedis/exceptions/AbortedTransactionException.java +++ /dev/null @@ -1,16 +0,0 @@ -package redis.clients.jedis.exceptions; - -public class AbortedTransactionException extends JedisDataException { - - public AbortedTransactionException(final String message) { - super(message); - } - - public AbortedTransactionException(final Throwable cause) { - super(cause); - } - - public AbortedTransactionException(final String message, final Throwable cause) { - super(message, cause); - } -} diff --git a/src/test/java/redis/clients/jedis/exceptions/ExceptionsTest.java b/src/test/java/redis/clients/jedis/exceptions/ExceptionsTest.java index 9bdd77371b..4b1bef38fe 100644 --- a/src/test/java/redis/clients/jedis/exceptions/ExceptionsTest.java +++ b/src/test/java/redis/clients/jedis/exceptions/ExceptionsTest.java @@ -19,33 +19,6 @@ public static void prepare() { CAUSE = new Throwable("This is a test cause."); } - @Test - public void abortedTransaction() { - try { - throw new AbortedTransactionException(MESSAGE); - } catch (Exception e) { - assertSame(AbortedTransactionException.class, e.getClass()); - assertEquals(MESSAGE, e.getMessage()); - assertNull(e.getCause()); - } - - try { - throw new AbortedTransactionException(CAUSE); - } catch (Exception e) { - assertSame(AbortedTransactionException.class, e.getClass()); - assertEquals(CAUSE, e.getCause()); - assertEquals(CAUSE.toString(), e.getMessage()); - } - - try { - throw new AbortedTransactionException(MESSAGE, CAUSE); - } catch (Exception e) { - assertSame(AbortedTransactionException.class, e.getClass()); - assertEquals(MESSAGE, e.getMessage()); - assertEquals(CAUSE, e.getCause()); - } - } - @Test public void invalidURI() { try { From 58c375e2cbf25ab848f4fd4d7d935721fd35f356 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Thu, 31 Aug 2023 17:43:20 +0600 Subject: [PATCH 17/23] Type-cast the Pipeline object in JedisSentineled (#3517) This is an expansion of #3221, as well as #3240. This is requested in #3516. --- src/main/java/redis/clients/jedis/JedisSentineled.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/redis/clients/jedis/JedisSentineled.java b/src/main/java/redis/clients/jedis/JedisSentineled.java index 7a6c0cc5c0..063d1c40d9 100644 --- a/src/main/java/redis/clients/jedis/JedisSentineled.java +++ b/src/main/java/redis/clients/jedis/JedisSentineled.java @@ -24,4 +24,9 @@ public JedisSentineled(SentineledConnectionProvider sentineledConnectionProvider public HostAndPort getCurrentMaster() { return ((SentineledConnectionProvider) provider).getCurrentMaster(); } + + @Override + public Pipeline pipelined() { + return (Pipeline) super.pipelined(); + } } From d023d2fce7ab6c0d3b8859acbb761cbe1002b186 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Thu, 31 Aug 2023 22:50:09 +0600 Subject: [PATCH 18/23] Modify JedisBroadcastException (#3518) * Modify JedisBroadcastException * Added tests --- .../exceptions/JedisBroadcastException.java | 34 ++++--------------- .../executors/ClusterCommandExecutor.java | 31 ++++++++--------- .../jedis/ClusterScriptingCommandsTest.java | 18 +++++++++- ...Test.java => PooledMiscellaneousTest.java} | 30 ++++++++++++++-- 4 files changed, 65 insertions(+), 48 deletions(-) rename src/test/java/redis/clients/jedis/commands/unified/pooled/{PooledPipeliningTest.java => PooledMiscellaneousTest.java} (75%) diff --git a/src/main/java/redis/clients/jedis/exceptions/JedisBroadcastException.java b/src/main/java/redis/clients/jedis/exceptions/JedisBroadcastException.java index d0670a2c85..172449c34d 100644 --- a/src/main/java/redis/clients/jedis/exceptions/JedisBroadcastException.java +++ b/src/main/java/redis/clients/jedis/exceptions/JedisBroadcastException.java @@ -1,5 +1,6 @@ package redis.clients.jedis.exceptions; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import redis.clients.jedis.HostAndPort; @@ -8,45 +9,22 @@ * Note: This exception extends {@link JedisDataException} just so existing applications catching * JedisDataException do not get broken. */ +// TODO: extends JedisException public class JedisBroadcastException extends JedisDataException { private static final String BROADCAST_ERROR_MESSAGE = "A failure occurred while broadcasting the command."; - private final Map replies = new HashMap<>(); + private final Map replies = new HashMap<>(); public JedisBroadcastException() { super(BROADCAST_ERROR_MESSAGE); } public void addReply(HostAndPort node, Object reply) { - replies.put(node, new SingleReply(reply)); + replies.put(node, reply); } - public void addError(HostAndPort node, JedisDataException error) { - replies.put(node, new SingleReply(error)); - } - - public static class SingleReply { - - private final Object reply; - private final JedisDataException error; - - public SingleReply(Object reply) { - this.reply = reply; - this.error = null; - } - - public SingleReply(JedisDataException error) { - this.reply = null; - this.error = error; - } - - public Object getReply() { - return reply; - } - - public JedisDataException getError() { - return error; - } + public Map getReplies() { + return Collections.unmodifiableMap(replies); } } diff --git a/src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java b/src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java index 48ed4cd6a0..4cc25c42a9 100644 --- a/src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java +++ b/src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java @@ -43,30 +43,29 @@ public final T broadcastCommand(CommandObject commandObject) { boolean isErrored = false; T reply = null; - JedisBroadcastException holder = new JedisBroadcastException(); + JedisBroadcastException bcastError = new JedisBroadcastException(); for (Map.Entry entry : connectionMap.entrySet()) { HostAndPort node = HostAndPort.from(entry.getKey()); ConnectionPool pool = entry.getValue(); try (Connection connection = pool.getResource()) { - try { - T aReply = execute(connection, commandObject); - holder.addReply(node, aReply); - if (isErrored) { // already errored - } else if (reply == null) { - reply = aReply; // ok - } else if (reply.equals(aReply)) { - // ok - } else { - isErrored = true; - reply = null; - } - } catch (JedisDataException anError) { - holder.addError(node, anError); + T aReply = execute(connection, commandObject); + bcastError.addReply(node, aReply); + if (isErrored) { // already errored + } else if (reply == null) { + reply = aReply; // ok + } else if (reply.equals(aReply)) { + // ok + } else { + isErrored = true; + reply = null; } + } catch (Exception anError) { + bcastError.addReply(node, anError); + isErrored = true; } } if (isErrored) { - throw holder; + throw bcastError; } return reply; } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ClusterScriptingCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ClusterScriptingCommandsTest.java index a2304bc38c..503337683e 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ClusterScriptingCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ClusterScriptingCommandsTest.java @@ -1,6 +1,8 @@ package redis.clients.jedis.commands.jedis; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import java.util.ArrayList; @@ -8,10 +10,11 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.function.Supplier; import org.junit.Test; +import redis.clients.jedis.HostAndPort; import redis.clients.jedis.args.FlushMode; +import redis.clients.jedis.exceptions.JedisBroadcastException; import redis.clients.jedis.exceptions.JedisClusterOperationException; import redis.clients.jedis.exceptions.JedisDataException; @@ -110,4 +113,17 @@ public void broadcast() { assertEquals(Arrays.asList(false, false), cluster.scriptExists(Arrays.asList(sha1_1, sha1_2))); } + + @Test + public void broadcastWithError() { + + JedisBroadcastException error = assertThrows(JedisBroadcastException.class, () -> cluster.functionDelete("xyz")); + + Map replies = error.getReplies(); + assertEquals(3, replies.size()); + replies.values().forEach(r -> { + assertSame(JedisDataException.class, r.getClass()); + assertEquals("ERR Library not found", ((JedisDataException) r).getMessage()); + }); + } } diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledPipeliningTest.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java similarity index 75% rename from src/test/java/redis/clients/jedis/commands/unified/pooled/PooledPipeliningTest.java rename to src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java index da2c3f8846..230d9d184b 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledPipeliningTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java @@ -1,6 +1,7 @@ package redis.clients.jedis.commands.unified.pooled; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; import java.util.ArrayList; import java.util.Arrays; @@ -15,10 +16,10 @@ import redis.clients.jedis.Pipeline; import redis.clients.jedis.Response; import redis.clients.jedis.Transaction; - import redis.clients.jedis.commands.unified.UnifiedJedisCommandsTestBase; +import redis.clients.jedis.exceptions.JedisDataException; -public class PooledPipeliningTest extends UnifiedJedisCommandsTestBase { +public class PooledMiscellaneousTest extends UnifiedJedisCommandsTestBase { protected Pipeline pipeline; protected Transaction transaction; @@ -47,7 +48,7 @@ public void tearDown() { } @Test - public void simple() { + public void pipeline() { final int count = 10; int totalCount = 0; for (int i = 0; i < count; i++) { @@ -104,4 +105,27 @@ public void transaction() { assertEquals(expected.get(i), responses.get(i)); } } + + @Test + public void broadcast() { + + String script_1 = "return 'jedis'"; + String sha1_1 = jedis.scriptLoad(script_1); + + String script_2 = "return 79"; + String sha1_2 = jedis.scriptLoad(script_2); + + assertEquals(Arrays.asList(true, true), jedis.scriptExists(Arrays.asList(sha1_1, sha1_2))); + + jedis.scriptFlush(); + + assertEquals(Arrays.asList(false, false), jedis.scriptExists(Arrays.asList(sha1_1, sha1_2))); + } + + @Test + public void broadcastWithError() { + JedisDataException error = assertThrows(JedisDataException.class, + () -> jedis.functionDelete("xyz")); + assertEquals("ERR Library not found", error.getMessage()); + } } From d6e21ef6ab751bf96fa9e428a08869fdbe51c824 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Wed, 23 Aug 2023 00:00:31 +0600 Subject: [PATCH 19/23] Jedis 5.0.0 is released! --- README.md | 55 ++++++++++++++++++++++++--------------------- docs/jedis-maven.md | 4 ++-- pom.xml | 2 +- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index f0a5d6ae61..c04c9da7e4 100644 --- a/README.md +++ b/README.md @@ -14,26 +14,23 @@ Jedis is a Java client for [Redis](https://github.com/redis/redis "Redis") desig Are you looking for a high-level library to handle object mapping? See [redis-om-spring](https://github.com/redis/redis-om-spring)! -## Contributing - -We'd love your contributions! - -**Bug reports** are always welcome! [You can open a bug report on GitHub](https://github.com/redis/jedis/issues/new). - -You can also **contribute documentation** -- or anything to improve Jedis. Please see -[contribution guideline](https://github.com/redis/jedis/blob/master/.github/CONTRIBUTING.md) for more details. - ## Supported Redis versions -The most recent version of this library supports redis version [5.0](https://github.com/redis/redis/blob/5.0/00-RELEASENOTES), [6.0](https://github.com/redis/redis/blob/6.0/00-RELEASENOTES), [6.2](https://github.com/redis/redis/blob/6.2/00-RELEASENOTES), and [7.0](https://github.com/redis/redis/blob/7.0/00-RELEASENOTES). +The most recent version of this library supports redis version +[5.0](https://github.com/redis/redis/blob/5.0/00-RELEASENOTES), +[6.0](https://github.com/redis/redis/blob/6.0/00-RELEASENOTES), +[6.2](https://github.com/redis/redis/blob/6.2/00-RELEASENOTES), +[7.0](https://github.com/redis/redis/blob/7.0/00-RELEASENOTES) and +[7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES). The table below highlights version compatibility of the most-recent library versions and Redis versions. Compatibility means communication features, and Redis command capabilities. -| Library version | Supported redis versions | JDK Compatibility | -|-----------------|--------------------------------|-------------------| -| 3.9+ | 5.0 and 6.2 Family of releases | 8, 11 | -| >= 4.0 | Version 5.0 to current | 8, 11, 17 | +| Jedis version | Supported Redis versions | JDK Compatibility | +|---------------|--------------------------------|-------------------| +| 3.9+ | 5.0 and 6.2 Family of releases | 8, 11 | +| >= 4.0 | Version 5.0 to current | 8, 11, 17 | +| >= 5.0 | Version 6.0 to current | 8, 11, 17 | ## Getting started @@ -43,7 +40,7 @@ To get started with Jedis, first add it as a dependency in your Java project. If redis.clients jedis - 4.4.3 + 5.0.0 ``` @@ -109,6 +106,13 @@ Now you can use the `JedisCluster` instance and send commands like you would wit jedis.sadd("planets", "Mars"); ``` +## Using Redis modules + +Jedis includes support for [Redis modules](https://redis.io/docs/modules/) such as +[RedisJSON](https://oss.redis.com/redisjson/) and [RediSearch](https://oss.redis.com/redisearch/). + +See the [RedisJSON Jedis](docs/redisjson.md) or [RediSearch Jedis](docs/redisearch.md) for details. + ## Failover Jedis supports retry and failover for your Redis deployments. This is useful when: @@ -127,25 +131,26 @@ You can also check the [latest Jedis Javadocs](https://www.javadoc.io/doc/redis. Some specific use-case examples can be found in [`redis.clients.jedis.examples` package](src/test/java/redis/clients/jedis/examples/) of the test source codes. -## Using Redis modules +## Troubleshooting -Jedis includes support for [Redis modules](https://redis.io/docs/modules/) such as -[RedisJSON](https://oss.redis.com/redisjson/) and [RediSearch](https://oss.redis.com/redisearch/). +If you run into trouble or have any questions, we're here to help! -See the [RedisJSON Jedis](docs/redisjson.md) or [RediSearch Jedis](docs/redisearch.md) for details. +Hit us up on the [Redis Discord Server](http://discord.gg/redis) or +[Jedis GitHub Discussions](https://github.com/redis/jedis/discussions) or +[Jedis mailing list](http://groups.google.com/group/jedis_redis). -## Troubleshooting +## Contributing -If you run into trouble or have any questions, we're here to help! +We'd love your contributions! -Hit us up on the [Redis Discord Server](http://discord.gg/redis) or [open an issue on GitHub](https://github.com/redis/jedis). +Bug reports are always welcome! [You can open a bug report on GitHub](https://github.com/redis/jedis/issues/new). -You can also find help on the [Jedis mailing list](http://groups.google.com/group/jedis_redis) or the -[GitHub Discussions](https://github.com/redis/jedis/discussions). +You can also contribute documentation -- or anything to improve Jedis. Please see +[contribution guideline](https://github.com/redis/jedis/blob/master/.github/CONTRIBUTING.md) for more details. ## License -Jedis is licensed under the [MIT license](https://github.com/redis/jedis/blob/master/LICENSE.txt). +Jedis is licensed under the [MIT license](https://github.com/redis/jedis/blob/master/LICENSE). ## Sponsorship diff --git a/docs/jedis-maven.md b/docs/jedis-maven.md index 1c5b0f2598..6466b1ef3a 100644 --- a/docs/jedis-maven.md +++ b/docs/jedis-maven.md @@ -6,7 +6,7 @@ redis.clients jedis - 4.3.0 + 5.0.0 ``` @@ -28,7 +28,7 @@ and redis.clients jedis - 4.4.0-SNAPSHOT + 5.1.0-SNAPSHOT ``` diff --git a/pom.xml b/pom.xml index afd13e8c0a..fb4c14f307 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ jar redis.clients jedis - 5.0.0-SNAPSHOT + 5.1.0-SNAPSHOT Jedis Jedis is a blazingly small and sane Redis java client. https://github.com/redis/jedis From 76797a4920eb0b676ca39e6b5656b5ca73527e04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 12:06:30 +0600 Subject: [PATCH 20/23] Bump mockito-inline from 3.12.4 to 4.11.0 (#3232) * Bump mockito-inline from 3.12.4 to 4.9.0 Bumps [mockito-inline](https://github.com/mockito/mockito) from 3.12.4 to 4.9.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.12.4...v4.9.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-inline dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * 4.11.0 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Chayim Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fb4c14f307..5659732177 100644 --- a/pom.xml +++ b/pom.xml @@ -101,7 +101,7 @@ org.mockito mockito-inline - 3.12.4 + 4.11.0 test From 50fb605865b32c1a73d15190995d1d5d70eb99c3 Mon Sep 17 00:00:00 2001 From: Chayim Date: Mon, 4 Sep 2023 12:56:06 +0300 Subject: [PATCH 21/23] Disabling doctests on tag (#3524) Ensuring doctests do not run on tag, since they have already run when integrated. --- .github/workflows/doctests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/doctests.yml b/.github/workflows/doctests.yml index 8122b40b20..daa8858b89 100644 --- a/.github/workflows/doctests.yml +++ b/.github/workflows/doctests.yml @@ -2,6 +2,8 @@ name: Documentation Tests on: push: + tags-ignore: + - '*' pull_request: workflow_dispatch: @@ -32,4 +34,4 @@ jobs: distribution: 'temurin' - name: Run doctests run: | - mvn -Pdoctests test \ No newline at end of file + mvn -Pdoctests test From 14591c8100c2404466d1f9b1e0400124831f4234 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:56:54 +0600 Subject: [PATCH 22/23] Extend CLIENT SETINFO support (#3509) * Extend CLIENT SETINFO support * Modify JedisMetaInfo * Fix custom lib name and ver * Remove version suffix * Separate ClientSetInfoConfig * Address braces * Rename method to isDisabled --- .../clients/jedis/ClientSetInfoConfig.java | 18 ++++++ .../java/redis/clients/jedis/Connection.java | 29 ++++++--- .../jedis/DefaultClientSetInfoConfig.java | 62 +++++++++++++++++++ .../jedis/DefaultJedisClientConfig.java | 25 ++++++-- .../clients/jedis/JedisClientConfig.java | 7 +++ .../clients/jedis/util/JedisMetaInfo.java | 56 ++++++++--------- .../java/redis/clients/jedis/JedisTest.java | 39 ++++++++++++ .../commands/jedis/ClientCommandsTest.java | 8 +-- 8 files changed, 195 insertions(+), 49 deletions(-) create mode 100644 src/main/java/redis/clients/jedis/ClientSetInfoConfig.java create mode 100644 src/main/java/redis/clients/jedis/DefaultClientSetInfoConfig.java diff --git a/src/main/java/redis/clients/jedis/ClientSetInfoConfig.java b/src/main/java/redis/clients/jedis/ClientSetInfoConfig.java new file mode 100644 index 0000000000..257c17d73d --- /dev/null +++ b/src/main/java/redis/clients/jedis/ClientSetInfoConfig.java @@ -0,0 +1,18 @@ +package redis.clients.jedis; + +/** + * This interface is to modify the behavior of internally executing CLIENT SETINFO command. + */ +public interface ClientSetInfoConfig { + + default boolean isDisabled() { + return false; + } + + /** + * If provided, this suffix will be enclosed by braces {@code ()}. + */ + default String getLibNameSuffix() { + return null; + } +} diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index 9cdbfdbd7c..fdf1887e60 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -388,7 +388,7 @@ private static boolean validateClientInfo(String info) { return true; } - private void initializeFromClientConfig(JedisClientConfig config) { + private void initializeFromClientConfig(final JedisClientConfig config) { try { connect(); @@ -415,16 +415,25 @@ private void initializeFromClientConfig(JedisClientConfig config) { fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETNAME).add(clientName)); } - String libName = JedisMetaInfo.getArtifactId(); - if (libName != null && validateClientInfo(libName)) { - fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETINFO) - .add(ClientAttributeOption.LIB_NAME.getRaw()).add(libName)); - } + ClientSetInfoConfig setInfoConfig = config.getClientSetInfoConfig(); + if (setInfoConfig == null) setInfoConfig = new ClientSetInfoConfig() { }; + + if (!setInfoConfig.isDisabled()) { + String libName = JedisMetaInfo.getArtifactId(); + if (libName != null && validateClientInfo(libName)) { + String libNameSuffix = setInfoConfig.getLibNameSuffix(); + if (libNameSuffix != null && validateClientInfo(libNameSuffix)) { + libName = libName + '(' + libNameSuffix + ')'; + } + fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETINFO) + .add(ClientAttributeOption.LIB_NAME.getRaw()).add(libName)); + } - String libVersion = JedisMetaInfo.getVersion(); - if (libVersion != null && validateClientInfo(libVersion)) { - fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETINFO) - .add(ClientAttributeOption.LIB_VER.getRaw()).add(libVersion)); + String libVersion = JedisMetaInfo.getVersion(); + if (libVersion != null && validateClientInfo(libVersion)) { + fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETINFO) + .add(ClientAttributeOption.LIB_VER.getRaw()).add(libVersion)); + } } for (CommandArguments arg : fireAndForgetMsg) { diff --git a/src/main/java/redis/clients/jedis/DefaultClientSetInfoConfig.java b/src/main/java/redis/clients/jedis/DefaultClientSetInfoConfig.java new file mode 100644 index 0000000000..c2f0298cb1 --- /dev/null +++ b/src/main/java/redis/clients/jedis/DefaultClientSetInfoConfig.java @@ -0,0 +1,62 @@ +package redis.clients.jedis; + +public final class DefaultClientSetInfoConfig implements ClientSetInfoConfig { + + private final boolean disabled; + + private final String libNameSuffix; + + private DefaultClientSetInfoConfig(boolean disabled, String libNameSuffix) { + this.disabled = disabled; + this.libNameSuffix = libNameSuffix; + } + + @Override + public boolean isDisabled() { + return disabled; + } + + @Override + public String getLibNameSuffix() { + return libNameSuffix; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private boolean disable = false; + + private String libNameSuffix = null; + + private Builder() { + } + + public DefaultClientSetInfoConfig build() { + if (disable) { + if (libNameSuffix != null) { + throw new IllegalArgumentException("libNameSuffix cannot be used when internal " + + "CLIENT SETINFO command is disabled."); + } + } + + return new DefaultClientSetInfoConfig(disable, libNameSuffix); + } + + public Builder disable() { + return disable(true); + } + + public Builder disable(boolean disable) { + this.disable = disable; + return this; + } + + public Builder libNameSuffix(String suffix) { + this.libNameSuffix = suffix; + return this; + } + } +} diff --git a/src/main/java/redis/clients/jedis/DefaultJedisClientConfig.java b/src/main/java/redis/clients/jedis/DefaultJedisClientConfig.java index 5f0b4866f1..b8ff01003f 100644 --- a/src/main/java/redis/clients/jedis/DefaultJedisClientConfig.java +++ b/src/main/java/redis/clients/jedis/DefaultJedisClientConfig.java @@ -24,10 +24,13 @@ public final class DefaultJedisClientConfig implements JedisClientConfig { private final HostAndPortMapper hostAndPortMapper; + private final ClientSetInfoConfig clientSetInfoConfig; + private DefaultJedisClientConfig(RedisProtocol protocol, int connectionTimeoutMillis, int soTimeoutMillis, int blockingSocketTimeoutMillis, Supplier credentialsProvider, int database, String clientName, boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, - HostnameVerifier hostnameVerifier, HostAndPortMapper hostAndPortMapper) { + HostnameVerifier hostnameVerifier, HostAndPortMapper hostAndPortMapper, + ClientSetInfoConfig clientSetInfoConfig) { this.redisProtocol = protocol; this.connectionTimeoutMillis = connectionTimeoutMillis; this.socketTimeoutMillis = soTimeoutMillis; @@ -40,6 +43,7 @@ private DefaultJedisClientConfig(RedisProtocol protocol, int connectionTimeoutMi this.sslParameters = sslParameters; this.hostnameVerifier = hostnameVerifier; this.hostAndPortMapper = hostAndPortMapper; + this.clientSetInfoConfig = clientSetInfoConfig; } @Override @@ -113,6 +117,11 @@ public HostAndPortMapper getHostAndPortMapper() { return hostAndPortMapper; } + @Override + public ClientSetInfoConfig getClientSetInfoConfig() { + return clientSetInfoConfig; + } + public static Builder builder() { return new Builder(); } @@ -138,6 +147,8 @@ public static class Builder { private HostAndPortMapper hostAndPortMapper = null; + private ClientSetInfoConfig clientSetInfoConfig = null; + private Builder() { } @@ -149,7 +160,7 @@ public DefaultJedisClientConfig build() { return new DefaultJedisClientConfig(redisProtocol, connectionTimeoutMillis, socketTimeoutMillis, blockingSocketTimeoutMillis, credentialsProvider, database, clientName, ssl, - sslSocketFactory, sslParameters, hostnameVerifier, hostAndPortMapper); + sslSocketFactory, sslParameters, hostnameVerifier, hostAndPortMapper, clientSetInfoConfig); } /** @@ -239,6 +250,11 @@ public Builder hostAndPortMapper(HostAndPortMapper hostAndPortMapper) { this.hostAndPortMapper = hostAndPortMapper; return this; } + + public Builder clientSetInfoConfig(ClientSetInfoConfig setInfoConfig) { + this.clientSetInfoConfig = setInfoConfig; + return this; + } } public static DefaultJedisClientConfig create(int connectionTimeoutMillis, int soTimeoutMillis, @@ -248,7 +264,7 @@ public static DefaultJedisClientConfig create(int connectionTimeoutMillis, int s return new DefaultJedisClientConfig(null, connectionTimeoutMillis, soTimeoutMillis, blockingSocketTimeoutMillis, new DefaultRedisCredentialsProvider(new DefaultRedisCredentials(user, password)), database, - clientName, ssl, sslSocketFactory, sslParameters, hostnameVerifier, hostAndPortMapper); + clientName, ssl, sslSocketFactory, sslParameters, hostnameVerifier, hostAndPortMapper, null); } public static DefaultJedisClientConfig copyConfig(JedisClientConfig copy) { @@ -256,6 +272,7 @@ public static DefaultJedisClientConfig copyConfig(JedisClientConfig copy) { copy.getConnectionTimeoutMillis(), copy.getSocketTimeoutMillis(), copy.getBlockingSocketTimeoutMillis(), copy.getCredentialsProvider(), copy.getDatabase(), copy.getClientName(), copy.isSsl(), copy.getSslSocketFactory(), - copy.getSslParameters(), copy.getHostnameVerifier(), copy.getHostAndPortMapper()); + copy.getSslParameters(), copy.getHostnameVerifier(), copy.getHostAndPortMapper(), + copy.getClientSetInfoConfig()); } } diff --git a/src/main/java/redis/clients/jedis/JedisClientConfig.java b/src/main/java/redis/clients/jedis/JedisClientConfig.java index beb0eabba6..8c0d729587 100644 --- a/src/main/java/redis/clients/jedis/JedisClientConfig.java +++ b/src/main/java/redis/clients/jedis/JedisClientConfig.java @@ -80,4 +80,11 @@ default HostAndPortMapper getHostAndPortMapper() { return null; } + /** + * Modify the behavior of internally executing CLIENT SETINFO command. + * @return CLIENT SETINFO config + */ + default ClientSetInfoConfig getClientSetInfoConfig() { + return null; + } } diff --git a/src/main/java/redis/clients/jedis/util/JedisMetaInfo.java b/src/main/java/redis/clients/jedis/util/JedisMetaInfo.java index c8c6566c4a..0025f3a522 100644 --- a/src/main/java/redis/clients/jedis/util/JedisMetaInfo.java +++ b/src/main/java/redis/clients/jedis/util/JedisMetaInfo.java @@ -2,45 +2,39 @@ import java.io.InputStream; import java.util.Properties; - -import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Jedis Meta info load version groupId */ public class JedisMetaInfo { - private static final Logger log = LoggerFactory.getLogger(JedisMetaInfo.class); - - private static String groupId; - private static String artifactId; - private static String version; - - static { - Properties p = new Properties(); - try { - InputStream in = JedisMetaInfo.class.getClassLoader().getResourceAsStream("pom.properties"); - p.load(in); - - groupId = p.getProperty("groupId", null); - artifactId = p.getProperty("artifactId", null); - version = p.getProperty("version", null); - - in.close(); - } catch (Exception e) { - log.error("Load Jedis meta info from pom.properties failed", e); - } - } - public static String getGroupId() { - return groupId; - } + private static final String groupId; + private static final String artifactId; + private static final String version; - public static String getArtifactId() { - return artifactId; + static { + Properties p = new Properties(); + try (InputStream in = JedisMetaInfo.class.getClassLoader().getResourceAsStream("pom.properties")) { + p.load(in); + } catch (Exception e) { + LoggerFactory.getLogger(JedisMetaInfo.class).error("Load Jedis meta info from pom.properties failed", e); } - public static String getVersion() { - return version; - } + groupId = p.getProperty("groupId", null); + artifactId = p.getProperty("artifactId", null); + version = p.getProperty("version", null); + } + + public static String getGroupId() { + return groupId; + } + + public static String getArtifactId() { + return artifactId; + } + + public static String getVersion() { + return version; + } } diff --git a/src/test/java/redis/clients/jedis/JedisTest.java b/src/test/java/redis/clients/jedis/JedisTest.java index df56ea4fb2..fa7edd501e 100644 --- a/src/test/java/redis/clients/jedis/JedisTest.java +++ b/src/test/java/redis/clients/jedis/JedisTest.java @@ -22,6 +22,7 @@ import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.commands.jedis.JedisCommandsTestBase; +import redis.clients.jedis.util.JedisMetaInfo; import redis.clients.jedis.util.SafeEncoder; public class JedisTest extends JedisCommandsTestBase { @@ -288,4 +289,42 @@ public void checkDisconnectOnQuit() { assertFalse(jedis.isConnected()); } + @Test + public void clientSetInfoDefault() { + try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared") + .build())) { + assertEquals("PONG", jedis.ping()); + String info = jedis.clientInfo(); + assertTrue(info.contains("lib-name=" + JedisMetaInfo.getArtifactId())); + assertTrue(info.contains("lib-ver=" + JedisMetaInfo.getVersion())); + } + } + + @Test + public void clientSetInfoDisable() { + try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared") + .clientSetInfoConfig(new ClientSetInfoConfig() { + @Override public boolean isDisabled() { return true; } + }).build())) { + assertEquals("PONG", jedis.ping()); + String info = jedis.clientInfo(); + assertFalse(info.contains("lib-name=" + JedisMetaInfo.getArtifactId())); + assertFalse(info.contains("lib-ver=" + JedisMetaInfo.getVersion())); + } + } + + @Test + public void clientSetInfoCustom() { + final String libNameSuffix = "for-redis"; + ClientSetInfoConfig setInfoConfig = DefaultClientSetInfoConfig.builder() + .libNameSuffix(libNameSuffix).build(); + try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared") + .clientSetInfoConfig(setInfoConfig).build())) { + assertEquals("PONG", jedis.ping()); + String info = jedis.clientInfo(); + assertTrue(info.contains("lib-name=" + JedisMetaInfo.getArtifactId() + '(' + libNameSuffix + ')')); + assertTrue(info.contains("lib-ver=" + JedisMetaInfo.getVersion())); + } + } + } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java index cbe04a5503..8c3f35db49 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java @@ -64,14 +64,14 @@ public void nameBinary() { } @Test - public void clientSetInfoDefault() { - String libName = "jedis"; + public void clientSetInfoCommand() { + String libName = "Jedis::A-Redis-Java-library"; String libVersion = "999.999.999"; assertEquals("OK", client.clientSetInfo(ClientAttributeOption.LIB_NAME, libName)); assertEquals("OK", client.clientSetInfo(ClientAttributeOption.LIB_VER, libVersion)); String info = client.clientInfo(); - assertTrue(info.contains("lib-name=jedis")); - assertTrue(info.contains("lib-ver=999.999.999")); + assertTrue(info.contains("lib-name=" + libName)); + assertTrue(info.contains("lib-ver=" + libVersion)); } @Test From bb38c97af21dc5361195e38cb01f3398392c7373 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Thu, 14 Sep 2023 13:37:54 +0600 Subject: [PATCH 23/23] Address further CLIENT SETINFO suffix rules (#3536) * Remove separate interface and class implementation of ClientSetInfoConfig * Address the braces rule --- .../clients/jedis/ClientSetInfoConfig.java | 70 ++++++++++++++++--- .../java/redis/clients/jedis/Connection.java | 4 +- .../jedis/DefaultClientSetInfoConfig.java | 62 ---------------- .../jedis/DefaultJedisClientConfig.java | 2 +- .../clients/jedis/JedisClientConfig.java | 2 +- .../java/redis/clients/jedis/JedisTest.java | 13 ++-- .../jedis/misc/ClientSetInfoConfigTest.java | 26 +++++++ 7 files changed, 96 insertions(+), 83 deletions(-) delete mode 100644 src/main/java/redis/clients/jedis/DefaultClientSetInfoConfig.java create mode 100644 src/test/java/redis/clients/jedis/misc/ClientSetInfoConfigTest.java diff --git a/src/main/java/redis/clients/jedis/ClientSetInfoConfig.java b/src/main/java/redis/clients/jedis/ClientSetInfoConfig.java index 257c17d73d..c1d804b28a 100644 --- a/src/main/java/redis/clients/jedis/ClientSetInfoConfig.java +++ b/src/main/java/redis/clients/jedis/ClientSetInfoConfig.java @@ -1,18 +1,70 @@ package redis.clients.jedis; -/** - * This interface is to modify the behavior of internally executing CLIENT SETINFO command. - */ -public interface ClientSetInfoConfig { +import java.util.Arrays; +import java.util.HashSet; +import redis.clients.jedis.exceptions.JedisValidationException; - default boolean isDisabled() { - return false; +public final class ClientSetInfoConfig { + + private final boolean disabled; + + private final String libNameSuffix; + + public ClientSetInfoConfig() { + this(false, null); + } + + public ClientSetInfoConfig(boolean disabled) { + this(disabled, null); + } + + /** + * @param libNameSuffix must not have braces ({@code ()[]{}}) and spaces will be replaced with hyphens + */ + public ClientSetInfoConfig(String libNameSuffix) { + this(false, libNameSuffix); + } + + private ClientSetInfoConfig(boolean disabled, String libNameSuffix) { + this.disabled = disabled; + this.libNameSuffix = validateLibNameSuffix(libNameSuffix); } + private static final HashSet BRACES = new HashSet<>(Arrays.asList('(', ')', '[', ']', '{', '}')); + + private static String validateLibNameSuffix(String suffix) { + if (suffix == null || suffix.trim().isEmpty()) { + return null; + } + + for (int i = 0; i < suffix.length(); i++) { + char c = suffix.charAt(i); + if (c < ' ' || c > '~' || BRACES.contains(c)) { + throw new JedisValidationException("lib-name suffix cannot contain braces, newlines or " + + "special characters."); + } + } + + return suffix.replaceAll("\\s", "-"); + } + + public final boolean isDisabled() { + return disabled; + } + + public final String getLibNameSuffix() { + return libNameSuffix; + } + + public static final ClientSetInfoConfig DEFAULT = new ClientSetInfoConfig(); + + public static final ClientSetInfoConfig DISABLED = new ClientSetInfoConfig(true); + /** - * If provided, this suffix will be enclosed by braces {@code ()}. + * @param suffix must not have braces ({@code ()[]{}}) and spaces will be replaced with hyphens + * @return config */ - default String getLibNameSuffix() { - return null; + public static ClientSetInfoConfig withLibNameSuffix(String suffix) { + return new ClientSetInfoConfig(suffix); } } diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index fdf1887e60..ada7592e3b 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -416,13 +416,13 @@ private void initializeFromClientConfig(final JedisClientConfig config) { } ClientSetInfoConfig setInfoConfig = config.getClientSetInfoConfig(); - if (setInfoConfig == null) setInfoConfig = new ClientSetInfoConfig() { }; + if (setInfoConfig == null) setInfoConfig = ClientSetInfoConfig.DEFAULT; if (!setInfoConfig.isDisabled()) { String libName = JedisMetaInfo.getArtifactId(); if (libName != null && validateClientInfo(libName)) { String libNameSuffix = setInfoConfig.getLibNameSuffix(); - if (libNameSuffix != null && validateClientInfo(libNameSuffix)) { + if (libNameSuffix != null) { // validation is moved into ClientSetInfoConfig constructor libName = libName + '(' + libNameSuffix + ')'; } fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETINFO) diff --git a/src/main/java/redis/clients/jedis/DefaultClientSetInfoConfig.java b/src/main/java/redis/clients/jedis/DefaultClientSetInfoConfig.java deleted file mode 100644 index c2f0298cb1..0000000000 --- a/src/main/java/redis/clients/jedis/DefaultClientSetInfoConfig.java +++ /dev/null @@ -1,62 +0,0 @@ -package redis.clients.jedis; - -public final class DefaultClientSetInfoConfig implements ClientSetInfoConfig { - - private final boolean disabled; - - private final String libNameSuffix; - - private DefaultClientSetInfoConfig(boolean disabled, String libNameSuffix) { - this.disabled = disabled; - this.libNameSuffix = libNameSuffix; - } - - @Override - public boolean isDisabled() { - return disabled; - } - - @Override - public String getLibNameSuffix() { - return libNameSuffix; - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private boolean disable = false; - - private String libNameSuffix = null; - - private Builder() { - } - - public DefaultClientSetInfoConfig build() { - if (disable) { - if (libNameSuffix != null) { - throw new IllegalArgumentException("libNameSuffix cannot be used when internal " - + "CLIENT SETINFO command is disabled."); - } - } - - return new DefaultClientSetInfoConfig(disable, libNameSuffix); - } - - public Builder disable() { - return disable(true); - } - - public Builder disable(boolean disable) { - this.disable = disable; - return this; - } - - public Builder libNameSuffix(String suffix) { - this.libNameSuffix = suffix; - return this; - } - } -} diff --git a/src/main/java/redis/clients/jedis/DefaultJedisClientConfig.java b/src/main/java/redis/clients/jedis/DefaultJedisClientConfig.java index b8ff01003f..6d62646a5e 100644 --- a/src/main/java/redis/clients/jedis/DefaultJedisClientConfig.java +++ b/src/main/java/redis/clients/jedis/DefaultJedisClientConfig.java @@ -147,7 +147,7 @@ public static class Builder { private HostAndPortMapper hostAndPortMapper = null; - private ClientSetInfoConfig clientSetInfoConfig = null; + private ClientSetInfoConfig clientSetInfoConfig = ClientSetInfoConfig.DEFAULT; private Builder() { } diff --git a/src/main/java/redis/clients/jedis/JedisClientConfig.java b/src/main/java/redis/clients/jedis/JedisClientConfig.java index 8c0d729587..0ad6e979f6 100644 --- a/src/main/java/redis/clients/jedis/JedisClientConfig.java +++ b/src/main/java/redis/clients/jedis/JedisClientConfig.java @@ -85,6 +85,6 @@ default HostAndPortMapper getHostAndPortMapper() { * @return CLIENT SETINFO config */ default ClientSetInfoConfig getClientSetInfoConfig() { - return null; + return ClientSetInfoConfig.DEFAULT; } } diff --git a/src/test/java/redis/clients/jedis/JedisTest.java b/src/test/java/redis/clients/jedis/JedisTest.java index fa7edd501e..e9849e7b7b 100644 --- a/src/test/java/redis/clients/jedis/JedisTest.java +++ b/src/test/java/redis/clients/jedis/JedisTest.java @@ -292,7 +292,7 @@ public void checkDisconnectOnQuit() { @Test public void clientSetInfoDefault() { try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared") - .build())) { + .clientSetInfoConfig(ClientSetInfoConfig.DEFAULT).build())) { assertEquals("PONG", jedis.ping()); String info = jedis.clientInfo(); assertTrue(info.contains("lib-name=" + JedisMetaInfo.getArtifactId())); @@ -301,11 +301,9 @@ public void clientSetInfoDefault() { } @Test - public void clientSetInfoDisable() { + public void clientSetInfoDisabled() { try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared") - .clientSetInfoConfig(new ClientSetInfoConfig() { - @Override public boolean isDisabled() { return true; } - }).build())) { + .clientSetInfoConfig(ClientSetInfoConfig.DISABLED).build())) { assertEquals("PONG", jedis.ping()); String info = jedis.clientInfo(); assertFalse(info.contains("lib-name=" + JedisMetaInfo.getArtifactId())); @@ -314,10 +312,9 @@ public void clientSetInfoDisable() { } @Test - public void clientSetInfoCustom() { + public void clientSetInfoLibNameSuffix() { final String libNameSuffix = "for-redis"; - ClientSetInfoConfig setInfoConfig = DefaultClientSetInfoConfig.builder() - .libNameSuffix(libNameSuffix).build(); + ClientSetInfoConfig setInfoConfig = ClientSetInfoConfig.withLibNameSuffix(libNameSuffix); try (Jedis jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared") .clientSetInfoConfig(setInfoConfig).build())) { assertEquals("PONG", jedis.ping()); diff --git a/src/test/java/redis/clients/jedis/misc/ClientSetInfoConfigTest.java b/src/test/java/redis/clients/jedis/misc/ClientSetInfoConfigTest.java new file mode 100644 index 0000000000..8b85f70252 --- /dev/null +++ b/src/test/java/redis/clients/jedis/misc/ClientSetInfoConfigTest.java @@ -0,0 +1,26 @@ +package redis.clients.jedis.misc; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import java.util.Arrays; +import org.junit.Test; + +import redis.clients.jedis.ClientSetInfoConfig; +import redis.clients.jedis.exceptions.JedisValidationException; + +public class ClientSetInfoConfigTest { + + @Test + public void replaceSpacesWithHyphens() { + assertEquals("Redis-Java-client", + ClientSetInfoConfig.withLibNameSuffix("Redis Java client").getLibNameSuffix()); + } + + @Test + public void errorForBraces() { + Arrays.asList('(', ')', '[', ']', '{', '}') + .forEach(brace -> assertThrows(JedisValidationException.class, + () -> ClientSetInfoConfig.withLibNameSuffix("" + brace))); + } +}