def dataset_query(request, app, data): try: if 'filters' not in data or not isinstance(data['filters'], dict): raise SuspiciousOperation('Filters must be a dictionary') filters = {} for attr, filter_obj in data['filters'].items(): filters[attr] = BaseFilter.deserialize(filter_obj) # Empty list means query all attributes to the older versions of # the adminapi. if not data.get('restrict'): restrict = None else: restrict = data['restrict'] order_by = data.get('order_by') return { 'status': 'success', 'result': execute_query(filters, restrict, order_by), } except (FilterValueError, ValidationError) as error: return { 'status': 'error', 'type': 'ValueError', 'message': str(error), }
def __init__(self, filters=None, restrict=['hostname'], order_by=None): if filters is None: self._filters = None self._restrict = None self._order_by = None self._results = [] return self._filters = { a: f if isinstance(f, BaseFilter) else BaseFilter(f) for a, f in filters.items() } self._restrict = restrict self._order_by = order_by self._results = None
def parse_query(term, hostname=None): # NOQA: C901 parsed_args = parse_function_string(term, strict=True) if not parsed_args: return {} # If first token is not a key, we assume that a hostname is meant token, value = parsed_args[0] if token != 'key': if hostname: # We already parsed a hostname, so we don't expect another one raise DatatypeError("Garbled hostname: {0}".format(hostname)) term_parts = term.split(None, 1) if len(term_parts) == 2: hostname_part, remaining_part = term_parts query_args = parse_query(remaining_part, hostname_part) else: hostname_part = term query_args = {} if any(x in hostname_part for x in _trigger_re_chars): hostname = Regexp(hostname_part) else: hostname = BaseFilter(hostname_part) if 'hostname' in query_args: query_args['hostname'] = Any(query_args['hostname'], hostname) else: query_args['hostname'] = hostname return query_args # Otherwise just parse all attributes query_args = {} stack = [] call_depth = 0 for arg in parsed_args: token, value = arg if token == 'key': if stack: query_args[stack[0][1]] = stack[1][1] stack = [] stack.append(arg) elif token == 'func': # Do not allow functions without preceding key # if they are on top level (e.g. call_depth = 0) if not stack or (call_depth == 0 and stack[-1][0] != 'key'): raise DatatypeError( 'Invalid term: top level function requires ' 'preceding attribute' ) call_depth += 1 stack.append(arg) elif token == 'endfunc': call_depth -= 1 fn_args = [] while True: s_token, s_value = stack.pop() if s_token == 'func': break else: fn_args.append(s_value) fn_args.reverse() for filter_class in filter_classes: if filter_class.__name__.lower() == s_value.lower(): try: instance = filter_class(*fn_args) except TypeError: raise DatatypeError( 'Invalid function args ' + filter_class.__name__ ) break else: raise DatatypeError('Invalid function ' + s_value) stack.append(('instance', instance)) elif token == 'literal': # Do not allow literals without key or function context if not stack or (call_depth == 0 and stack[-1][0] != 'key'): raise DatatypeError( 'Invalid term: Top level literals are not ' 'allowed when attributes are used' ) if call_depth == 0: stack.append(('literal', BaseFilter(value))) else: stack.append(('literal', value)) if stack and stack[0][0] == 'key': if len(stack) != 2: raise DatatypeError( 'Invalid term: Attribute requires one argument' ) query_args[stack[0][1]] = stack[1][1] return query_args