Skip to content

Commit

Permalink
Add support for quoted (default) MongoDB search term values in Search…
Browse files Browse the repository at this point in the history
…QueryParser (#21567)

* Add support for quoted default search term values

* Add change log

* Cleanup

(cherry picked from commit 32fbea9)
  • Loading branch information
danotorrey authored and github-actions[bot] committed Feb 11, 2025
1 parent a878d86 commit 05558f7
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 1 deletion.
5 changes: 5 additions & 0 deletions changelog/unreleased/issue-21565.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type = "fixed"
message = "Fixed issue preventing quoted entity search values from finding exact matches on various pages throughout Graylog."

issues = ["21565"]
pulls = ["21567"]
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,16 @@ public class SearchQueryParser {
private static final Splitter FIELD_VALUE_SPLITTER = Splitter.on(":").limit(2).omitEmptyStrings().trimResults();
private static final Splitter VALUE_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();

// Pattern to split a search query into individual parsable elements terms.
private static final String TERM_SPLIT_PATTERN =
"(\\S+:(=|=~|<|<=|>|>=)?'(?:[^'\\\\]|\\\\.)*')|" + // Split field-specific terms with single-quotes: title:'value'
"(\\S+:(=|=~|<|<=|>|>=)?\"(?:[^\"\\\\]|\\\\.)*\")|" + // Split field-specific terms with double-quotes title:"value"
"['\"][^\\\\]*?(?:\\\\.[^\\\\]*)*?['\"]|" + // Split single quoted value: "value one"
"\\S+:(=|=~|<|<=|>|>=)?\\S+|" + // Split field-specific terms without quotes title:value
"\\S+"; // Split the words of any other string value

// This needs to be updated if more operators are added
private static final Pattern QUERY_SPLITTER_PATTERN = Pattern.compile("(\\S+:(=|=~|<|<=|>|>=)?'(?:[^'\\\\]|\\\\.)*')|(\\S+:(=|=~|<|<=|>|>=)?\"(?:[^\"\\\\]|\\\\.)*\")|\\S+|\\S+:(=|=~|<|<=|>|>=)?\\S+");
private static final Pattern QUERY_SPLITTER_PATTERN = Pattern.compile(TERM_SPLIT_PATTERN);
private static final String INVALID_ENTRY_MESSAGE = "Chunk [%s] is not a valid entry";
private static final String QUOTE_REPLACE_REGEX = "^[\"']|[\"']$";
public static final SearchQueryOperator DEFAULT_STRING_OPERATOR = SearchQueryOperators.REGEXP;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,31 @@ void emptyFieldPrefixDoesNotChangeDefaultBehavior() {
assertThat(searchQuery.hasDisallowedKeys()).isFalse();
}

@Test
void unquotedEmptyFieldPrefixSingleSearchTerm() {
final SearchQueryParser parser = new SearchQueryParser("name", Set.of(), "");
// Verify unquoted term is split into two search values.
final SearchQuery searchQuery = parser.parse("Bobby testerson");
final Multimap<String, SearchQueryParser.FieldValue> queryMap = searchQuery.getQueryMap();
assertThat(queryMap.keySet().size()).isEqualTo(1);
final Collection<SearchQueryParser.FieldValue> values = queryMap.get("name");
assertThat(values.size()).isEqualTo(2);
assertThat(values).contains(new SearchQueryParser.FieldValue("Bobby", false));
assertThat(values).contains(new SearchQueryParser.FieldValue("testerson", false));
}

@Test
void quotedEmptyFieldPrefixSingleSearchTerm() {
final SearchQueryParser parser = new SearchQueryParser("name", Set.of(), "");
// Verify quoted term is maintained as a single search value.
final SearchQuery searchQuery = parser.parse("\"Bobby testerson\"");
final Multimap<String, SearchQueryParser.FieldValue> queryMap = searchQuery.getQueryMap();
assertThat(queryMap.keySet().size()).isEqualTo(1);
final Collection<SearchQueryParser.FieldValue> values = queryMap.get("name");
assertThat(values.size()).isEqualTo(1);
assertThat(values).containsOnly(new SearchQueryParser.FieldValue("Bobby testerson", false));
}

@Test
void booleanValuesSupported() {
final SearchQueryParser parser = new SearchQueryParser("name",
Expand Down

0 comments on commit 05558f7

Please sign in to comment.