コード例 #1
0
class BaseTypeConverter(QueryProcessor, ABC):
    def __init__(self, columns: Set[str], optimize_ordering: bool = False):
        self.columns = columns
        self.optimize_ordering = optimize_ordering
        column_match = Or([String(col) for col in columns])

        literal = Param("literal", LiteralMatch(AnyMatch(str)))

        ordering_operators = (
            ConditionFunctions.GT,
            ConditionFunctions.GTE,
            ConditionFunctions.LT,
            ConditionFunctions.LTE,
        )

        operator = Param(
            "operator",
            Or([
                String(op) for op in (
                    ConditionFunctions.EQ,
                    ConditionFunctions.NEQ,
                    ConditionFunctions.IS_NULL,
                    ConditionFunctions.IS_NOT_NULL,
                    *(ordering_operators if self.optimize_ordering else ()),
                )
            ]),
        )

        unoptimizable_operator = Param(
            "operator",
            Or([
                String(op) for op in (
                    ConditionFunctions.LIKE,
                    ConditionFunctions.NOT_LIKE,
                    *(() if self.optimize_ordering else ordering_operators),
                )
            ]),
        )

        in_operators = Param(
            "operator",
            Or((String(ConditionFunctions.IN),
                String(ConditionFunctions.NOT_IN))),
        )

        col = Param("col", ColumnMatch(None, column_match))

        self.__condition_matcher = Or([
            FunctionCallMatch(operator, (literal, col)),
            FunctionCallMatch(operator, (col, literal)),
            FunctionCallMatch(Param("operator", String("has")),
                              (col, literal)),
        ])

        self.__in_condition_matcher = FunctionCallMatch(
            in_operators,
            (
                col,
                Param(
                    "tuple",
                    FunctionCallMatch(String("tuple"),
                                      all_parameters=LiteralMatch()),
                ),
            ),
        )

        self.__unoptimizable_condition_matcher = Or([
            FunctionCallMatch(unoptimizable_operator, (literal, col)),
            FunctionCallMatch(unoptimizable_operator, (col, literal)),
        ])

    def process_query(self, query: Query,
                      query_settings: QuerySettings) -> None:
        query.transform_expressions(self._process_expressions,
                                    skip_transform_condition=True)

        condition = query.get_condition()
        if condition is not None:
            if self.__contains_unoptimizable_condition(condition):
                processed = condition.transform(self._process_expressions)
            else:
                processed = condition.transform(
                    self.__process_optimizable_condition)
                if condition == processed:
                    processed = processed.transform(self._process_expressions)

            query.set_ast_condition(processed)

    def __strip_column_alias(self, exp: Expression) -> Expression:
        assert isinstance(exp, Column)
        return Column(alias=None,
                      table_name=exp.table_name,
                      column_name=exp.column_name)

    def __contains_unoptimizable_condition(self, exp: Expression) -> bool:
        """
        Returns true if there is an unoptimizable condition, otherwise false.
        """
        for e in exp:
            match = self.__unoptimizable_condition_matcher.match(e)
            if match is not None:
                return True

        return False

    def __process_optimizable_condition(self, exp: Expression) -> Expression:
        def assert_literal(lit: Expression) -> Literal:
            assert isinstance(lit, Literal)
            return lit

        match = self.__condition_matcher.match(exp)
        if match is not None:
            return FunctionCall(
                exp.alias,
                match.string("operator"),
                (
                    self.__strip_column_alias(match.expression("col")),
                    self._translate_literal(
                        assert_literal(match.expression("literal"))),
                ),
            )

        in_condition_match = self.__in_condition_matcher.match(exp)

        if in_condition_match is not None:
            tuple_func = in_condition_match.expression("tuple")
            assert isinstance(tuple_func, FunctionCall)

            params = tuple_func.parameters
            for param in params:
                assert isinstance(param, Literal)

            new_tuple_func = FunctionCall(
                tuple_func.alias,
                tuple_func.function_name,
                parameters=tuple([
                    self._translate_literal(assert_literal(lit))
                    for lit in tuple_func.parameters
                ]),
            )
            return FunctionCall(
                exp.alias,
                in_condition_match.string("operator"),
                (
                    self.__strip_column_alias(
                        in_condition_match.expression("col")),
                    new_tuple_func,
                ),
            )

        return exp

    @abstractmethod
    def _translate_literal(self, exp: Literal) -> Expression:
        raise NotImplementedError

    @abstractmethod
    def _process_expressions(self, exp: Expression) -> Expression:
        raise NotImplementedError
