示例#1
0
def parse_value_operation(operation: str) -> "QueryOpSpec":
    """Parse value operations.

    A value operation can be one of the following:

     * single value: tag1:foo
     * negation single value: tag1:~foo
     * multiple values: tag1:foo|bar|moo
     * negation multiple values: tag1:~foo|bar|moo

    This parser does not allow `..`, '>', '<', '>=', and '<='.
    """
    _operation = operation.strip()
    if not _operation:
        raise PQLException("Operation is not valid: {}".format(operation))
    # Check range not allowed
    if ".." in _operation:
        raise PQLException(
            "`..` is not allowed for value operations. "
            "Operation: {}".format(operation)
        )

    # Check negation
    negation, _operation = parse_negation_operation(_operation)

    # Check comparison not allowed
    op, _operation = parse_comparison_operation(_operation)
    if op:
        raise PQLException(
            "`{}` is not allowed for value operations, "
            "Operation: {}".format(op, operation)
        )

    # Check in operator
    if "|" in _operation:
        op = "|"
        params = _operation.split("|")
        params = [param.strip() for param in params if param.strip()]
        if len(params) <= 1:
            raise PQLException(
                "`{}` is not allowed for value operations, "
                "Operation: {}".format(op, operation)
            )
        return QueryOpSpec(op, negation, params)

    if not _operation:
        raise PQLException(
            "Expression is not valid, it must be formatted as "
            "name:operation, "
            "Operation: {}".format(operation)
        )
    # Now the operation must be an equality param param
    return QueryOpSpec("=", negation, _operation)
示例#2
0
def parse_datetime_operation(operation: str) -> "QueryOpSpec":
    """Parse datetime operations.

    A datetime operation can be one of the following:

     * single value: start_date:2014-10-10, start_date:>2014-10-10, start_date:>=2014-10-10
     * negation single value: start_date:~2014-10-10
     * interval: start_date:2010-10-10 10:10 .. 2012-10-10
     * negation interval: start_date:~2010-10-10 10:10 .. 2012-10-10

    This parser does not allow `|`
    """
    _operation = operation.strip()
    if not _operation:
        raise PQLException("Operation is not valid: {}".format(operation))
    # Check not allowed ops
    if "|" in _operation:
        raise PQLException(
            "`|` is not allowed for datetime operations. "
            "Operation: {}".format(operation)
        )

    # Check negation
    negation, _operation = parse_negation_operation(_operation)

    # Check range operator
    if ".." in _operation:
        op = ".."
        params = _operation.split("..")
        params = [param.strip() for param in params if param]
        if len(params) != 2:
            raise PQLException(
                "Expression is not valid, ranges requires only 2 params, "
                "Operation: {}".format(operation)
            )
        return QueryOpSpec(op, negation, params)

    # Check comparison operators
    op, _operation = parse_comparison_operation(_operation)
    if not op:
        # Now the operation must be an equality param param
        op = "="

    if not _operation:
        raise PQLException(
            "Expression is not valid, it must be formatted as "
            "name:operation, "
            "Operation: {}".format(operation)
        )
    return QueryOpSpec(op, negation, _operation)
示例#3
0
    def __init__(self, op: str, negation: bool = False) -> None:
        if op not in self.VALUES and op not in self.REPRESENTATIONS:
            raise PQLException("Received an invalid operator `{}`, "
                               "possible values `{}` or `{}`.".format(
                                   op, self.VALUES, self.REPRESENTATIONS))

        self.operator = self._get_operator(op, negation)
示例#4
0
def split_query(query: str) -> List[str]:
    """Split a query into different expressions.

    Example:
        name:bla, foo:<=1
    """
    try:
        _query = query.strip()
    except (ValueError, AttributeError):
        raise PQLException("query is not valid, received instead {}".format(query))

    expressions = _query.split(",")
    expressions = [exp.strip() for exp in expressions if exp.strip()]
    if not expressions:
        raise PQLException("Query is not valid: {}".format(query))

    return expressions
