|
@@ -95,13 +95,15 @@ boolean_term = (paren_term / search_term) space? (boolean_operator space
|
|
|
paren_term = space? open_paren space? (paren_term / boolean_term)+ space? closed_paren space?
|
|
|
search_term = key_val_term / quoted_raw_search / raw_search
|
|
|
key_val_term = space? (tag_filter / time_filter / rel_time_filter / specific_time_filter
|
|
|
- / numeric_filter / aggregate_filter / aggregate_date_filter / has_filter / is_filter / basic_filter)
|
|
|
+ / numeric_filter / aggregate_filter / aggregate_date_filter / has_filter
|
|
|
+ / is_filter / quoted_basic_filter / basic_filter)
|
|
|
space?
|
|
|
raw_search = (!key_val_term ~r"\ *([^\ ^\n ()]+)\ *" )*
|
|
|
quoted_raw_search = spaces quoted_value spaces
|
|
|
|
|
|
# standard key:val filter
|
|
|
basic_filter = negation? search_key sep search_value
|
|
|
+quoted_basic_filter = negation? search_key sep quoted_value
|
|
|
# filter for dates
|
|
|
time_filter = search_key sep? operator date_format
|
|
|
# filter for relative dates
|
|
@@ -470,9 +472,18 @@ class SearchVisitor(NodeVisitor):
|
|
|
|
|
|
return node.text == "!"
|
|
|
|
|
|
+ def visit_quoted_basic_filter(self, node, children):
|
|
|
+ (negation, search_key, _, search_value) = children
|
|
|
+ operator = "!=" if self.is_negated(negation) else "="
|
|
|
+ search_value = SearchValue(search_value)
|
|
|
+ return self._handle_basic_filter(search_key, operator, search_value)
|
|
|
+
|
|
|
def visit_basic_filter(self, node, children):
|
|
|
(negation, search_key, _, search_value) = children
|
|
|
operator = "!=" if self.is_negated(negation) else "="
|
|
|
+ if not search_value.raw_value:
|
|
|
+ raise InvalidSearchQuery("Empty string after '%s:'" % search_key.name)
|
|
|
+
|
|
|
return self._handle_basic_filter(search_key, operator, search_value)
|
|
|
|
|
|
def _handle_basic_filter(self, search_key, operator, search_value):
|
|
@@ -504,7 +515,7 @@ class SearchVisitor(NodeVisitor):
|
|
|
return SearchFilter(SearchKey(u"tags[%s]" % (search_key.name)), operator, search_value)
|
|
|
|
|
|
def visit_is_filter(self, node, children):
|
|
|
- raise InvalidSearchQuery('"is" queries are not supported on this search')
|
|
|
+ raise InvalidSearchQuery('"is:" queries are only supported in issue search.')
|
|
|
|
|
|
def visit_search_key(self, node, children):
|
|
|
key = children[0]
|