コード例 #2
0
ファイル: __init__.py プロジェクト: pombredanne/snuba
class BaseTypeConverter(QueryProcessor, ABC):
    def __init__(self, columns: Set[str]):
        self.columns = columns
        column_match = Or([String(col) for col in columns])

        literal = Param("literal", LiteralMatch(AnyMatch(str)))

        operator = Param(
            "operator",
            Or(
                [
                    String(op)
                    for op in FUNCTION_TO_OPERATOR
                    if op not in (ConditionFunctions.IN, ConditionFunctions.NOT_IN)
                ]
            ),
        )

        in_operators = Param(
            "operator",
            Or((String(ConditionFunctions.IN), String(ConditionFunctions.NOT_IN))),
        )

        col = Param("col", ColumnMatch(None, column_match))

        self.__condition_matcher = Or(
            [
                FunctionCallMatch(operator, (literal, col)),
                FunctionCallMatch(operator, (col, literal)),
                FunctionCallMatch(Param("operator", String("has")), (col, literal)),
            ]
        )

        self.__in_condition_matcher = FunctionCallMatch(
            in_operators,
            (
                col,
                Param(
                    "tuple",
                    FunctionCallMatch(String("tuple"), all_parameters=LiteralMatch()),
                ),
            ),
        )

    def process_query(self, query: Query, request_settings: RequestSettings) -> None:
        query.transform_expressions(
            self._process_expressions, skip_transform_condition=True
        )

        condition = query.get_condition()
        if condition is not None:
            processed = condition.transform(self.__process_optimizable_condition)
            if processed == condition:
                processed = condition.transform(self._process_expressions)

            query.set_ast_condition(processed)

    def __strip_column_alias(self, exp: Expression) -> Expression:
        assert isinstance(exp, Column)
        return Column(
            alias=None, table_name=exp.table_name, column_name=exp.column_name
        )

    def __process_optimizable_condition(self, exp: Expression) -> Expression:
        def assert_literal(lit: Expression) -> Literal:
            assert isinstance(lit, Literal)
            return lit

        match = self.__condition_matcher.match(exp)
        if match is not None:
            return FunctionCall(
                exp.alias,
                match.string("operator"),
                (
                    self.__strip_column_alias(match.expression("col")),
                    self._translate_literal(
                        assert_literal(match.expression("literal"))
                    ),
                ),
            )

        in_condition_match = self.__in_condition_matcher.match(exp)

        if in_condition_match is not None:
            tuple_func = in_condition_match.expression("tuple")
            assert isinstance(tuple_func, FunctionCall)

            params = tuple_func.parameters
            for param in params:
                assert isinstance(param, Literal)

            new_tuple_func = FunctionCall(
                tuple_func.alias,
                tuple_func.function_name,
                parameters=tuple(
                    [
                        self._translate_literal(assert_literal(lit))
                        for lit in tuple_func.parameters
                    ]
                ),
            )
            return FunctionCall(
                exp.alias,
                in_condition_match.string("operator"),
                (
                    self.__strip_column_alias(in_condition_match.expression("col")),
                    new_tuple_func,
                ),
            )

        return exp

    @abstractmethod
    def _translate_literal(self, exp: Literal) -> Expression:
        raise NotImplementedError

    @abstractmethod
    def _process_expressions(self, exp: Expression) -> Expression:
        raise NotImplementedError