示例#5
0
def parse_scalar_operation(operation: str) -> "QueryOpSpec":
    """Parse scalar operations.

    A scalar operation can be one of the following:

     * single value: start_date:12, metric1:>0.9, metric1:>=-0.12
     * negation single value: metric1:~1112, metric1:~<1112 equivalent to metric1:>=1112

    This parser does not allow `|` and `..`.
    """
    _operation = operation.strip()
    if not _operation:
        raise PQLException("Operation is not valid: {}".format(operation))
    # Check not allowed ops
    if "|" in _operation:
        raise PQLException(
            "`|` is not allowed for scalar operations. "
            "Operation: {}".format(operation)
        )
    if ".." in _operation:
        raise PQLException(
            "`..` is not allowed for scalar operations. "
            "Operation: {}".format(operation)
        )

    # Check negation
    negation, _operation = parse_negation_operation(_operation)

    # Check comparison operators
    op, _operation = parse_comparison_operation(_operation)
    if not op:
        # Now the operation must be an equality param param
        op = "="

    # Check that params are scalar (int, float)
    try:
        _operation = int(_operation)
    except (ValueError, TypeError):
        try:
            _operation = float(_operation)
        except (ValueError, TypeError):
            raise PQLException(
                "Scalar operation requires int or float params, "
                "receive {}.".format(operation)
            )
    return QueryOpSpec(op, negation, _operation)
示例#6
0
    def _range_operator(name: str, params: Any, query_backend: Any,
                        timezone: str) -> Any:
        assert len(params) == 2
        try:
            start_date = DateTimeFormatter.extract(params[0], timezone)
            end_date = DateTimeFormatter.extract(params[1], timezone)
        except PolyaxonDateTimeFormatterException as e:
            raise PQLException(e)

        name = "{}__range".format(name)
        return query_backend(**{name: (start_date, end_date)})
示例#7
0
def parse_negation_operation(operation: str) -> Tuple[bool, str]:
    """Parse the negation modifier in an operation."""
    _operation = operation.strip()
    if not _operation:
        raise PQLException("Operation is not valid: {}".format(operation))
    negation = False
    if _operation[0] == "~":
        negation = True
        _operation = _operation[1:]

    return negation, _operation.strip()
示例#8
0
 def tokenize(cls, query_spec: str) -> Dict[str, Iterable]:
     tokenized_query = tokenize_query(query_spec)
     results = {}
     for key in tokenized_query.keys():
         field, _ = parse_field(key)
         if field and (field not in cls.PARSERS_BY_FIELD
                       or field not in cls.CONDITIONS_BY_FIELD):
             raise PQLException(
                 "key `{}` is not supported by query manager `{}`.".format(
                     key, cls.NAME))
         cls.trans_field(key, tokenized_query, results)
     return results
示例#9
0
def parse_nil_operation(operation: str) -> Optional["QueryOpSpec"]:
    """Parse the nil operator in an operation."""
    _operation = operation.strip()
    if not _operation:
        raise PQLException("Operation is not valid: {}".format(operation))

    # Check negation
    negation, _operation = parse_negation_operation(_operation)

    # Check nil
    if _operation == "nil":
        return QueryOpSpec("nil", negation, None)

    return None
示例#10
0
def parse_comparison_operation(operation: str) -> Tuple[Optional[str], str]:
    """Parse the comparison operator in an operation."""
    _operation = operation.strip()
    if not _operation:
        raise PQLException("Operation is not valid: {}".format(operation))
    # Check inclusion comparison
    if _operation[:2] in ("<=", "=<"):
        return "<=", _operation[2:].strip()

    if _operation[:2] in (">=", "=>"):
        return ">=", _operation[2:].strip()

    # Non inclusive
    if _operation[:1] in (">", "<"):
        return _operation[:1], _operation[1:].strip()

    return None, _operation
示例#11
0
def parse_field(field: str) -> Tuple[str, Optional[str]]:
    """Parses fields with underscores, and return field and suffix.

    Example:
        foo => foo, None
        metrics.foo => metric, foo
    """
    _field = field.split(".")
    _field = [f.strip() for f in _field]
    if len(_field) == 1 and _field[0]:
        return _field[0], None
    elif len(_field) == 2 and _field[0] and _field[1]:
        return _field[0], _field[1]
    raise PQLException("Query field must be either a single value,"
                       "possibly with single underscores, "
                       "or a prefix double underscore field. "
                       "Received `{}`".format(field))
