diff --git a/awx/main/fields.py b/awx/main/fields.py index 3f1dd3db76..84e090b7de 100644 --- a/awx/main/fields.py +++ b/awx/main/fields.py @@ -401,19 +401,18 @@ class DynamicFilterField(models.TextField): contains_count += 1 ''' - Explicit quotes are kept up till this point. - They will be kept if there is ONLY ONE [] in the key search. - This is because django filter + postgres expect strings to be - quoted "\"hello_world\"". If, instead, there are many [] in a - filter key then we can remove the " and ". + Explicit quotes are kept until this point. + Note: we could have totally "ripped" them off earlier when we decided + what type to convert the token to. ''' - if contains_count != 1: - if type(v) is unicode and v.startswith('"') and v.endswith('"'): - v = v[1:-1] - if contains_count == 0: - assembled_v = v + if type(v) is unicode and v.startswith('"') and v.endswith('"'): + v = v[1:-1] - if contains_count > 1: + if contains_count == 0: + assembled_v = v + elif contains_count == 1: + assembled_v = [v] + elif contains_count > 1: if type(last_v) is list: last_v.append(v) if type(last_v) is dict: @@ -471,9 +470,13 @@ class DynamicFilterField(models.TextField): class BoolNot(object): - def __init__(self,t): - self.right = t[0][1] - self.result = ~self.right + def __init__(self, t): + self.right = t[0][1].result + + self.result = self.execute_logic(self.right) + + def execute_logic(self, right): + return ~right @classmethod @@ -503,7 +506,7 @@ class DynamicFilterField(models.TextField): grammar.setParseAction(cls.BoolOperand) boolExpr = infixNotation(grammar, [ - #("not", 1, opAssoc.RIGHT, cls.BoolNot), + ("not", 1, opAssoc.RIGHT, cls.BoolNot), ("and", 2, opAssoc.LEFT, cls.BoolAnd), ("or", 2, opAssoc.LEFT, cls.BoolOr), ]) diff --git a/awx/main/tests/unit/test_fields.py b/awx/main/tests/unit/test_fields.py index 699d049a8d..bca17f049a 100644 --- a/awx/main/tests/unit/test_fields.py +++ b/awx/main/tests/unit/test_fields.py @@ -48,19 +48,20 @@ class TestDynamicFilterFieldFilterStringToQ(): ('(a=b and c=d)', Q(**{u"a": u"b"}) & Q(**{u"c": u"d"})), ('a=b or c=d', Q(**{u"a": u"b"}) | Q(**{u"c": u"d"})), ('(a=b and c=d) or (e=f)', (Q(**{u"a": u"b"}) & Q(**{u"c": u"d"})) | (Q(**{u"e": u"f"}))), - ('(a=b) and (c=d or (e=f and (g=h or i=j))) or (y=z)', Q(**{u"a": u"b"}) & (Q(**{u"c": u"d"}) | (Q(**{u"e": u"f"}) & (Q(**{u"g": u"h"}) | Q(**{u"i": u"j"})))) | Q(**{u"y": u"z"})) + ('(a=b and not c=d) or not (e=f)', (Q(**{u"a": u"b"}) & ~Q(**{u"c": u"d"})) | (~Q(**{u"e": u"f"}))), + ('(a=b) and not (c=d or (e=f and (g=h or i=j))) or (y=z)', Q(**{u"a": u"b"}) & ~(Q(**{u"c": u"d"}) | (Q(**{u"e": u"f"}) & (Q(**{u"g": u"h"}) | Q(**{u"i": u"j"})))) | Q(**{u"y": u"z"})) ]) def test_boolean_parenthesis(self, filter_string, q_expected): q = DynamicFilterField.filter_string_to_q(filter_string) assert unicode(q) == unicode(q_expected) @pytest.mark.parametrize("filter_string,q_expected", [ - ('a__b__c[]=3', Q(**{u"a__b__c__contains": 3})), - ('a__b__c[]=3.14', Q(**{u"a__b__c__contains": 3.14})), - ('a__b__c[]=true', Q(**{u"a__b__c__contains": True})), - ('a__b__c[]=false', Q(**{u"a__b__c__contains": False})), - ('a__b__c[]="true"', Q(**{u"a__b__c__contains": u"\"true\""})), - ('a__b__c[]="hello world"', Q(**{u"a__b__c__contains": u"\"hello world\""})), + ('a__b__c[]=3', Q(**{u"a__b__c__contains": [3]})), + ('a__b__c[]=3.14', Q(**{u"a__b__c__contains": [3.14]})), + ('a__b__c[]=true', Q(**{u"a__b__c__contains": [True]})), + ('a__b__c[]=false', Q(**{u"a__b__c__contains": [False]})), + ('a__b__c[]="true"', Q(**{u"a__b__c__contains": [u"true"]})), + ('a__b__c[]="hello world"', Q(**{u"a__b__c__contains": [u"hello world"]})), ('a__b__c[]__d[]="foobar"', Q(**{u"a__b__c__contains": [{u"d": [u"foobar"]}]})), ('a__b__c[]__d="foobar"', Q(**{u"a__b__c__contains": [{u"d": u"foobar"}]})), ('a__b__c[]__d__e="foobar"', Q(**{u"a__b__c__contains": [{u"d": {u"e": u"foobar"}}]})), @@ -84,8 +85,6 @@ class TestDynamicFilterFieldFilterStringToQ(): q = DynamicFilterField.filter_string_to_q(filter_string) assert unicode(q) == unicode(q_expected) - - ''' #('"facts__quoted_val"="f\"oo"', 1), #('facts__facts__arr[]="foo"', 1),