diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 87f4eb6566..1f62f4bd26 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -1537,53 +1537,6 @@ public List build(Object data) { } }; - public static final Builder> JSON_TYPE = new Builder>() { - @Override - public Class build(Object data) { - if (data == null) return null; - String str = STRING.build(data); - switch (str) { - case "null": - return null; - case "boolean": - return boolean.class; - case "integer": - return int.class; - case "number": - return float.class; - case "string": - return String.class; - case "object": - return Object.class; - case "array": - return List.class; - default: - throw new JedisException("Unknown type: " + str); - } - } - - @Override - public String toString() { - return "Class"; - } - }; - - public static final Builder>> JSON_TYPE_LIST = new Builder>>() { - @Override - public List> build(Object data) { - List list = (List) data; - List> classes = new ArrayList<>(list.size()); - for (Object elem : list) { - try { - classes.add(JSON_TYPE.build(elem)); - } catch (JedisException je) { - classes.add(null); - } - } - return classes; - } - }; - public static final Builder>> STRING_LIST_LIST = new Builder>>() { @Override @SuppressWarnings("unchecked") @@ -1612,209 +1565,6 @@ public String toString() { } }; - 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"; - private final String CHILD_ITERATORS_STR = "Child iterators"; - private final String RESULT_PROCESSORS_PROFILE_STR = "Result processors profile"; - - @Override - public Map build(Object data) { - List list = (List) SafeEncoder.encodeObject(data); - Map profileMap = new HashMap<>(list.size(), 1f); - - for (Object listObject : list) { - List attributeList = (List) listObject; - String attributeName = (String) attributeList.get(0); - Object attributeValue; - - if (attributeList.size() == 2) { - - Object value = attributeList.get(1); - if (attributeName.equals(ITERATORS_PROFILE_STR)) { - attributeValue = parseIterators(value); - } else if (attributeName.endsWith(" time")) { - attributeValue = DoublePrecision.parseFloatingPointNumber((String) value); - } else { - attributeValue = value; - } - - } else if (attributeList.size() > 2) { - - if (attributeName.equals(RESULT_PROCESSORS_PROFILE_STR)) { - List> resultProcessorsProfileList = new ArrayList<>(attributeList.size() - 1); - for (int i = 1; i < attributeList.size(); i++) { - resultProcessorsProfileList.add(parseResultProcessors(attributeList.get(i))); - } - attributeValue = resultProcessorsProfileList; - } else { - attributeValue = attributeList.subList(1, attributeList.size()); - } - - } else { - attributeValue = null; - } - - profileMap.put(attributeName, attributeValue); - } - return profileMap; - } - - private Map parseResultProcessors(Object data) { - List list = (List) data; - Map map = new HashMap<>(list.size() / 2, 1f); - for (int i = 0; i < list.size(); i += 2) { - String key = (String) list.get(i); - Object value = list.get(i + 1); - if (key.equals("Time")) { - value = DoublePrecision.parseFloatingPointNumber((String) value); - } - map.put(key, value); - } - return map; - } - - private Object parseIterators(Object data) { - if (!(data instanceof List)) return data; - List iteratorsAttributeList = (List) data; - int childIteratorsIndex = iteratorsAttributeList.indexOf(CHILD_ITERATORS_STR); - // https://github.com/RediSearch/RediSearch/issues/3205 patch. TODO: Undo if resolved in RediSearch. - if (childIteratorsIndex < 0) childIteratorsIndex = iteratorsAttributeList.indexOf("Child iterator"); - - Map iteratorsProfile; - if (childIteratorsIndex < 0) { - childIteratorsIndex = iteratorsAttributeList.size(); - iteratorsProfile = new HashMap<>(childIteratorsIndex / 2, 1f); - } else { - iteratorsProfile = new HashMap<>(1 + childIteratorsIndex / 2, 1f); - } - - for (int i = 0; i < childIteratorsIndex; i += 2) { - String key = (String) iteratorsAttributeList.get(i); - Object value = iteratorsAttributeList.get(i + 1); - if (key.equals("Time")) { - value = DoublePrecision.parseFloatingPointNumber((String) value); - } - iteratorsProfile.put(key, value); - } - - if (childIteratorsIndex + 1 < iteratorsAttributeList.size()) { - List childIteratorsList = new ArrayList(iteratorsAttributeList.size() - childIteratorsIndex - 1); - for (int i = childIteratorsIndex + 1; i < iteratorsAttributeList.size(); i++) { - childIteratorsList.add(parseIterators(iteratorsAttributeList.get(i))); - } - iteratorsProfile.put(CHILD_ITERATORS_STR, childIteratorsList); - } - return iteratorsProfile; - } - }; - - public static final Builder>> SEARCH_SYNONYM_GROUPS = new Builder>>() { - @Override - public Map> build(Object data) { - List list = (List) data; - Map> dump = new HashMap<>(list.size() / 2, 1f); - for (int i = 0; i < list.size(); i += 2) { - dump.put(STRING.build(list.get(i)), STRING_LIST.build(list.get(i + 1))); - } - return dump; - } - }; - - public static final Builder>> SEARCH_SPELLCHECK_RESPONSE - = new Builder>>() { - - private final String TERM = "TERM"; - - @Override - public Map> build(Object data) { - List rawTerms = (List) data; - Map> returnTerms = new LinkedHashMap<>(rawTerms.size()); - - for (Object rawTerm : rawTerms) { - List rawElements = (List) rawTerm; - - String header = STRING.build(rawElements.get(0)); - if (!TERM.equals(header)) { - throw new IllegalStateException("Unrecognized header: " + header); - } - String term = STRING.build(rawElements.get(1)); - - List> list = (List>) rawElements.get(2); - Map entries = new LinkedHashMap<>(list.size()); - list.forEach(entry -> entries.put(STRING.build(entry.get(1)), DOUBLE.build(entry.get(0)))); - - returnTerms.put(term, entries); - } - return returnTerms; - } - }; - - public static final Builder TIMESERIES_ELEMENT = new Builder() { - @Override - public TSElement build(Object data) { - List list = (List) data; - if (list == null || list.isEmpty()) return null; - return new TSElement(LONG.build(list.get(0)), DOUBLE.build(list.get(1))); - } - }; - - public static final Builder> TIMESERIES_ELEMENT_LIST = new Builder>() { - @Override - public List build(Object data) { - return ((List) data).stream().map((pairObject) -> (List) pairObject) - .map((pairList) -> new TSElement(LONG.build(pairList.get(0)), - DOUBLE.build(pairList.get(1)))) - .collect(Collectors.toList()); - } - }; - - public static final Builder> TIMESERIES_MRANGE_RESPONSE = new Builder>() { - @Override - public List build(Object data) { - return ((List) data).stream().map((tsObject) -> (List) tsObject) - .map((tsList) -> new TSKeyedElements(STRING.build(tsList.get(0)), - STRING_MAP_FROM_PAIRS.build(tsList.get(1)), - TIMESERIES_ELEMENT_LIST.build(tsList.get(2)))) - .collect(Collectors.toList()); - } - }; - - public static final Builder>> TIMESERIES_MGET_RESPONSE - = new Builder>>() { - @Override - public List> build(Object data) { - return ((List) data).stream().map((tsObject) -> (List) tsObject) - .map((tsList) -> new TSKeyValue<>(STRING.build(tsList.get(0)), - STRING_MAP_FROM_PAIRS.build(tsList.get(1)), - TIMESERIES_ELEMENT.build(tsList.get(2)))) - .collect(Collectors.toList()); - } - }; - - public static final Builder> BLOOM_SCANDUMP_RESPONSE = new Builder>() { - @Override - public Map.Entry build(Object data) { - List list = (List) data; - return new KeyValue<>(LONG.build(list.get(0)), BINARY.build(list.get(1))); - } - }; - /** * A decorator to implement Set from List. Assume that given List do not contains duplicated * values. The resulting set displays the same ordering, concurrency, and performance diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 6544baf345..c24d97724a 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -3,7 +3,6 @@ import static redis.clients.jedis.Protocol.Command.*; import static redis.clients.jedis.Protocol.Keyword.*; -import com.google.gson.Gson; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -18,22 +17,19 @@ import redis.clients.jedis.bloom.*; import redis.clients.jedis.bloom.RedisBloomProtocol.*; import redis.clients.jedis.commands.ProtocolCommand; -import redis.clients.jedis.graph.GraphProtocol.GraphCommand; -import redis.clients.jedis.graph.GraphProtocol.GraphKeyword; +import redis.clients.jedis.graph.GraphProtocol.*; import redis.clients.jedis.json.*; import redis.clients.jedis.json.JsonProtocol.JsonCommand; import redis.clients.jedis.params.*; import redis.clients.jedis.resps.*; import redis.clients.jedis.search.*; -import redis.clients.jedis.search.SearchProtocol.SearchCommand; -import redis.clients.jedis.search.SearchProtocol.SearchKeyword; +import redis.clients.jedis.search.SearchProtocol.*; import redis.clients.jedis.search.SearchResult.SearchResultBuilder; import redis.clients.jedis.search.aggr.AggregationBuilder; import redis.clients.jedis.search.aggr.AggregationResult; import redis.clients.jedis.search.schemafields.SchemaField; import redis.clients.jedis.timeseries.*; -import redis.clients.jedis.timeseries.TimeSeriesProtocol.TimeSeriesCommand; -import redis.clients.jedis.timeseries.TimeSeriesProtocol.TimeSeriesKeyword; +import redis.clients.jedis.timeseries.TimeSeriesProtocol.*; import redis.clients.jedis.util.KeyValue; public class CommandObjects { @@ -3134,12 +3130,12 @@ public CommandObject> ftExplainCLI(String indexName, Query query) { public CommandObject ftAggregate(String indexName, AggregationBuilder aggr) { return new CommandObject<>(commandArguments(SearchCommand.AGGREGATE).add(indexName).addObjects(aggr.getArgs()), - !aggr.isWithCursor() ? BuilderFactory.SEARCH_AGGREGATION_RESULT : BuilderFactory.SEARCH_AGGREGATION_RESULT_WITH_CURSOR); + !aggr.isWithCursor() ? SearchBuilderFactory.SEARCH_AGGREGATION_RESULT : SearchBuilderFactory.SEARCH_AGGREGATION_RESULT_WITH_CURSOR); } public CommandObject ftCursorRead(String indexName, long cursorId, int count) { return new CommandObject<>(commandArguments(SearchCommand.CURSOR).add(SearchKeyword.READ) - .add(indexName).add(cursorId).add(count), BuilderFactory.SEARCH_AGGREGATION_RESULT_WITH_CURSOR); + .add(indexName).add(cursorId).add(count), SearchBuilderFactory.SEARCH_AGGREGATION_RESULT_WITH_CURSOR); } public CommandObject ftCursorDel(String indexName, long cursorId) { @@ -3152,8 +3148,8 @@ public CommandObject>> ftProfil return new CommandObject<>(commandArguments(SearchCommand.PROFILE).add(indexName) .add(SearchKeyword.AGGREGATE).addParams(profileParams).add(SearchKeyword.QUERY) .addObjects(aggr.getArgs()), new SearchProfileResponseBuilder<>(!aggr.isWithCursor() - ? BuilderFactory.SEARCH_AGGREGATION_RESULT - : BuilderFactory.SEARCH_AGGREGATION_RESULT_WITH_CURSOR)); + ? SearchBuilderFactory.SEARCH_AGGREGATION_RESULT + : SearchBuilderFactory.SEARCH_AGGREGATION_RESULT_WITH_CURSOR)); } public CommandObject>> ftProfileSearch( @@ -3186,7 +3182,7 @@ public CommandObject ftSynUpdate(String indexName, String synonymGroupId } public CommandObject>> ftSynDump(String indexName) { - return new CommandObject<>(commandArguments(SearchCommand.SYNDUMP).add(indexName), BuilderFactory.SEARCH_SYNONYM_GROUPS); + return new CommandObject<>(commandArguments(SearchCommand.SYNDUMP).add(indexName), SearchBuilderFactory.SEARCH_SYNONYM_GROUPS); } public final CommandObject ftDictAdd(String dictionary, String... terms) { @@ -3215,13 +3211,13 @@ public final CommandObject> ftDictDumpBySampleKey(String indexName, public final CommandObject>> ftSpellCheck(String index, String query) { return new CommandObject<>(commandArguments(SearchCommand.SPELLCHECK).key(index).add(query), - BuilderFactory.SEARCH_SPELLCHECK_RESPONSE); + SearchBuilderFactory.SEARCH_SPELLCHECK_RESPONSE); } public final CommandObject>> ftSpellCheck(String index, String query, FTSpellCheckParams spellCheckParams) { return new CommandObject<>(commandArguments(SearchCommand.SPELLCHECK).key(index).add(query) - .addParams(spellCheckParams), BuilderFactory.SEARCH_SPELLCHECK_RESPONSE); + .addParams(spellCheckParams), SearchBuilderFactory.SEARCH_SPELLCHECK_RESPONSE); } public CommandObject> ftInfo(String indexName) { @@ -3398,15 +3394,15 @@ public final CommandObject jsonToggle(String key, Path path) { } public final CommandObject> jsonType(String key) { - return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key), BuilderFactory.JSON_TYPE); + return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key), JsonBuilderFactory.JSON_TYPE); } public final CommandObject>> jsonType(String key, Path2 path) { - return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path), BuilderFactory.JSON_TYPE_LIST); + return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path), JsonBuilderFactory.JSON_TYPE_LIST); } public final CommandObject> jsonType(String key, Path path) { - return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path), BuilderFactory.JSON_TYPE); + return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path), JsonBuilderFactory.JSON_TYPE); } public final CommandObject jsonStrAppend(String key, Object string) { @@ -3663,57 +3659,57 @@ public final CommandObject tsDecrBy(String key, double value, long timesta public final CommandObject> tsRange(String key, long fromTimestamp, long toTimestamp) { return new CommandObject<>(commandArguments(TimeSeriesCommand.RANGE).key(key) - .add(fromTimestamp).add(toTimestamp), BuilderFactory.TIMESERIES_ELEMENT_LIST); + .add(fromTimestamp).add(toTimestamp), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST); } public final CommandObject> tsRange(String key, TSRangeParams rangeParams) { return new CommandObject<>(commandArguments(TimeSeriesCommand.RANGE).key(key) - .addParams(rangeParams), BuilderFactory.TIMESERIES_ELEMENT_LIST); + .addParams(rangeParams), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST); } public final CommandObject> tsRevRange(String key, long fromTimestamp, long toTimestamp) { return new CommandObject<>(commandArguments(TimeSeriesCommand.REVRANGE).key(key) - .add(fromTimestamp).add(toTimestamp), BuilderFactory.TIMESERIES_ELEMENT_LIST); + .add(fromTimestamp).add(toTimestamp), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST); } public final CommandObject> tsRevRange(String key, TSRangeParams rangeParams) { return new CommandObject<>(commandArguments(TimeSeriesCommand.REVRANGE).key(key) - .addParams(rangeParams), BuilderFactory.TIMESERIES_ELEMENT_LIST); + .addParams(rangeParams), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST); } public final CommandObject> tsMRange(long fromTimestamp, long toTimestamp, String... filters) { return new CommandObject<>(commandArguments(TimeSeriesCommand.MRANGE).add(fromTimestamp) .add(toTimestamp).add(TimeSeriesKeyword.FILTER).addObjects((Object[]) filters), - BuilderFactory.TIMESERIES_MRANGE_RESPONSE); + TimeSeriesBuilderFactory.TIMESERIES_MRANGE_RESPONSE); } public final CommandObject> tsMRange(TSMRangeParams multiRangeParams) { return new CommandObject<>(commandArguments(TimeSeriesCommand.MRANGE) - .addParams(multiRangeParams), BuilderFactory.TIMESERIES_MRANGE_RESPONSE); + .addParams(multiRangeParams), TimeSeriesBuilderFactory.TIMESERIES_MRANGE_RESPONSE); } public final CommandObject> tsMRevRange(long fromTimestamp, long toTimestamp, String... filters) { return new CommandObject<>(commandArguments(TimeSeriesCommand.MREVRANGE).add(fromTimestamp) .add(toTimestamp).add(TimeSeriesKeyword.FILTER).addObjects((Object[]) filters), - BuilderFactory.TIMESERIES_MRANGE_RESPONSE); + TimeSeriesBuilderFactory.TIMESERIES_MRANGE_RESPONSE); } public final CommandObject> tsMRevRange(TSMRangeParams multiRangeParams) { return new CommandObject<>(commandArguments(TimeSeriesCommand.MREVRANGE).addParams(multiRangeParams), - BuilderFactory.TIMESERIES_MRANGE_RESPONSE); + TimeSeriesBuilderFactory.TIMESERIES_MRANGE_RESPONSE); } public final CommandObject tsGet(String key) { - return new CommandObject<>(commandArguments(TimeSeriesCommand.GET).key(key), BuilderFactory.TIMESERIES_ELEMENT); + return new CommandObject<>(commandArguments(TimeSeriesCommand.GET).key(key), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT); } public final CommandObject tsGet(String key, TSGetParams getParams) { - return new CommandObject<>(commandArguments(TimeSeriesCommand.GET).key(key).addParams(getParams), BuilderFactory.TIMESERIES_ELEMENT); + return new CommandObject<>(commandArguments(TimeSeriesCommand.GET).key(key).addParams(getParams), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT); } public final CommandObject>> tsMGet(TSMGetParams multiGetParams, String... filters) { return new CommandObject<>(commandArguments(TimeSeriesCommand.MGET).addParams(multiGetParams) - .add(TimeSeriesKeyword.FILTER).addObjects((Object[]) filters), BuilderFactory.TIMESERIES_MGET_RESPONSE); + .add(TimeSeriesKeyword.FILTER).addObjects((Object[]) filters), TimeSeriesBuilderFactory.TIMESERIES_MGET_RESPONSE); } public final CommandObject tsCreateRule(String sourceKey, String destKey, AggregationType aggregationType, @@ -3786,7 +3782,7 @@ public final CommandObject> bfMExists(String key, String... items) } public final CommandObject> bfScanDump(String key, long iterator) { - return new CommandObject<>(commandArguments(BloomFilterCommand.SCANDUMP).key(key).add(iterator), BuilderFactory.BLOOM_SCANDUMP_RESPONSE); + return new CommandObject<>(commandArguments(BloomFilterCommand.SCANDUMP).key(key).add(iterator), BLOOM_SCANDUMP_RESPONSE); } public final CommandObject bfLoadChunk(String key, long iterator, byte[] data) { @@ -3855,7 +3851,7 @@ public final CommandObject cfCount(String key, String item) { } public final CommandObject> cfScanDump(String key, long iterator) { - return new CommandObject<>(commandArguments(CuckooFilterCommand.SCANDUMP).key(key).add(iterator), BuilderFactory.BLOOM_SCANDUMP_RESPONSE); + return new CommandObject<>(commandArguments(CuckooFilterCommand.SCANDUMP).key(key).add(iterator), BLOOM_SCANDUMP_RESPONSE); } public final CommandObject cfLoadChunk(String key, long iterator, byte[] data) { @@ -4052,7 +4048,7 @@ public SearchProfileResponseBuilder(Builder replyBuilder) { public Map.Entry> build(Object data) { List list = (List) data; return KeyValue.of(replyBuilder.build(list.get(0)), - BuilderFactory.SEARCH_PROFILE_PROFILE.build(list.get(1))); + SearchBuilderFactory.SEARCH_PROFILE_PROFILE.build(list.get(1))); } } private class GsonObjectBuilder extends Builder { @@ -4087,6 +4083,14 @@ public List build(Object data) { } } + private static final Builder> BLOOM_SCANDUMP_RESPONSE = new Builder>() { + @Override + public Map.Entry build(Object data) { + List list = (List) data; + return new KeyValue<>(BuilderFactory.LONG.build(list.get(0)), BuilderFactory.BINARY.build(list.get(1))); + } + }; + private CommandArguments addFlatArgs(CommandArguments args, long... values) { for (long value : values) { args.add(value); diff --git a/src/main/java/redis/clients/jedis/JsonBuilderFactory.java b/src/main/java/redis/clients/jedis/JsonBuilderFactory.java deleted file mode 100644 index 2638b0c926..0000000000 --- a/src/main/java/redis/clients/jedis/JsonBuilderFactory.java +++ /dev/null @@ -1,70 +0,0 @@ -package redis.clients.jedis; - -import java.util.List; -import java.util.stream.Collectors; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import redis.clients.jedis.exceptions.JedisException; - -final class JsonBuilderFactory { - - private JsonBuilderFactory() { - } - - static final Builder JSON_OBJECT = new Builder() { - @Override - public Object build(Object data) { - if (data == null) { - return null; - } - - if (!(data instanceof byte[])) { - return data; - } - - String str = BuilderFactory.STRING.build(data); - if (str.charAt(0) == '{') { - try { - return new JSONObject(str); - } catch (Exception ex) { - } - } else if (str.charAt(0) == '[') { - try { - return new JSONArray(str); - } catch (Exception ex) { - } - } - return str; - } - }; - - static final Builder JSON_ARRAY = new Builder() { - @Override - public JSONArray build(Object data) { - if (data == null) { - return null; - } - String str = BuilderFactory.STRING.build(data); - try { - return new JSONArray(str); - } catch (JSONException ex) { - // This is not necessary but we are doing this just to make is safer - // for com.vaadin.external.google:android-json library - throw new JedisException(ex); - } - } - }; - - static final Builder> JSON_ARRAY_LIST = new Builder>() { - @Override - public List build(Object data) { - if (data == null) { - return null; - } - List list = (List) data; - return list.stream().map(o -> JSON_ARRAY.build(o)).collect(Collectors.toList()); - } - }; - -} diff --git a/src/main/java/redis/clients/jedis/json/JsonBuilderFactory.java b/src/main/java/redis/clients/jedis/json/JsonBuilderFactory.java new file mode 100644 index 0000000000..8b4ec686bc --- /dev/null +++ b/src/main/java/redis/clients/jedis/json/JsonBuilderFactory.java @@ -0,0 +1,120 @@ +package redis.clients.jedis.json; + +import static redis.clients.jedis.BuilderFactory.STRING; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import redis.clients.jedis.Builder; +import redis.clients.jedis.exceptions.JedisException; + +public final class JsonBuilderFactory { + + public static final Builder> JSON_TYPE = new Builder>() { + @Override + public Class build(Object data) { + if (data == null) return null; + String str = STRING.build(data); + switch (str) { + case "null": + return null; + case "boolean": + return boolean.class; + case "integer": + return int.class; + case "number": + return float.class; + case "string": + return String.class; + case "object": + return Object.class; + case "array": + return List.class; + default: + throw new JedisException("Unknown type: " + str); + } + } + + @Override + public String toString() { + return "Class"; + } + }; + + public static final Builder>> JSON_TYPE_LIST = new Builder>>() { + @Override + public List> build(Object data) { + List list = (List) data; + List> classes = new ArrayList<>(list.size()); + for (Object elem : list) { + try { + classes.add(JSON_TYPE.build(elem)); + } catch (JedisException je) { + classes.add(null); + } + } + return classes; + } + }; + + public static final Builder JSON_OBJECT = new Builder() { + @Override + public Object build(Object data) { + if (data == null) { + return null; + } + + if (!(data instanceof byte[])) { + return data; + } + + String str = STRING.build(data); + if (str.charAt(0) == '{') { + try { + return new JSONObject(str); + } catch (Exception ex) { + } + } else if (str.charAt(0) == '[') { + try { + return new JSONArray(str); + } catch (Exception ex) { + } + } + return str; + } + }; + + public static final Builder JSON_ARRAY = new Builder() { + @Override + public JSONArray build(Object data) { + if (data == null) { + return null; + } + String str = STRING.build(data); + try { + return new JSONArray(str); + } catch (JSONException ex) { // This is not necessary but we are doing this + // just to make it safe for com.vaadin.external.google:android-json library + throw new JedisException(ex); + } + } + }; + + public static final Builder> JSON_ARRAY_LIST = new Builder>() { + @Override + public List build(Object data) { + if (data == null) { + return null; + } + List list = (List) data; + return list.stream().map(o -> JSON_ARRAY.build(o)).collect(Collectors.toList()); + } + }; + + private JsonBuilderFactory() { + throw new InstantiationError("Must not instantiate this class"); + } +} diff --git a/src/main/java/redis/clients/jedis/search/SearchBuilderFactory.java b/src/main/java/redis/clients/jedis/search/SearchBuilderFactory.java new file mode 100644 index 0000000000..7083d9e4f3 --- /dev/null +++ b/src/main/java/redis/clients/jedis/search/SearchBuilderFactory.java @@ -0,0 +1,175 @@ +package redis.clients.jedis.search; + +import static redis.clients.jedis.BuilderFactory.STRING; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +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.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"; + private final String CHILD_ITERATORS_STR = "Child iterators"; + private final String RESULT_PROCESSORS_PROFILE_STR = "Result processors profile"; + + @Override + public Map build(Object data) { + List list = (List) SafeEncoder.encodeObject(data); + Map profileMap = new HashMap<>(list.size(), 1f); + + for (Object listObject : list) { + List attributeList = (List) listObject; + String attributeName = (String) attributeList.get(0); + Object attributeValue; + + if (attributeList.size() == 2) { + + Object value = attributeList.get(1); + if (attributeName.equals(ITERATORS_PROFILE_STR)) { + attributeValue = parseIterators(value); + } else if (attributeName.endsWith(" time")) { + attributeValue = DoublePrecision.parseFloatingPointNumber((String) value); + } else { + attributeValue = value; + } + + } else if (attributeList.size() > 2) { + + if (attributeName.equals(RESULT_PROCESSORS_PROFILE_STR)) { + List> resultProcessorsProfileList = new ArrayList<>(attributeList.size() - 1); + for (int i = 1; i < attributeList.size(); i++) { + resultProcessorsProfileList.add(parseResultProcessors(attributeList.get(i))); + } + attributeValue = resultProcessorsProfileList; + } else { + attributeValue = attributeList.subList(1, attributeList.size()); + } + + } else { + attributeValue = null; + } + + profileMap.put(attributeName, attributeValue); + } + return profileMap; + } + + private Map parseResultProcessors(Object data) { + List list = (List) data; + Map map = new HashMap<>(list.size() / 2, 1f); + for (int i = 0; i < list.size(); i += 2) { + String key = (String) list.get(i); + Object value = list.get(i + 1); + if (key.equals("Time")) { + value = DoublePrecision.parseFloatingPointNumber((String) value); + } + map.put(key, value); + } + return map; + } + + private Object parseIterators(Object data) { + if (!(data instanceof List)) return data; + List iteratorsAttributeList = (List) data; + int childIteratorsIndex = iteratorsAttributeList.indexOf(CHILD_ITERATORS_STR); + // https://github.com/RediSearch/RediSearch/issues/3205 patch. TODO: Undo if resolved in RediSearch. + if (childIteratorsIndex < 0) childIteratorsIndex = iteratorsAttributeList.indexOf("Child iterator"); + + Map iteratorsProfile; + if (childIteratorsIndex < 0) { + childIteratorsIndex = iteratorsAttributeList.size(); + iteratorsProfile = new HashMap<>(childIteratorsIndex / 2, 1f); + } else { + iteratorsProfile = new HashMap<>(1 + childIteratorsIndex / 2, 1f); + } + + for (int i = 0; i < childIteratorsIndex; i += 2) { + String key = (String) iteratorsAttributeList.get(i); + Object value = iteratorsAttributeList.get(i + 1); + if (key.equals("Time")) { + value = DoublePrecision.parseFloatingPointNumber((String) value); + } + iteratorsProfile.put(key, value); + } + + if (childIteratorsIndex + 1 < iteratorsAttributeList.size()) { + List childIteratorsList = new ArrayList(iteratorsAttributeList.size() - childIteratorsIndex - 1); + for (int i = childIteratorsIndex + 1; i < iteratorsAttributeList.size(); i++) { + childIteratorsList.add(parseIterators(iteratorsAttributeList.get(i))); + } + iteratorsProfile.put(CHILD_ITERATORS_STR, childIteratorsList); + } + return iteratorsProfile; + } + }; + + public static final Builder>> SEARCH_SYNONYM_GROUPS = new Builder>>() { + @Override + public Map> build(Object data) { + List list = (List) data; + 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))); + } + return dump; + } + }; + + public static final Builder>> SEARCH_SPELLCHECK_RESPONSE + = new Builder>>() { + + private final String TERM = "TERM"; + + @Override + public Map> build(Object data) { + List rawTerms = (List) data; + Map> returnTerms = new LinkedHashMap<>(rawTerms.size()); + + for (Object rawTerm : rawTerms) { + List rawElements = (List) rawTerm; + + String header = STRING.build(rawElements.get(0)); + if (!TERM.equals(header)) { + throw new IllegalStateException("Unrecognized header: " + header); + } + String term = STRING.build(rawElements.get(1)); + + List> list = (List>) rawElements.get(2); + Map entries = new LinkedHashMap<>(list.size()); + list.forEach(entry -> entries.put(STRING.build(entry.get(1)), BuilderFactory.DOUBLE.build(entry.get(0)))); + + returnTerms.put(term, entries); + } + return returnTerms; + } + }; + + private SearchBuilderFactory() { + throw new InstantiationError("Must not instantiate this class"); + } +} diff --git a/src/main/java/redis/clients/jedis/timeseries/TimeSeriesBuilderFactory.java b/src/main/java/redis/clients/jedis/timeseries/TimeSeriesBuilderFactory.java new file mode 100644 index 0000000000..8ee566d169 --- /dev/null +++ b/src/main/java/redis/clients/jedis/timeseries/TimeSeriesBuilderFactory.java @@ -0,0 +1,55 @@ +package redis.clients.jedis.timeseries; + +import java.util.List; +import java.util.stream.Collectors; +import redis.clients.jedis.Builder; +import redis.clients.jedis.BuilderFactory; + +public final class TimeSeriesBuilderFactory { + + public static final Builder TIMESERIES_ELEMENT = new Builder() { + @Override + public TSElement build(Object data) { + List list = (List) data; + if (list == null || list.isEmpty()) return null; + return new TSElement(BuilderFactory.LONG.build(list.get(0)), BuilderFactory.DOUBLE.build(list.get(1))); + } + }; + + public static final Builder> TIMESERIES_ELEMENT_LIST = new Builder>() { + @Override + public List build(Object data) { + return ((List) data).stream().map((pairObject) -> (List) pairObject) + .map((pairList) -> new TSElement(BuilderFactory.LONG.build(pairList.get(0)), + BuilderFactory.DOUBLE.build(pairList.get(1)))) + .collect(Collectors.toList()); + } + }; + + public static final Builder> TIMESERIES_MRANGE_RESPONSE = new Builder>() { + @Override + public List build(Object data) { + return ((List) data).stream().map((tsObject) -> (List) tsObject) + .map((tsList) -> new TSKeyedElements(BuilderFactory.STRING.build(tsList.get(0)), + BuilderFactory.STRING_MAP_FROM_PAIRS.build(tsList.get(1)), + TIMESERIES_ELEMENT_LIST.build(tsList.get(2)))) + .collect(Collectors.toList()); + } + }; + + public static final Builder>> TIMESERIES_MGET_RESPONSE + = new Builder>>() { + @Override + public List> build(Object data) { + return ((List) data).stream().map((tsObject) -> (List) tsObject) + .map((tsList) -> new TSKeyValue<>(BuilderFactory.STRING.build(tsList.get(0)), + BuilderFactory.STRING_MAP_FROM_PAIRS.build(tsList.get(1)), + TIMESERIES_ELEMENT.build(tsList.get(2)))) + .collect(Collectors.toList()); + } + }; + + private TimeSeriesBuilderFactory() { + throw new InstantiationError("Must not instantiate this class"); + } +}