5252 / specific_time_filter
5353 / duration_filter
5454 / boolean_filter
55+ / numeric_in_filter
5556 / numeric_filter
5657 / aggregate_filter
5758 / aggregate_date_filter
5859 / aggregate_rel_date_filter
5960 / has_filter
6061 / is_filter
62+ / text_in_filter
6163 / text_filter
6264
6365# standard key:val filter
64- text_filter = negation? text_key sep ((open_bracket text_value (comma spaces text_value)* closed_bracket) / search_value)
66+ text_filter = negation? text_key sep search_value
67+
68+ # in filter key:[val1, val2]
69+ text_in_filter = negation? text_key sep text_in_list
6570
6671# filter for dates
6772time_filter = search_key sep operator iso_8601_date_format
7580# exact time filter for dates
7681specific_time_filter = search_key sep iso_8601_date_format
7782
78- # Numeric comparison filter
79- numeric_filter = search_key sep ((operator? numeric_value) / (open_bracket numeric_value (comma spaces numeric_value)* closed_bracket))
83+ # numeric comparison filter
84+ numeric_filter = search_key sep operator? numeric_value
85+
86+ # numeric in filter
87+ numeric_in_filter = search_key sep numeric_in_list
8088
81- # Boolean comparison filter
89+ # boolean comparison filter
8290boolean_filter = negation? search_key sep boolean_value
8391
84- # Aggregate numeric filter
92+ # aggregate numeric filter
8593aggregate_filter = negation? aggregate_key sep operator? (duration_format / numeric_value / percentage_format)
8694aggregate_date_filter = negation? aggregate_key sep operator? iso_8601_date_format
8795aggregate_rel_date_filter = negation? aggregate_key sep operator? rel_date_format
104112text_key = explicit_tag_key / search_key
105113text_value = quoted_value / in_value
106114quoted_value = ~r"\"((?:\\\"|[^\"])*)?\""s
115+ numeric_in_list = open_bracket numeric_value (comma spaces numeric_value)* closed_bracket
116+ text_in_list = open_bracket text_value (comma spaces text_value)* closed_bracket
107117
108118# Formats
109119iso_8601_date_format = ~r"(\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{1,6})?)?(Z|([+-]\d{2}:\d{2}))?)(?=\s|\)|$)"
@@ -375,12 +385,8 @@ def visit_boolean_filter(self, node, children):
375385 (
376386 search_key ,
377387 sep ,
378- (
379- (
380- "=" ,
381- search_value ,
382- ),
383- ),
388+ "=" ,
389+ search_value ,
384390 ),
385391 )
386392
@@ -405,41 +411,38 @@ def process_list(self, first, remaining):
405411 ]
406412
407413 def visit_numeric_filter (self , node , children ):
408- (search_key , _ , (value ,)) = children
409- operator = value [0 ]
414+ (search_key , _ , operator , search_value ) = children
410415 if isinstance (operator , Node ):
411- if isinstance (operator .expr , Optional ):
412- operator = "="
413- else :
414- operator = operator .text
416+ operator = "=" if isinstance (operator .expr , Optional ) else operator .text
415417 else :
416418 operator = operator [0 ]
417419
418- if operator == "[" :
419- operator = "IN"
420- search_value = self .process_list (value [1 ], value [2 ])
420+ if self .is_numeric_key (search_key .name ):
421+ try :
422+ search_value = SearchValue (parse_numeric_value (* search_value .match .groups ()))
423+ except InvalidQuery as exc :
424+ raise InvalidSearchQuery (str (exc ))
425+ return SearchFilter (search_key , operator , search_value )
421426 else :
422- search_value = value [1 ]
427+ search_value = search_value .text
428+ search_value = SearchValue (operator + search_value if operator != "=" else search_value )
429+ return self ._handle_basic_filter (search_key , "=" , search_value )
430+
431+ def visit_numeric_in_filter (self , node , children ):
432+ (search_key , _ , value ) = children
433+ operator = "IN"
434+ search_value = self .process_list (value [1 ], value [2 ])
423435
424436 if self .is_numeric_key (search_key .name ):
425437 try :
426438 search_value = SearchValue (
427439 [parse_numeric_value (* val .match .groups ()) for val in search_value ]
428- if operator == "IN"
429- else parse_numeric_value (* search_value .match .groups ())
430440 )
431441 except InvalidQuery as exc :
432442 raise InvalidSearchQuery (str (exc ))
433443 return SearchFilter (search_key , operator , search_value )
434444 else :
435- if operator != "IN" :
436- search_value = search_value .text
437- else :
438- search_value = [v .text for v in search_value ]
439- search_value = SearchValue (
440- operator + search_value if operator not in ("=" , "IN" ) else search_value
441- )
442- operator = "=" if operator not in ("=" , "IN" ) else operator
445+ search_value = SearchValue ([v .text for v in search_value ])
443446 return self ._handle_basic_filter (search_key , operator , search_value )
444447
445448 def handle_negation (self , negation , operator ):
@@ -542,7 +545,7 @@ def visit_duration_filter(self, node, children):
542545 raise InvalidSearchQuery (str (exc ))
543546 return SearchFilter (search_key , operator , SearchValue (search_value ))
544547 elif self .is_numeric_key (search_key .name ):
545- return self .visit_numeric_filter (node , (search_key , sep , (( operator , search_value ),) ))
548+ return self .visit_numeric_filter (node , (search_key , sep , operator , search_value ))
546549 else :
547550 search_value = operator + search_value .text if operator != "=" else search_value .text
548551 return self ._handle_basic_filter (search_key , "=" , SearchValue (search_value ))
@@ -605,18 +608,23 @@ def is_negated(self, node):
605608 return node .text == "!"
606609
607610 def visit_text_filter (self , node , children ):
608- (negation , search_key , _ , ( search_value ,) ) = children
611+ (negation , search_key , _ , search_value ) = children
609612 operator = "="
610- if isinstance (search_value , list ):
611- operator = "IN"
612- search_value = SearchValue (
613- self .process_list (search_value [1 ], [(_ , _ , val ) for _ , _ , val in search_value [2 ]])
614- )
615- else :
616- # XXX: We check whether the text in the node itself is actually empty, so
617- # we can tell the difference between an empty quoted string and no string
618- if not search_value .raw_value and not node .children [3 ].text :
619- raise InvalidSearchQuery (f"Empty string after '{ search_key .name } :'" )
613+ # XXX: We check whether the text in the node itself is actually empty, so
614+ # we can tell the difference between an empty quoted string and no string
615+ if not search_value .raw_value and not node .children [3 ].text :
616+ raise InvalidSearchQuery (f"Empty string after '{ search_key .name } :'" )
617+
618+ operator = self .handle_negation (negation , operator )
619+
620+ return self ._handle_basic_filter (search_key , operator , search_value )
621+
622+ def visit_text_in_filter (self , node , children ):
623+ (negation , search_key , _ , search_value ) = children
624+ operator = "IN"
625+ search_value = SearchValue (
626+ self .process_list (search_value [1 ], [(_ , _ , val ) for _ , _ , val in search_value [2 ]])
627+ )
620628
621629 operator = self .handle_negation (negation , operator )
622630
0 commit comments