Skip to content

Commit d369cf6

Browse files
authored
Merge branch 'master' into 5.2.0
2 parents ce210ea + fdf165f commit d369cf6

File tree

7 files changed

+534
-70
lines changed

7 files changed

+534
-70
lines changed

Diff for: pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@
315315
<!--Sign the components - this is required by maven central for releases -->
316316
<plugin>
317317
<artifactId>maven-gpg-plugin</artifactId>
318-
<version>3.2.4</version>
318+
<version>3.2.5</version>
319319
<configuration>
320320
<gpgArguments>
321321
<arg>--pinentry-mode</arg>

Diff for: src/main/java/redis/clients/jedis/CommandObjects.java

+20-12
Original file line numberDiff line numberDiff line change
@@ -3384,19 +3384,20 @@ public final CommandObject<String> ftDropIndexDD(String indexName) {
33843384

33853385
public final CommandObject<SearchResult> ftSearch(String indexName, String query) {
33863386
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SEARCH, indexName).add(query),
3387-
getSearchResultBuilder(() -> new SearchResultBuilder(true, false, true)));
3387+
getSearchResultBuilder(null, () -> new SearchResultBuilder(true, false, true)));
33883388
}
33893389

33903390
public final CommandObject<SearchResult> ftSearch(String indexName, String query, FTSearchParams params) {
33913391
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SEARCH, indexName)
33923392
.add(query).addParams(params.dialectOptional(searchDialect.get())),
3393-
getSearchResultBuilder(() -> new SearchResultBuilder(!params.getNoContent(), params.getWithScores(), true)));
3393+
getSearchResultBuilder(params.getReturnFieldDecodeMap(), () -> new SearchResultBuilder(
3394+
!params.getNoContent(), params.getWithScores(), true, params.getReturnFieldDecodeMap())));
33943395
}
33953396

33963397
public final CommandObject<SearchResult> ftSearch(String indexName, Query query) {
33973398
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SEARCH, indexName)
3398-
.addParams(query.dialectOptional(searchDialect.get())), getSearchResultBuilder(() ->
3399-
new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true)));
3399+
.addParams(query.dialectOptional(searchDialect.get())), getSearchResultBuilder(null,
3400+
() -> new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true)));
34003401
}
34013402

34023403
@Deprecated
@@ -3405,8 +3406,8 @@ public final CommandObject<SearchResult> ftSearch(byte[] indexName, Query query)
34053406
throw new UnsupportedOperationException("binary ft.search is not implemented with resp3.");
34063407
}
34073408
return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.SEARCH), indexName)
3408-
.addParams(query.dialectOptional(searchDialect.get())), getSearchResultBuilder(() ->
3409-
new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), false)));
3409+
.addParams(query.dialectOptional(searchDialect.get())), getSearchResultBuilder(null,
3410+
() -> new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), false)));
34103411
}
34113412

34123413
public final CommandObject<String> ftExplain(String indexName, Query query) {
@@ -3449,20 +3450,27 @@ public final CommandObject<Map.Entry<SearchResult, Map<String, Object>>> ftProfi
34493450
String indexName, FTProfileParams profileParams, Query query) {
34503451
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.PROFILE, indexName)
34513452
.add(SearchKeyword.SEARCH).addParams(profileParams).add(SearchKeyword.QUERY)
3452-
.addParams(query.dialectOptional(searchDialect.get())), new SearchProfileResponseBuilder<>(
3453-
getSearchResultBuilder(() -> new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true))));
3453+
.addParams(query.dialectOptional(searchDialect.get())),
3454+
new SearchProfileResponseBuilder<>(getSearchResultBuilder(null,
3455+
() -> new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true))));
34543456
}
34553457

34563458
public final CommandObject<Map.Entry<SearchResult, Map<String, Object>>> ftProfileSearch(
34573459
String indexName, FTProfileParams profileParams, String query, FTSearchParams searchParams) {
34583460
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.PROFILE, indexName)
34593461
.add(SearchKeyword.SEARCH).addParams(profileParams).add(SearchKeyword.QUERY).add(query)
3460-
.addParams(searchParams.dialectOptional(searchDialect.get())), new SearchProfileResponseBuilder<>(
3461-
getSearchResultBuilder(() -> new SearchResultBuilder(!searchParams.getNoContent(), searchParams.getWithScores(), true))));
3462+
.addParams(searchParams.dialectOptional(searchDialect.get())),
3463+
new SearchProfileResponseBuilder<>(getSearchResultBuilder(searchParams.getReturnFieldDecodeMap(),
3464+
() -> new SearchResultBuilder(!searchParams.getNoContent(), searchParams.getWithScores(), true,
3465+
searchParams.getReturnFieldDecodeMap()))));
34623466
}
34633467

