Skip to content

Commit 1577b26

Browse files
committed
fix: EqualPredicate changes in 0.9.10 breaking search syntax (#609)
Fix regression introduced in v0.9.10 where tag field equality predicates incorrectly escape quotes, causing Redis syntax errors.
1 parent 2288d97 commit 1577b26

File tree

2 files changed

+103
-2
lines changed

2 files changed

+103
-2
lines changed

redis-om-spring/src/main/java/com/redis/om/spring/search/stream/predicates/tag/EqualPredicate.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,27 @@ public Node apply(Node root) {
9595
Iterable<?> values = (Iterable<?>) getValue();
9696
QueryNode and = QueryBuilders.intersect();
9797
for (Object v : values) {
98-
and.add(getSearchAlias(), "{\"" + v.toString() + "\"}");
98+
and.add(getSearchAlias(), escapeTagValue(v.toString()));
9999
}
100100
return QueryBuilders.intersect(root, and);
101101
} else {
102-
return QueryBuilders.intersect(root).add(getSearchAlias(), "{\"" + value.toString() + "\"}");
102+
return QueryBuilders.intersect(root).add(getSearchAlias(), escapeTagValue(value.toString()));
103+
}
104+
}
105+
106+
/**
107+
* Escapes a tag value for Redis tag queries.
108+
* Values with special characters need to be escaped.
109+
*/
110+
private String escapeTagValue(String value) {
111+
// Check if the value contains special characters that need escaping
112+
// Special characters in Redis tags: space, comma, period, <, >, {, }, [, ], ", ', :, ;, !, @, #, $, %, ^, &, *, (, ), -, +, =, ~, /
113+
if (value.matches(".*[\\s,.<>{}\\[\\]\"':;!@#$%^&*()\\-+=~/].*")) {
114+
// For values with special characters, wrap in quotes to handle escaping
115+
return "{\"" + value + "\"}";
116+
} else {
117+
// For simple values (alphanumeric and underscore), no quotes needed
118+
return "{" + value + "}";
103119
}
104120
}
105121

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.redis.om.spring.search.stream.predicates.tag;
2+
3+
import com.redis.om.spring.metamodel.SearchFieldAccessor;
4+
import org.junit.jupiter.api.Test;
5+
import redis.clients.jedis.search.querybuilder.Node;
6+
import redis.clients.jedis.search.querybuilder.QueryBuilders;
7+
8+
import java.lang.reflect.Field;
9+
10+
import static org.assertj.core.api.Assertions.assertThat;
11+
12+
/**
13+
* Test to verify the fix for issue #609
14+
* https://github.com/redis/redis-om-spring/issues/609
15+
*
16+
* In version 0.9.10, the EqualPredicate for tag fields started incorrectly
17+
* escaping quotes, causing syntax errors in Redis queries.
18+
* This test verifies the fix is working correctly.
19+
*/
20+
class TagEqualPredicateRegressionTest {
21+
22+
@Test
23+
void testTagEqualPredicateWithSimpleValue() throws NoSuchFieldException {
24+
// Given a field and a simple alphanumeric value
25+
Field mockField = String.class.getDeclaredField("value");
26+
SearchFieldAccessor fieldAccessor = new SearchFieldAccessor("type", "$.type", mockField);
27+
String enumValue = "REGISTRATION";
28+
29+
// When creating an EqualPredicate
30+
EqualPredicate<Object, String> predicate = new EqualPredicate<>(fieldAccessor, enumValue);
31+
32+
// And applying it to a query
33+
Node root = QueryBuilders.intersect();
34+
Node result = predicate.apply(root);
35+
36+
// Then the generated query should have the correct syntax without quotes
37+
String queryString = result.toString();
38+
39+
// Simple values should not have quotes
40+
assertThat(queryString).contains("@type:{REGISTRATION}");
41+
assertThat(queryString).doesNotContain("@type:{\"REGISTRATION\"}");
42+
}
43+
44+
@Test
45+
void testTagEqualPredicateWithSpecialCharacters() throws NoSuchFieldException {
46+
// Given a field and value with special characters (spaces)
47+
Field mockField = String.class.getDeclaredField("value");
48+
SearchFieldAccessor fieldAccessor = new SearchFieldAccessor("status", "$.status", mockField);
49+
String valueWithSpaces = "IN PROGRESS";
50+
51+
// When creating an EqualPredicate
52+
EqualPredicate<Object, String> predicate = new EqualPredicate<>(fieldAccessor, valueWithSpaces);
53+
54+
// And applying it to a query
55+
Node root = QueryBuilders.intersect();
56+
Node result = predicate.apply(root);
57+
58+
// Then the generated query should use quotes for values with special characters
59+
String queryString = result.toString();
60+
61+
// Values with special characters should be quoted
62+
assertThat(queryString).contains("@status:{\"IN PROGRESS\"}");
63+
}
64+
65+
@Test
66+
void testTagEqualPredicateWithUUID() throws NoSuchFieldException {
67+
// Given a field and a UUID value (contains hyphens)
68+
Field mockField = String.class.getDeclaredField("value");
69+
SearchFieldAccessor fieldAccessor = new SearchFieldAccessor("uuid", "$.uuid", mockField);
70+
String uuidValue = "123e4567-e89b-12d3-a456-426614174000";
71+
72+
// When creating an EqualPredicate
73+
EqualPredicate<Object, String> predicate = new EqualPredicate<>(fieldAccessor, uuidValue);
74+
75+
// And applying it to a query
76+
Node root = QueryBuilders.intersect();
77+
Node result = predicate.apply(root);
78+
79+
// Then the generated query should use quotes because UUIDs contain hyphens
80+
String queryString = result.toString();
81+
82+
// UUIDs with hyphens need quotes
83+
assertThat(queryString).contains("@uuid:{\"123e4567-e89b-12d3-a456-426614174000\"}");
84+
}
85+
}

0 commit comments

Comments
 (0)