示例#12
0
def parse_expression(expression: str) -> Tuple[str, str]:
    """Base parsing for expressions.

    Every expression must follow a basic format:
        `name:[modifier|operator]operation[*[operator]operation]`

    So this parser just split the expression into: field name, operation.
    """
    try:
        _expression = expression.strip()
        name, operation = _expression.split(":")
        name = name.strip()
        operation = operation.strip()
        if not name or not operation:
            raise ValueError
    except (ValueError, AttributeError):
        raise PQLException("Expression is not valid, it must be formatted as "
                           "name:operation, "
                           "Expression: {}".format(expression))
    return name, operation
示例#13
0
    def apply(cls, query_spec: str, queryset: Any) -> Any:
        built_query = cls.handle_query(query_spec=query_spec)
        operators = []
        for key, cond_specs in built_query.items():
            key = cls.proxy_field(key)
            for cond_spec in cond_specs:
                try:
                    operator = cond_spec.cond.apply_operator(
                        name=key,
                        params=cond_spec.params,
                        query_backend=cls.QUERY_BACKEND,
                        timezone=cls.TIMEZONE,
                    )
                except Exception as e:
                    raise PQLException(
                        "Error applying operator for key `%s` by the query manager `%s`. "
                        "%s" % (key, cls.NAME, e))
                operators.append(operator)

        return queryset.filter(*operators)
示例#14
0
def parse_search_operation(operation: str) -> "QueryOpSpec":
    """Parse search operations.

    A search operation can be one of the following:

     * single value: tag1:foo
     * negation single value: tag1:~foo
     * multiple values: tag1:foo|bar|moo
     * negation multiple values: tag1:~foo|bar|moo
     * like value: name:%foo or name:foo% or name:%foo%
     * not like value: name:~%foo or name:~foo% or name:~%foo%

    This parser does not allow `..`, '>', '<', '>=', and '<='.
    """
    _operation = operation.strip()
    if not _operation:
        raise PQLException("Operation is not valid: {}".format(operation))
    # Check range not allowed
    if ".." in _operation:
        raise PQLException("`..` is not allowed for value operations. "
                           "Operation: {}".format(operation))

    # Check negation
    negation, _operation = parse_negation_operation(_operation)

    # Check comparison not allowed
    op, _operation = parse_comparison_operation(_operation)
    if op:
        raise PQLException("`{}` is not allowed for value operations, "
                           "Operation: {}".format(op, operation))

    # Check in operator
    if "|" in _operation:
        op = "|"
        params = _operation.split("|")
        params = [param.strip() for param in params if param.strip()]
        if len(params) <= 1:
            raise PQLException("`{}` is not allowed for value operations, "
                               "Operation: {}".format(op, operation))
        return QueryOpSpec(op, negation, params)

    # Check like operator
    start_like = _operation.endswith("%")
    end_like = _operation.startswith("%")
    if start_like and end_like:
        op = "%%"
        params = _operation.split("%")
        params = [param.strip() for param in params if param.strip()]
        if len(params) != 1:
            raise PQLException("`{}` is not allowed for value operations, "
                               "Operation: {}".format(op, operation))
        return QueryOpSpec(op, negation, params[0])

    if start_like:
        op = "_%"
        params = _operation.split("%")
        params = [param.strip() for param in params if param.strip()]
        if len(params) != 1:
            raise PQLException("`{}` is not allowed for value operations, "
                               "Operation: {}".format(op, operation))
        return QueryOpSpec(op, negation, params[0])

    if end_like:
        op = "%_"
        params = _operation.split("%")
        params = [param.strip() for param in params if param.strip()]
        if len(params) != 1:
            raise PQLException("`{}` is not allowed for value operations, "
                               "Operation: {}".format(op, operation))
        return QueryOpSpec(op, negation, params[0])

    if not _operation:
        raise PQLException("Expression is not valid, it must be formatted as "
                           "name:operation, "
                           "Operation: {}".format(operation))
    # Now the operation must be an equality param param
    return QueryOpSpec("=", negation, _operation)
示例#15
0
 def filter_queryset(cls, manager: PQLManager, query_spec: str,
                     queryset: Any) -> Any:
     try:
         return manager.apply(query_spec=query_spec, queryset=queryset)
     except Exception as e:
         raise PQLException("Error applying or resolving queryset, %s" % e)