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}")
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")
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)
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"], )
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"]), )
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)
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"], )
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")
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}")
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)}")
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)
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