Skip to content

Commit 3d1cc9d

Browse files
committed
fix(query): escape special characters in tag filter values
Add escapeTagValue() method that escapes RediSearch special characters including spaces in tag values. This prevents syntax errors when tag values contain hyphens, colons, periods, or other special characters. - Add escapeTagValue() that calls escapeSpecialCharacters() + space escaping - Update tag() method to escape each value before building the query - Add comprehensive test covering hyphens, colons, @, spaces, and multiple values Test cases verified: - "test-user-001" → "test\-user\-001" - "2025-12-10T15:02:37Z" → "2025\-12\-10T15\:02\:37Z" - "user@example.com" → "user\@example\.com" - "New York" → "New\ York"
1 parent 53b4e91 commit 3d1cc9d

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

core/src/main/java/com/redis/vl/query/Filter.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ public static Filter tag(String field, String... values) {
6161
return new Filter(FilterType.CUSTOM, field, "*", null);
6262
}
6363

64-
String valueStr = values.length == 1 ? values[0] : String.join("|", values);
64+
// Escape special characters in each tag value (including spaces)
65+
String[] escapedValues =
66+
Arrays.stream(values).map(Filter::escapeTagValue).toArray(String[]::new);
67+
String valueStr =
68+
escapedValues.length == 1 ? escapedValues[0] : String.join("|", escapedValues);
6569

6670
String expr = String.format("@%s:{%s}", escapeFieldName(field), valueStr);
6771
return new Filter(FilterType.TAG, field, expr, null);
@@ -278,7 +282,7 @@ private static void validateValue(String value) {
278282
}
279283
}
280284

281-
/** Escape special characters in search queries */
285+
/** Escape special characters in search queries (for text filters - does NOT escape spaces) */
282286
private static String escapeSpecialCharacters(String value) {
283287
// Escape Redis search special characters
284288
return value
@@ -313,6 +317,12 @@ private static String escapeSpecialCharacters(String value) {
313317
.replace(";", "\\;");
314318
}
315319

320+
/** Escape special characters in tag values (includes space escaping) */
321+
private static String escapeTagValue(String value) {
322+
// For tag values, escape all special characters including spaces
323+
return escapeSpecialCharacters(value).replace(" ", "\\ ");
324+
}
325+
316326
/**
317327
* Build the filter query string
318328
*

core/src/test/java/com/redis/vl/query/FilterQueryTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,35 @@ void shouldCreateTagFilterWithMultipleValues() {
5252
assertThat(filter.build()).isEqualTo("@tags:{redis|database|nosql}");
5353
}
5454

55+
@Test
56+
@DisplayName("Should escape special characters in tag values")
57+
void shouldEscapeSpecialCharactersInTagValues() {
58+
// When - test value with hyphens
59+
Filter filterWithHyphen = Filter.tag("user_id", "test-user-001");
60+
// Then
61+
assertThat(filterWithHyphen.build()).isEqualTo("@user_id:{test\\-user\\-001}");
62+
63+
// When - test value with colons (timestamp)
64+
Filter filterWithColon = Filter.tag("timestamp", "2025-12-10T15:02:37Z");
65+
// Then
66+
assertThat(filterWithColon.build()).isEqualTo("@timestamp:{2025\\-12\\-10T15\\:02\\:37Z}");
67+
68+
// When - test value with @ symbol (email)
69+
Filter filterWithAt = Filter.tag("email", "user@example.com");
70+
// Then
71+
assertThat(filterWithAt.build()).isEqualTo("@email:{user\\@example\\.com}");
72+
73+
// When - test value with spaces
74+
Filter filterWithSpace = Filter.tag("category", "New York");
75+
// Then
76+
assertThat(filterWithSpace.build()).isEqualTo("@category:{New\\ York}");
77+
78+
// When - test multiple values with special characters
79+
Filter filterMultiple = Filter.tag("tags", "dev-ops", "ci-cd", "k8s");
80+
// Then
81+
assertThat(filterMultiple.build()).isEqualTo("@tags:{dev\\-ops|ci\\-cd|k8s}");
82+
}
83+
5584
@Test
5685
@DisplayName("Should create numeric range filter")
5786
void shouldCreateNumericRangeFilter() {

0 commit comments

Comments
 (0)