Ejemplo n.º 1
0
 def validate(self, query: Query, alias: Optional[str] = None) -> None:
     condition = query.get_condition()
     top_level = get_first_level_and_conditions(
         condition) if condition else []
     for cond in top_level:
         if self.match.match(cond):
             raise InvalidExpressionException(
                 cond,
                 f"Cannot have existing conditions on time field {self.required_time_column}",
                 report=False,
             )
Ejemplo n.º 2
0
    def validate(self, query: Query, alias: Optional[str] = None) -> None:
        condition = query.get_condition()
        top_level = get_first_level_and_conditions(
            condition) if condition else []

        missing = set()
        if self.required_columns:
            for col in self.required_columns:
                match = build_match(col, [ConditionFunctions.EQ], int, alias)
                found = any(match.match(cond) for cond in top_level)
                if not found:
                    missing.add(col)

        if missing:
            raise InvalidQueryException(
                f"missing required conditions for {', '.join(missing)}")
Ejemplo n.º 3
0
    def _validate_groupby_fields_have_matching_conditions(
            query: Query, alias: Optional[str] = None) -> None:
        """
        Method that insures that for every field in the group by clause, there should be a
        matching a condition. For example, if we had in our groupby clause [project_id, tags[3]],
        we should have the following conditions in the where clause `project_id = 3 AND tags[3]
        IN array(1,2,3)`. This is necessary because we want to avoid the case where an
        unspecified number of buckets is returned.
        """
        condition = query.get_condition()
        top_level = get_first_level_and_conditions(
            condition) if condition else []
        for exp in query.get_groupby():
            key: Optional[str] = None
            if isinstance(exp, SubscriptableReferenceExpr):
                column_name = str(exp.column.column_name)
                key = str(exp.key.value)
            elif isinstance(exp, Column):
                column_name = exp.column_name
            else:
                raise InvalidQueryException(
                    "Unhandled column type in group by validation")

            match = build_match(
                col=column_name,
                ops=[ConditionFunctions.EQ],
                param_type=int,
                alias=alias,
                key=key,
            )
            found = any(match.match(cond) for cond in top_level)

            if not found:
                raise InvalidQueryException(
                    f"Every field in groupby must have a corresponding condition in "
                    f"where clause. missing condition for field {exp}")
Ejemplo n.º 4
0
def get_object_ids_in_query_ast(query: AbstractQuery,
                                object_column: str) -> Optional[Set[int]]:
    """
    Finds the object ids (e.g. project ids) this query is filtering according to the AST
    query representation.

    It works like get_project_ids_in_query with the exception that
    boolean functions are supported here.
    """
    def get_object_ids_in_condition(
            condition: Expression) -> Optional[Set[int]]:
        """
        Extract project ids from an expression. Returns None if no project
        if condition is found. It returns an empty set of conflicting project_id
        conditions are found.
        """
        match = FunctionCall(
            String(ConditionFunctions.EQ),
            (
                Column(column_name=String(object_column)),
                Literal(value=Param("object_id", Any(int))),
            ),
        ).match(condition)
        if match is not None:
            return {match.integer("object_id")}

        match = is_in_condition_pattern(
            Column(column_name=String(object_column))).match(condition)
        if match is not None:
            objects = match.expression("tuple")
            assert isinstance(objects, FunctionCallExpr)
            return {
                lit.value
                for lit in objects.parameters
                if isinstance(lit, LiteralExpr) and isinstance(lit.value, int)
            }

        match = FunctionCall(
            Param(
                "operator",
                Or([String(BooleanFunctions.AND),
                    String(BooleanFunctions.OR)]),
            ),
            (Param("lhs", AnyExpression()), Param("rhs", AnyExpression())),
        ).match(condition)
        if match is not None:
            lhs_objects = get_object_ids_in_condition(match.expression("lhs"))
            rhs_objects = get_object_ids_in_condition(match.expression("rhs"))
            if lhs_objects is None:
                return rhs_objects
            elif rhs_objects is None:
                return lhs_objects
            else:
                return (lhs_objects & rhs_objects if match.string("operator")
                        == BooleanFunctions.AND else lhs_objects | rhs_objects)

        return None

    condition = query.get_condition()
    return get_object_ids_in_condition(
        condition) if condition is not None else None