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, )
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_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 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