mirror of
https://github.com/ansible/awx.git
synced 2026-02-25 06:56:00 -03:30
Merge pull request #5990 from chrismeyersfsu/feature-jsonsearch
host filtering; handle unicode and python types
This commit is contained in:
@@ -323,9 +323,9 @@ unicode_spaces_other = unicode_spaces + [u'(', u')', u'=', u'"']
|
|||||||
|
|
||||||
|
|
||||||
def string_to_type(t):
|
def string_to_type(t):
|
||||||
if t == 'true':
|
if t == u'true':
|
||||||
return True
|
return True
|
||||||
elif t == 'false':
|
elif t == u'false':
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if re.search('^[-+]?[0-9]+$',t):
|
if re.search('^[-+]?[0-9]+$',t):
|
||||||
@@ -342,7 +342,6 @@ class DynamicFilterField(models.TextField):
|
|||||||
|
|
||||||
class BoolOperand(object):
|
class BoolOperand(object):
|
||||||
def __init__(self, t):
|
def __init__(self, t):
|
||||||
#print("Got t %s" % t)
|
|
||||||
kwargs = dict()
|
kwargs = dict()
|
||||||
k, v = self._extract_key_value(t)
|
k, v = self._extract_key_value(t)
|
||||||
k, v = self._json_path_to_contains(k, v)
|
k, v = self._json_path_to_contains(k, v)
|
||||||
@@ -371,13 +370,13 @@ class DynamicFilterField(models.TextField):
|
|||||||
contains_count = 0
|
contains_count = 0
|
||||||
for i, piece in enumerate(pieces):
|
for i, piece in enumerate(pieces):
|
||||||
if flag_first_arr_found is False and piece.endswith('[]'):
|
if flag_first_arr_found is False and piece.endswith('[]'):
|
||||||
assembled_k += '%s__contains' % (piece[0:-2])
|
assembled_k += u'%s__contains' % (piece[0:-2])
|
||||||
contains_count += 1
|
contains_count += 1
|
||||||
flag_first_arr_found = True
|
flag_first_arr_found = True
|
||||||
elif flag_first_arr_found is False and i == len(pieces) - 1:
|
elif flag_first_arr_found is False and i == len(pieces) - 1:
|
||||||
assembled_k += '%s' % piece
|
assembled_k += u'%s' % piece
|
||||||
elif flag_first_arr_found is False:
|
elif flag_first_arr_found is False:
|
||||||
assembled_k += '%s__' % piece
|
assembled_k += u'%s__' % piece
|
||||||
elif flag_first_arr_found is True:
|
elif flag_first_arr_found is True:
|
||||||
new_kv = dict()
|
new_kv = dict()
|
||||||
if piece.endswith('[]'):
|
if piece.endswith('[]'):
|
||||||
@@ -401,9 +400,20 @@ class DynamicFilterField(models.TextField):
|
|||||||
last_kv = new_kv
|
last_kv = new_kv
|
||||||
contains_count += 1
|
contains_count += 1
|
||||||
|
|
||||||
if contains_count == 1 and isinstance(assembled_v, basestring):
|
'''
|
||||||
assembled_v = '"' + assembled_v + '"'
|
Explicit quotes are kept up till this point.
|
||||||
elif contains_count > 1:
|
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 ".
|
||||||
|
'''
|
||||||
|
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 contains_count > 1:
|
||||||
if type(last_v) is list:
|
if type(last_v) is list:
|
||||||
last_v.append(v)
|
last_v.append(v)
|
||||||
if type(last_v) is dict:
|
if type(last_v) is dict:
|
||||||
@@ -430,10 +440,11 @@ class DynamicFilterField(models.TextField):
|
|||||||
# value
|
# value
|
||||||
# ="something"
|
# ="something"
|
||||||
if t_len > (v_offset + 2) and t[v_offset] == "\"" and t[v_offset + 2] == "\"":
|
if t_len > (v_offset + 2) and t[v_offset] == "\"" and t[v_offset + 2] == "\"":
|
||||||
v = t[v_offset + 1]
|
v = u'"' + unicode(t[v_offset + 1]) + u'"'
|
||||||
|
#v = t[v_offset + 1]
|
||||||
# empty ""
|
# empty ""
|
||||||
elif t_len > (v_offset + 1):
|
elif t_len > (v_offset + 1):
|
||||||
v = ""
|
v = u""
|
||||||
# no ""
|
# no ""
|
||||||
else:
|
else:
|
||||||
v = string_to_type(t[v_offset])
|
v = string_to_type(t[v_offset])
|
||||||
@@ -481,6 +492,8 @@ class DynamicFilterField(models.TextField):
|
|||||||
* handle optional value quoted: a.b.c=""
|
* handle optional value quoted: a.b.c=""
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
filter_string = unicode(filter_string)
|
||||||
|
|
||||||
atom = CharsNotIn(unicode_spaces_other)
|
atom = CharsNotIn(unicode_spaces_other)
|
||||||
atom_inside_quotes = CharsNotIn(u'"')
|
atom_inside_quotes = CharsNotIn(u'"')
|
||||||
atom_quoted = Literal('"') + Optional(atom_inside_quotes) + Literal('"')
|
atom_quoted = Literal('"') + Optional(atom_inside_quotes) + Literal('"')
|
||||||
|
|||||||
@@ -12,20 +12,20 @@ from django.db.models import Q
|
|||||||
|
|
||||||
class TestDynamicFilterFieldFilterStringToQ():
|
class TestDynamicFilterFieldFilterStringToQ():
|
||||||
@pytest.mark.parametrize("filter_string,q_expected", [
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
('facts__facts__blank=""', Q(facts__facts__blank="")),
|
('facts__facts__blank=""', Q(**{u"facts__facts__blank": u""})),
|
||||||
('"facts__facts__ space "="f"', Q(**{ "facts__facts__ space ": "f"})),
|
('"facts__facts__ space "="f"', Q(**{u"facts__facts__ space ": u"f"})),
|
||||||
('"facts__facts__ e "=no_quotes_here', Q(**{ "facts__facts__ e ": "no_quotes_here"})),
|
('"facts__facts__ e "=no_quotes_here', Q(**{u"facts__facts__ e ": u"no_quotes_here"})),
|
||||||
('a__b__c=3', Q(**{ "a__b__c": 3})),
|
('a__b__c=3', Q(**{u"a__b__c": 3})),
|
||||||
('a__b__c=3.14', Q(**{ "a__b__c": 3.14})),
|
('a__b__c=3.14', Q(**{u"a__b__c": 3.14})),
|
||||||
('a__b__c=true', Q(**{ "a__b__c": True})),
|
('a__b__c=true', Q(**{u"a__b__c": True})),
|
||||||
('a__b__c=false', Q(**{ "a__b__c": False})),
|
('a__b__c=false', Q(**{u"a__b__c": False})),
|
||||||
('a__b__c="true"', Q(**{ "a__b__c": "true"})),
|
('a__b__c="true"', Q(**{u"a__b__c": u"true"})),
|
||||||
#('"a__b\"__c"="true"', Q(**{ "a__b\"__c": "true"})),
|
#('"a__b\"__c"="true"', Q(**{u"a__b\"__c": "true"})),
|
||||||
#('a__b\"__c="true"', Q(**{ "a__b\"__c": "true"})),
|
#('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
|
||||||
])
|
])
|
||||||
def test_query_generated(self, filter_string, q_expected):
|
def test_query_generated(self, filter_string, q_expected):
|
||||||
q = DynamicFilterField.filter_string_to_q(filter_string)
|
q = DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
assert str(q) == str(q_expected)
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
@pytest.mark.parametrize("filter_string", [
|
@pytest.mark.parametrize("filter_string", [
|
||||||
'facts__facts__blank='
|
'facts__facts__blank='
|
||||||
@@ -40,39 +40,50 @@ class TestDynamicFilterFieldFilterStringToQ():
|
|||||||
])
|
])
|
||||||
def test_unicode(self, filter_string, q_expected):
|
def test_unicode(self, filter_string, q_expected):
|
||||||
q = DynamicFilterField.filter_string_to_q(filter_string)
|
q = DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
assert str(q) == str(q_expected)
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
@pytest.mark.parametrize("filter_string,q_expected", [
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
('(a=b)', Q(**{"a": "b"})),
|
('(a=b)', Q(**{u"a": u"b"})),
|
||||||
('a=b and c=d', Q(**{"a": "b"}) & Q(**{"c": "d"})),
|
('a=b and c=d', Q(**{u"a": u"b"}) & Q(**{u"c": u"d"})),
|
||||||
('(a=b and c=d)', Q(**{"a": "b"}) & Q(**{"c": "d"})),
|
('(a=b and c=d)', Q(**{u"a": u"b"}) & Q(**{u"c": u"d"})),
|
||||||
('a=b or c=d', Q(**{"a": "b"}) | Q(**{"c": "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(**{"a": "b"}) & Q(**{"c": "d"})) | (Q(**{"e": "f"}))),
|
('(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(**{"a": "b"}) & (Q(**{"c": "d"}) | (Q(**{"e": "f"}) & (Q(**{"g": "h"}) | Q(**{"i": "j"})))) | Q(**{"y": "z"}))
|
('(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"}))
|
||||||
])
|
])
|
||||||
def test_boolean_parenthesis(self, filter_string, q_expected):
|
def test_boolean_parenthesis(self, filter_string, q_expected):
|
||||||
q = DynamicFilterField.filter_string_to_q(filter_string)
|
q = DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
assert str(q) == str(q_expected)
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
@pytest.mark.parametrize("filter_string,q_expected", [
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
('a__b__c[]=3', Q(**{ "a__b__c__contains": 3})),
|
('a__b__c[]=3', Q(**{u"a__b__c__contains": 3})),
|
||||||
('a__b__c[]=3.14', Q(**{ "a__b__c__contains": 3.14})),
|
('a__b__c[]=3.14', Q(**{u"a__b__c__contains": 3.14})),
|
||||||
('a__b__c[]=true', Q(**{ "a__b__c__contains": True})),
|
('a__b__c[]=true', Q(**{u"a__b__c__contains": True})),
|
||||||
('a__b__c[]=false', Q(**{ "a__b__c__contains": False})),
|
('a__b__c[]=false', Q(**{u"a__b__c__contains": False})),
|
||||||
('a__b__c[]="true"', Q(**{ "a__b__c__contains": "\"true\""})),
|
('a__b__c[]="true"', Q(**{u"a__b__c__contains": u"\"true\""})),
|
||||||
('a__b__c[]="hello world"', Q(**{ "a__b__c__contains": "\"hello world\""})),
|
('a__b__c[]="hello world"', Q(**{u"a__b__c__contains": u"\"hello world\""})),
|
||||||
('a__b__c[]__d[]="foobar"', Q(**{ "a__b__c__contains": [{"d": ["foobar"]}]})),
|
('a__b__c[]__d[]="foobar"', Q(**{u"a__b__c__contains": [{u"d": [u"foobar"]}]})),
|
||||||
('a__b__c[]__d="foobar"', Q(**{ "a__b__c__contains": [{"d": "foobar"}]})),
|
('a__b__c[]__d="foobar"', Q(**{u"a__b__c__contains": [{u"d": u"foobar"}]})),
|
||||||
('a__b__c[]__d__e="foobar"', Q(**{ "a__b__c__contains": [{"d": {"e": "foobar"}}]})),
|
('a__b__c[]__d__e="foobar"', Q(**{u"a__b__c__contains": [{u"d": {u"e": u"foobar"}}]})),
|
||||||
('a__b__c[]__d__e[]="foobar"', Q(**{ "a__b__c__contains": [{"d": {"e": ["foobar"]}}]})),
|
('a__b__c[]__d__e[]="foobar"', Q(**{u"a__b__c__contains": [{u"d": {u"e": [u"foobar"]}}]})),
|
||||||
('a__b__c[]__d__e__f[]="foobar"', Q(**{ "a__b__c__contains": [{"d": {"e": {"f": ["foobar"]}}}]})),
|
('a__b__c[]__d__e__f[]="foobar"', Q(**{u"a__b__c__contains": [{u"d": {u"e": {u"f": [u"foobar"]}}}]})),
|
||||||
('(a__b__c[]__d__e__f[]="foobar") and (a__b__c[]__d__e[]="foobar")', Q(**{ "a__b__c__contains": [{"d": {"e": {"f": ["foobar"]}}}]}) & Q(**{ "a__b__c__contains": [{"d": {"e": ["foobar"]}}]})),
|
('(a__b__c[]__d__e__f[]="foobar") and (a__b__c[]__d__e[]="foobar")', Q(**{ u"a__b__c__contains": [{u"d": {u"e": {u"f": [u"foobar"]}}}]}) & Q(**{u"a__b__c__contains": [{u"d": {u"e": [u"foobar"]}}]})),
|
||||||
#('"a__b\"__c"="true"', Q(**{ "a__b\"__c": "true"})),
|
#('"a__b\"__c"="true"', Q(**{u"a__b\"__c": "true"})),
|
||||||
#('a__b\"__c="true"', Q(**{ "a__b\"__c": "true"})),
|
#('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
|
||||||
])
|
])
|
||||||
def test_contains_query_generated(self, filter_string, q_expected):
|
def test_contains_query_generated(self, filter_string, q_expected):
|
||||||
q = DynamicFilterField.filter_string_to_q(filter_string)
|
q = DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
assert str(q) == str(q_expected)
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
|
#('a__b__c[]="true"', Q(**{u"a__b__c__contains": u"\"true\""})),
|
||||||
|
('a__b__c="true"', Q(**{u"a__b__c": u"true"})),
|
||||||
|
#('"a__b\"__c"="true"', Q(**{u"a__b\"__c": "true"})),
|
||||||
|
#('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
|
||||||
|
])
|
||||||
|
def test_contains_query_generated_unicode(self, filter_string, q_expected):
|
||||||
|
q = DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|||||||
Reference in New Issue
Block a user