示例#1
0
    def visit_aggregate_duration_filter(self, node, children):
        (negation, search_key, _, operator, search_value) = children
        operator = handle_negation(negation, operator)

        try:
            # Even if the search value matches duration format, only act as
            # duration for certain columns
            function = resolve_field(search_key.name, self.params, functions_acl=FUNCTIONS.keys())

            is_duration_key = False
            if function.aggregate is not None:
                args = function.aggregate[1]
                if isinstance(args, list):
                    is_duration_key = all(self.is_duration_key(arg) for arg in args)
                else:
                    is_duration_key = self.is_duration_key(args)

            if is_duration_key:
                aggregate_value = parse_duration(*search_value)
            else:
                # Duration overlaps with numeric values with `m` (million vs
                # minutes). So we fall through to numeric if it's not a
                # duration key
                #
                # TODO(epurkhiser): Should we validate that the field is
                # numeric and do some other fallback if it's not?
                aggregate_value = parse_numeric_value(*search_value)
        except ValueError:
            raise InvalidSearchQuery(f"Invalid aggregate query condition: {search_key}")
        except InvalidQuery as exc:
            raise InvalidSearchQuery(str(exc))

        return AggregateFilter(search_key, operator, SearchValue(aggregate_value))
示例#2
0
    def visit_aggregate_filter(self, node, children):
        (negation, search_key, _, operator, search_value) = children
        operator = self.handle_negation(negation, operator)
        search_value = search_value[0] if not isinstance(search_value, RegexNode) else search_value

        try:
            aggregate_value = None
            if search_value.expr_name in ["duration_format", "percentage_format"]:
                # Even if the search value matches duration format, only act as duration for certain columns
                function = resolve_field(
                    search_key.name, self.params, functions_acl=FUNCTIONS.keys()
                )
                if function.aggregate is not None:
                    if search_value.expr_name == "percentage_format" and self.is_percentage_key(
                        function.aggregate[0]
                    ):
                        aggregate_value = parse_percentage(*search_value.match.groups())
                    # Extract column and function name out so we can check if we should parse as duration
                    elif search_value.expr_name == "duration_format" and self.is_duration_key(
                        function.aggregate[1]
                    ):
                        aggregate_value = parse_duration(*search_value.match.groups())

            if aggregate_value is None:
                aggregate_value = parse_numeric_value(*search_value.match.groups())
        except ValueError:
            raise InvalidSearchQuery(f"Invalid aggregate query condition: {search_key}")
        except InvalidQuery as exc:
            raise InvalidSearchQuery(str(exc))
        return AggregateFilter(search_key, operator, SearchValue(aggregate_value))
示例#3
0
    def visit_aggregate_numeric_filter(self, node, children):
        (negation, search_key, _, operator, search_value) = children
        operator = handle_negation(negation, operator)

        try:
            aggregate_value = parse_numeric_value(*search_value)
        except InvalidQuery as exc:
            raise InvalidSearchQuery(str(exc))

        return AggregateFilter(search_key, operator, SearchValue(aggregate_value))
示例#4
0
    def _handle_numeric_filter(self, search_key, operator, search_value):
        operator = get_operator_value(operator)

        if self.is_numeric_key(search_key.name):
            try:
                search_value = SearchValue(parse_numeric_value(*search_value))
            except InvalidQuery as exc:
                raise InvalidSearchQuery(str(exc))
            return SearchFilter(search_key, operator, search_value)

        return self._handle_text_filter(search_key, operator, SearchValue("".join(search_value)))
示例#5
0
    def visit_numeric_in_filter(self, node, children):
        (negation, search_key, _, search_value) = children
        operator = handle_negation(negation, "IN")

        if self.is_numeric_key(search_key.name):
            try:
                search_value = SearchValue([parse_numeric_value(*val) for val in search_value])
            except InvalidQuery as exc:
                raise InvalidSearchQuery(str(exc))
            return SearchFilter(search_key, operator, search_value)

        search_value = SearchValue(["".join(value) for value in search_value])
        return self._handle_basic_filter(search_key, operator, search_value)
示例#6
0
    def visit_numeric_filter(self, node, children):
        (search_key, _, (value, )) = children
        operator = value[0]
        if isinstance(operator, Node):
            if isinstance(operator.expr, Optional):
                operator = "="
            else:
                operator = operator.text
        else:
            operator = operator[0]

        if operator == "[":
            operator = "IN"
            search_value = self.process_list(value[1], value[2])
        else:
            search_value = value[1]

        if self.is_numeric_key(search_key.name):
            try:
                search_value = SearchValue([
                    parse_numeric_value(*val.match.groups())
                    for val in search_value
                ] if operator == "IN" else parse_numeric_value(
                    *search_value.match.groups()))
            except InvalidQuery as exc:
                raise InvalidSearchQuery(str(exc))
            return SearchFilter(search_key, operator, search_value)
        else:
            if operator != "IN":
                search_value = search_value.text
            else:
                search_value = [v.text for v in search_value]
            search_value = SearchValue(operator +
                                       search_value if operator not in (
                                           "=", "IN") else search_value)
            operator = "=" if operator not in ("=", "IN") else operator
            return self._handle_basic_filter(search_key, operator,
                                             search_value)