3464-
private Builder<SearchResult> getSearchResultBuilder(Supplier<Builder<SearchResult>> resp2) {
3465-
if (protocol == RedisProtocol.RESP3) return SearchResult.SEARCH_RESULT_BUILDER;
3468+
private Builder<SearchResult> getSearchResultBuilder(
3469+
Map<String, Boolean> isReturnFieldDecode, Supplier<Builder<SearchResult>> resp2) {
3470+
if (protocol == RedisProtocol.RESP3) {
3471+
return isReturnFieldDecode == null ? SearchResult.SEARCH_RESULT_BUILDER
3472+
: new SearchResult.PerFieldDecoderSearchResultBuilder(isReturnFieldDecode);
3473+
}
34663474
return resp2.get();
34673475
}
34683476

Diff for: src/main/java/redis/clients/jedis/search/Document.java

+76-25
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.HashMap;
88
import java.util.List;
99
import java.util.Map;
10+
1011
import redis.clients.jedis.Builder;
1112
import redis.clients.jedis.BuilderFactory;
1213
import redis.clients.jedis.util.KeyValue;
@@ -50,24 +51,6 @@ public Iterable<Map.Entry<String, Object>> getProperties() {
5051
return fields.entrySet();
5152
}
5253

53-
public static Document load(String id, double score, byte[] payload, List<byte[]> fields) {
54-
return Document.load(id, score, fields, true);
55-
}
56-
57-
public static Document load(String id, double score, List<byte[]> fields, boolean decode) {
58-
Document ret = new Document(id, score);
59-
if (fields != null) {
60-
for (int i = 0; i < fields.size(); i += 2) {
61-
byte[] rawKey = fields.get(i);
62-
byte[] rawValue = fields.get(i + 1);
63-
String key = SafeEncoder.encode(rawKey);
64-
Object value = rawValue == null ? null : decode ? SafeEncoder.encode(rawValue) : rawValue;
65-
ret.set(key, value);
66-
}
67-
}
68-
return ret;
69-
}
70-
7154
/**
7255
* @return the document's id
7356
*/
@@ -102,16 +85,22 @@ public Object get(String key) {
10285
*/
10386
public String getString(String key) {
10487
Object value = fields.get(key);
105-
if (value instanceof String) {
88+
if (value == null) {
89+
return null;
90+
} else if (value instanceof String) {
10691
return (String) value;
92+
} else if (value instanceof byte[]) {
93+
return SafeEncoder.encode((byte[]) value);
94+
} else {
95+
return String.valueOf(value);
10796
}
108-
return value instanceof byte[] ? SafeEncoder.encode((byte[]) value) : value.toString();
10997
}
11098

11199
public boolean hasProperty(String key) {
112100
return fields.containsKey(key);
113101
}
114102

103+
// TODO: private ??
115104
public Document set(String key, Object value) {
116105
fields.put(key, value);
117106
return this;
@@ -122,7 +111,9 @@ public Document set(String key, Object value) {
122111
*
123112
* @param score new score to set
124113
* @return the document itself
114+
* @deprecated
125115
*/
116+
@Deprecated
126117
public Document setScore(float score) {
127118
this.score = (double) score;
128119
return this;
@@ -134,13 +125,58 @@ public String toString() {
134125
", properties:" + this.getProperties();
135126
}
136127

137-
static Builder<Document> SEARCH_DOCUMENT = new Builder<Document>() {
128+
/// RESP2 -->
129+
public static Document load(String id, double score, byte[] payload, List<byte[]> fields) {
130+
return Document.load(id, score, fields, true);
131+
}
132+
133+
public static Document load(String id, double score, List<byte[]> fields, boolean decode) {
134+
return load(id, score, fields, decode, null);
135+
}
136+
137+
/**
138+
* Parse document object from FT.SEARCH reply.
139+
* @param id
140+
* @param score
141+
* @param fields
142+
* @param decode
143+
* @param isFieldDecode checked only if {@code decode=true}
144+
* @return document
145+
*/
146+
public static Document load(String id, double score, List<byte[]> fields, boolean decode,
147+
Map<String, Boolean> isFieldDecode) {
148+
Document ret = new Document(id, score);
149+
if (fields != null) {
150+
for (int i = 0; i < fields.size(); i += 2) {
151+
byte[] rawKey = fields.get(i);
152+
byte[] rawValue = fields.get(i + 1);
153+
String key = SafeEncoder.encode(rawKey);
154+
Object value = rawValue == null ? null
155+
: (decode && (isFieldDecode == null || !Boolean.FALSE.equals(isFieldDecode.get(key))))
156+
? SafeEncoder.encode(rawValue) : rawValue;
157+
ret.set(key, value);
158+
}
159+
}
160+
return ret;
161+
}
162+
/// <-- RESP2
163+
164+
/// RESP3 -->
165+
// TODO: final
166+
static Builder<Document> SEARCH_DOCUMENT = new PerFieldDecoderDocumentBuilder((Map) null);
167+
168+
static final class PerFieldDecoderDocumentBuilder extends Builder<Document> {
138169

139170
private static final String ID_STR = "id";
140171
private static final String SCORE_STR = "score";
141-
// private static final String FIELDS_STR = "fields";
142172
private static final String FIELDS_STR = "extra_attributes";
143173

174+
private final Map<String, Boolean> isFieldDecode;
175+
176+
public PerFieldDecoderDocumentBuilder(Map<String, Boolean> isFieldDecode) {
177+
this.isFieldDecode = isFieldDecode != null ? isFieldDecode : Collections.emptyMap();
178+
}
179+
144180
@Override
145181
public Document build(Object data) {
146182
List<KeyValue> list = (List<KeyValue>) data;
@@ -157,13 +193,28 @@ public Document build(Object data) {
157193
score = BuilderFactory.DOUBLE.build(kv.getValue());
158194
break;
159195
case FIELDS_STR:
160-
fields = BuilderFactory.ENCODED_OBJECT_MAP.build(kv.getValue());
196+
fields = makeFieldsMap(isFieldDecode, kv.getValue());
161197
break;
162198
}
163199
}
164-
// assert id != null;
165-
// if (fields == null) fields = Collections.emptyMap();
166200
return new Document(id, score, fields);
167201
}
168202
};
203+
204+
private static Map<String, Object> makeFieldsMap(Map<String, Boolean> isDecode, Object data) {
205+
if (data == null) return null;
206+
207+
final List<KeyValue> list = (List) data;
208+
209+
Map<String, Object> map = new HashMap<>(list.size(), 1f);
210+
list.stream().filter((kv) -> (kv != null && kv.getKey() != null && kv.getValue() != null))
211+
.forEach((kv) -> {
212+
String key = BuilderFactory.STRING.build(kv.getKey());
213+
map.put(key,
214+
(Boolean.FALSE.equals(isDecode.get(key)) ? BuilderFactory.RAW_OBJECT
215+
: BuilderFactory.AGGRESSIVE_ENCODED_OBJECT).build(kv.getValue()));
216+
});
217+
return map;
218+
}
219+
/// <-- RESP3
169220
}

Diff for: src/main/java/redis/clients/jedis/search/FTSearchParams.java

+37-25
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ public class FTSearchParams implements IParams {
2424
private final List<IParams> filters = new LinkedList<>();
2525
private Collection<String> inKeys;
2626
private Collection<String> inFields;
27-
private Collection<String> returnFields;
28-
private Collection<FieldName> returnFieldNames;
27+
private Collection<FieldName> returnFieldsNames;
2928
private boolean summarize;
3029
private SummarizeParams summarizeParams;
3130
private boolean highlight;
@@ -43,6 +42,9 @@ public class FTSearchParams implements IParams {
4342
private Map<String, Object> params;
4443
private Integer dialect;
4544

45+
/// non command parameters
46+
private Map<String, Boolean> returnFieldDecodeMap = null;
47+
4648
public FTSearchParams() {
4749
}
4850

@@ -78,17 +80,15 @@ public void addParams(CommandArguments args) {
7880
args.add(INFIELDS).add(inFields.size()).addObjects(inFields);
7981
}
8082

81-
if (returnFieldNames != null && !returnFieldNames.isEmpty()) {
83+
if (returnFieldsNames != null && !returnFieldsNames.isEmpty()) {
8284
args.add(RETURN);
8385
LazyRawable returnCountObject = new LazyRawable();
8486
args.add(returnCountObject); // holding a place for setting the total count later.
8587
int returnCount = 0;
86-
for (FieldName fn : returnFieldNames) {
88+
for (FieldName fn : returnFieldsNames) {
8789
returnCount += fn.addCommandArguments(args);
8890
}
8991
returnCountObject.setRaw(Protocol.toByteArray(returnCount));
90-
} else if (returnFields != null && !returnFields.isEmpty()) {
91-
args.add(RETURN).add(returnFields.size()).addObjects(returnFields);
9292
}
9393

9494
if (summarizeParams != null) {
@@ -256,41 +256,46 @@ public FTSearchParams inFields(Collection<String> fields) {
256256
* @return the query object itself
257257
*/
258258
public FTSearchParams returnFields(String... fields) {
259-
if (returnFieldNames != null) {
260-
Arrays.stream(fields).forEach(f -> returnFieldNames.add(FieldName.of(f)));
261-
} else {
262-
if (returnFields == null) {
263-
returnFields = new ArrayList<>();
264-
}
265-
Arrays.stream(fields).forEach(f -> returnFields.add(f));
259+
if (returnFieldsNames == null) {
260+
returnFieldsNames = new ArrayList<>();
266261
}
262+
Arrays.stream(fields).forEach(f -> returnFieldsNames.add(FieldName.of(f)));
267263
return this;
268264
}
269265

270266
public FTSearchParams returnField(FieldName field) {
271-
initReturnFieldNames();
272-
returnFieldNames.add(field);
273-
return this;
267+
return returnFields(Collections.singleton(field));
274268
}
275269

276270
public FTSearchParams returnFields(FieldName... fields) {
277271
return returnFields(Arrays.asList(fields));
278272
}
279273

280274
public FTSearchParams returnFields(Collection<FieldName> fields) {
281-
initReturnFieldNames();
282-
returnFieldNames.addAll(fields);
275+
if (returnFieldsNames == null) {
276+
returnFieldsNames = new ArrayList<>();
277+
}
278+
returnFieldsNames.addAll(fields);
283279
return this;
284280
}
285281

286-
private void initReturnFieldNames() {
287-
if (returnFieldNames == null) {
288-
returnFieldNames = new ArrayList<>();
289-
}
290-
if (returnFields != null) {
291-
returnFields.forEach(f -> returnFieldNames.add(FieldName.of(f)));
292-
returnFields = null;
282+
public FTSearchParams returnField(String field, boolean decode) {
283+
returnFields(field);
284+
addReturnFieldDecode(field, decode);
285+
return this;
286+
}
287+
288+
public FTSearchParams returnField(FieldName field, boolean decode) {
289+
returnFields(field);
290+
addReturnFieldDecode(field.getAttribute() != null ? field.getAttribute() : field.getName(), decode);
291+
return this;
292+
}
293+
294+
private void addReturnFieldDecode(String returnName, boolean decode) {
295+
if (returnFieldDecodeMap == null) {
296+
returnFieldDecodeMap = new HashMap<>();
293297
}
298+
returnFieldDecodeMap.put(returnName, decode);
294299
}
295300

296301
public FTSearchParams summarize() {
@@ -436,14 +441,21 @@ public FTSearchParams dialectOptional(int dialect) {
436441
return this;
437442
}
438443

444+
@Internal
439445
public boolean getNoContent() {
440446
return noContent;
441447
}
442448

449+
@Internal
443450
public boolean getWithScores() {
444451
return withScores;
445452
}
446453

454+
@Internal
455+
public Map<String, Boolean> getReturnFieldDecodeMap() {
456+
return returnFieldDecodeMap;
457+
}
458+
447459
/**
448460
* NumericFilter wraps a range filter on a numeric field. It can be inclusive or exclusive
449461
*/

0 commit comments

Comments
 (0)