Merge in latest DynamicFilter changes

This commit is contained in:
Wayne Witzel III 2017-05-01 13:38:39 -04:00
parent 1750e5bd2a
commit bdb13ecd71

View File

@ -13,7 +13,6 @@ from django.db import models
__all__ = ['DynamicFilter']
unicode_spaces = [unichr(c) for c in xrange(sys.maxunicode) if unichr(c).isspace()]
unicode_spaces_other = unicode_spaces + [u'(', u')', u'=', u'"']
@ -34,7 +33,7 @@ def string_to_type(t):
class DynamicFilter(object):
SEARCHABLE_RELATIONSHIP = 'ansible_facts'
class BoolOperand(object):
def __init__(self, t):
@ -44,6 +43,16 @@ class DynamicFilter(object):
kwargs[k] = v
self.result = models.Q(**kwargs)
def strip_quotes_traditional_logic(self, v):
if type(v) is unicode and v.startswith('"') and v.endswith('"'):
return v[1:-1]
return v
def strip_quotes_json_logic(self, v):
if type(v) is unicode and v.startswith('"') and v.endswith('"') and v != u'"null"':
return v[1:-1]
return v
'''
TODO: We should be able to express this in the grammar and let
pyparsing do the heavy lifting.
@ -53,66 +62,50 @@ class DynamicFilter(object):
relationship refered to to see if it's a jsonb type.
'''
def _json_path_to_contains(self, k, v):
pieces = k.split('__')
if not k.startswith(DynamicFilter.SEARCHABLE_RELATIONSHIP):
v = self.strip_quotes_traditional_logic(v)
return (k, v)
flag_first_arr_found = False
# Strip off leading relationship key
if k.startswith(DynamicFilter.SEARCHABLE_RELATIONSHIP + '__'):
strip_len = len(DynamicFilter.SEARCHABLE_RELATIONSHIP) + 2
else:
strip_len = len(DynamicFilter.SEARCHABLE_RELATIONSHIP)
k = k[strip_len:]
assembled_k = ''
assembled_v = v
pieces = k.split(u'__')
assembled_k = u'%s__contains' % (DynamicFilter.SEARCHABLE_RELATIONSHIP)
assembled_v = None
last_kv = None
last_v = None
last_kv = None
contains_count = 0
for i, piece in enumerate(pieces):
if flag_first_arr_found is False and piece.endswith('[]'):
assembled_k += u'%s__contains' % (piece[0:-2])
contains_count += 1
flag_first_arr_found = True
elif flag_first_arr_found is False and i == len(pieces) - 1:
assembled_k += u'%s' % piece
elif flag_first_arr_found is False:
assembled_k += u'%s__' % piece
elif flag_first_arr_found is True:
new_kv = dict()
if piece.endswith('[]'):
new_v = []
new_kv[piece[0:-2]] = new_v
else:
new_v = dict()
new_kv[piece] = new_v
new_kv = dict()
if piece.endswith(u'[]'):
new_v = []
new_kv[piece[0:-2]] = new_v
else:
new_v = dict()
new_kv[piece] = new_v
if last_kv is None:
assembled_v = new_kv
elif type(last_v) is list:
last_v.append(new_kv)
elif type(last_v) is dict:
last_kv[last_kv.keys()[0]] = new_kv
if last_v is None:
last_v = []
assembled_v = last_v
last_v = new_v
last_kv = new_kv
if type(last_v) is list:
last_v.append(new_kv)
elif type(last_v) is dict:
last_kv[last_kv.keys()[0]] = new_kv
v = self.strip_quotes_json_logic(v)
last_v = new_v
last_kv = new_kv
contains_count += 1
'''
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 type(v) is unicode and v.startswith('"') and v.endswith('"') and v != u'"null"':
v = v[1:-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:
last_kv[last_kv.keys()[0]] = v
if type(last_v) is list:
last_v.append(v)
elif type(last_v) is dict:
last_kv[last_kv.keys()[0]] = v
return (assembled_k, assembled_v)
@ -181,12 +174,12 @@ class DynamicFilter(object):
@classmethod
def query_from_string(cls, filter_string):
'''
TODO:
* handle values with " via: a.b.c.d="hello\"world"
* handle keys with " via: a.\"b.c="yeah"
* handle key with __ in it
'''
filter_string_raw = filter_string
filter_string = unicode(filter_string)
@ -207,6 +200,7 @@ class DynamicFilter(object):
try:
res = boolExpr.parseString('(' + filter_string + ')')
#except ParseException as e:
except Exception:
raise RuntimeError(u"Invalid query %s" % filter_string_raw)
@ -214,5 +208,3 @@ class DynamicFilter(object):
return res[0].result
raise RuntimeError("Parsing the filter_string %s went terribly wrong" % filter_string)