示例#7
0
    def _handle_numeric_filter(self, search_key, operator, search_value):
        if isinstance(operator, Node):
            operator = "=" if isinstance(operator.expr, Optional) else operator.text
        else:
            operator = operator[0]

        if self.is_numeric_key(search_key.name):
            try:
                search_value = SearchValue(parse_numeric_value(*search_value))
            except InvalidQuery as exc:
                raise InvalidSearchQuery(str(exc))
            return SearchFilter(search_key, operator, search_value)

        return self._handle_text_filter(search_key, operator, SearchValue("".join(search_value)))
示例#8
0
    def visit_numeric_in_filter(self, node, children):
        (search_key, _, value) = children
        operator = "IN"
        search_value = self.process_list(value[1], value[2])

        if self.is_numeric_key(search_key.name):
            try:
                search_value = SearchValue([
                    parse_numeric_value(*val.match.groups())
                    for val in search_value
                ])
            except InvalidQuery as exc:
                raise InvalidSearchQuery(str(exc))
            return SearchFilter(search_key, operator, search_value)
        else:
            search_value = SearchValue([v.text for v in search_value])
            return self._handle_basic_filter(search_key, operator,
                                             search_value)
示例#9
0
    def visit_numeric_filter(self, node, children):
        (search_key, _, operator, search_value) = children
        if isinstance(operator, Node):
            operator = "=" if isinstance(operator.expr,
                                         Optional) else operator.text
        else:
            operator = operator[0]

        if self.is_numeric_key(search_key.name):
            try:
                search_value = SearchValue(
                    parse_numeric_value(*search_value.match.groups()))
            except InvalidQuery as exc:
                raise InvalidSearchQuery(str(exc))
            return SearchFilter(search_key, operator, search_value)
        else:
            search_value = search_value.text
            search_value = SearchValue(
                operator + search_value if operator != "=" else search_value)
            return self._handle_basic_filter(search_key, "=", search_value)
示例#10
0
    def node_visitor(token):
        if token["type"] == "spaces":
            return None

        if token["type"] == "filter":
            # Filters with an invalid reason raises to signal to the test
            # runner that we should expect this exception
            if token.get("invalid"):
                raise InvalidSearchQuery(token["invalid"]["reason"])

            # Transform the operator to match for list values
            if token["value"]["type"] in ["valueTextList", "valueNumberList"]:
                operator = "NOT IN" if token["negated"] else "IN"
            else:
                # Negate the operator if the filter is negated to match
                operator = token["operator"] or "="
                operator = f"!{operator}" if token["negated"] else operator

            key = node_visitor(token["key"])
            value = node_visitor(token["value"])

            if token["filter"] == "boolean" and token["negated"]:
                operator = "="
                value = SearchValue(raw_value=1 if value.raw_value == 0 else 0)

            return SearchFilter(key, operator, value)

        if token["type"] == "keySimple":
            return SearchKey(name=token["value"])

        if token["type"] == "keyExplicitTag":
            return SearchKey(name=f"tags[{token['key']['value']}]")

        if token["type"] == "keyAggregate":
            name = node_visitor(token["name"]).name
            # Consistent join aggregate function parameters
            args = ", ".join(arg["value"]["value"]
                             for arg in token["args"]["args"])
            return AggregateKey(name=f"{name}({args})")

        if token["type"] == "valueText":
            # Noramlize values by removing the escaped quotes
            value = token["value"].replace('\\"', '"')
            return SearchValue(raw_value=value)

        if token["type"] == "valueNumber":
            return SearchValue(
                raw_value=parse_numeric_value(token["value"], token["unit"]))

        if token["type"] == "valueTextList":
            return SearchValue(
                raw_value=[item["value"]["value"] for item in token["items"]])

        if token["type"] == "valueNumberList":
            return SearchValue(raw_value=[
                item["value"]["rawValue"] for item in token["items"]
            ])

        if token["type"] == "valueIso8601Date":
            return SearchValue(raw_value=parse_datetime_string(token["value"]))

        if token["type"] == "valueDuration":
            return SearchValue(
                raw_value=parse_duration(token["value"], token["unit"]))

        if token["type"] == "valueRelativeDate":
            return SearchValue(
                raw_value=parse_duration(token["value"], token["unit"]))

        if token["type"] == "valueBoolean":
            return SearchValue(raw_value=int(token["value"]))

        if token["type"] == "freeText":
            if token["quoted"]:
                # Normalize quotes
                value = token["value"].replace('\\"', '"')
            else:
                # Normalize spacing
                value = token["value"].strip(" ")

            if value == "":
                return None

            return SearchFilter(
                key=SearchKey(name="message"),
                operator="=",
                value=SearchValue(raw_value=value),
            )