Example #1
0
 def validate(self, query: Query, alias: Optional[str] = None) -> None:
     granularity = query.get_granularity()
     if granularity is None:
         if self.required:
             raise InvalidQueryException("Granularity is missing")
     elif granularity < self.minimum or (granularity % self.minimum) != 0:
         raise InvalidQueryException(
             f"granularity must be multiple of {self.minimum}")
Example #2
0
    def validate(self, query: Query, alias: Optional[str] = None) -> None:
        selected = query.get_selected_columns()
        if len(selected) != 1:
            raise InvalidQueryException(
                "only one aggregation in the select allowed")

        disallowed = ["groupby", "having", "orderby"]
        for field in disallowed:
            if getattr(query, f"get_{field}")():
                raise InvalidQueryException(
                    f"invalid clause {field} in subscription query")
Example #3
0
    def decode(self, value: bytes) -> SubscriptionData:
        try:
            data = json.loads(value.decode("utf-8"))
        except json.JSONDecodeError:
            raise InvalidQueryException("Invalid JSON")

        return SubscriptionData.from_dict(data, self.entity_key)
Example #4
0
    def from_dict(cls, data: Mapping[str, Any]) -> SnQLSubscriptionData:
        if data.get(cls.TYPE_FIELD) != SubscriptionType.SNQL.value:
            raise InvalidQueryException("Invalid SnQL subscription structure")

        return SnQLSubscriptionData(
            project_id=data["project_id"],
            time_window=timedelta(seconds=data["time_window"]),
            resolution=timedelta(seconds=data["resolution"]),
            query=data["query"],
        )
Example #5
0
    def from_dict(cls, data: Mapping[str, Any]) -> LegacySubscriptionData:
        if not data.get("aggregations"):
            raise InvalidQueryException("No aggregation provided")

        return LegacySubscriptionData(
            project_id=data["project_id"],
            conditions=data["conditions"],
            aggregations=data["aggregations"],
            time_window=timedelta(seconds=data["time_window"]),
            resolution=timedelta(seconds=data["resolution"]),
        )
Example #6
0
    def validate(
        self,
        query: Query,
        alias: Optional[str] = None,
    ) -> None:
        selected = query.get_selected_columns()
        if len(selected) > self.max_allowed_aggregations:
            aggregation_error_text = (
                "1 aggregation is" if self.max_allowed_aggregations == 1 else
                f"{self.max_allowed_aggregations} aggregations are")
            raise InvalidQueryException(
                f"A maximum of {aggregation_error_text} allowed in the select")

        for field in self.disallowed_aggregations:
            if getattr(query, f"get_{field}")():
                raise InvalidQueryException(
                    f"invalid clause {field} in subscription query")

        if "groupby" not in self.disallowed_aggregations:
            self._validate_groupby_fields_have_matching_conditions(
                query, alias)
Example #7
0
    def from_dict(cls, data: Mapping[str, Any]) -> DelegateSubscriptionData:
        if data.get(cls.TYPE_FIELD) != SubscriptionType.DELEGATE.value:
            raise InvalidQueryException(
                "Invalid delegate subscription structure")

        return DelegateSubscriptionData(
            project_id=data["project_id"],
            time_window=timedelta(seconds=data["time_window"]),
            resolution=timedelta(seconds=data["resolution"]),
            conditions=data["conditions"],
            aggregations=data["aggregations"],
            query=data["query"],
        )
Example #8
0
    def decode(self, value: bytes) -> SubscriptionData:
        try:
            data = json.loads(value.decode("utf-8"))
        except json.JSONDecodeError:
            raise InvalidQueryException("Invalid JSON")

        subscription_type = data.get(SubscriptionData.TYPE_FIELD)
        if subscription_type == SubscriptionType.SNQL.value:
            return SnQLSubscriptionData.from_dict(data)
        elif subscription_type == SubscriptionType.DELEGATE.value:
            return DelegateSubscriptionData.from_dict(data)
        elif subscription_type is None:
            return LegacySubscriptionData.from_dict(data)
        else:
            raise InvalidSubscriptionError("Invalid subscription data")
Example #9
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}")
Example #10
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)}")
Example #11
0
    def validate(self, query: Query, alias: Optional[str] = None) -> None:
        if self.validation_mode == ColumnValidationMode.DO_NOTHING:
            return

        query_columns = query.get_all_ast_referenced_columns()

        missing = set()
        for column in query_columns:
            if (column.table_name == alias
                    and column.column_name not in self.entity_data_model):
                missing.add(column.column_name)

        if missing:
            error_message = f"query column(s) {', '.join(missing)} do not exist"
            if self.validation_mode == ColumnValidationMode.ERROR:
                raise InvalidQueryException(error_message)
            elif self.validation_mode == ColumnValidationMode.WARN:
                logger.warning(error_message, exc_info=True)
Example #12
0
    def __process_condition(self, exp: Expression) -> Expression:
        result = self.condition_match.match(exp)
        if result is not None:
            literal = result.expression("literal")
            assert isinstance(exp, FunctionCall)  # mypy
            assert isinstance(literal, Literal)  # mypy
            try:
                value = parse_datetime(str(literal.value))
            except ValueError as err:
                column_name = result.string("column_name")
                raise InvalidQueryException(
                    f"Illegal datetime in condition on column {column_name}: '{literal.value}''"
                ) from err

            return FunctionCall(
                exp.alias,
                exp.function_name,
                (exp.parameters[0], Literal(literal.alias, value)),
            )

        return exp