def condition_pattern( operators: Set[str], lhs_pattern: Pattern[Expression], rhs_pattern: Pattern[Expression], commutative: bool, ) -> Pattern[Expression]: """ Matches a binary condition given the two operands and the valid operators. It also supports commutative conditions. """ pattern: Pattern[Expression] if commutative: pattern = Or( [ FunctionCallPattern( Or([String(op) for op in operators]), (lhs_pattern, rhs_pattern) ), FunctionCallPattern( Or([String(op) for op in operators]), (rhs_pattern, lhs_pattern) ), ] ) else: pattern = FunctionCallPattern( Or([String(op) for op in operators]), (lhs_pattern, rhs_pattern) ) return pattern
def __set_condition_pattern(lhs: Pattern[Expression], operator: str) -> FunctionCallPattern: return FunctionCallPattern( String(operator), ( Param("lhs", lhs), Param("tuple", FunctionCallPattern(String("tuple"), None)), ), )
def build_match( col: str, ops: Sequence[str], param_type: Any, alias: Optional[str] = None, key: Optional[str] = None, ) -> Or[Expression]: # The IN condition has to be checked separately since each parameter # has to be checked individually. alias_match = AnyOptionalString() if alias is None else String(alias) pattern: Union[ColumnPattern, SubscriptableReferencePattern] if key is not None: pattern = SubscriptableReferencePattern(table_name=alias_match, column_name=String(col), key=String(key)) else: pattern = ColumnPattern(table_name=alias_match, column_name=String(col)) column_match = Param("column", pattern) return Or([ FunctionCallPattern( Or([String(op) for op in ops]), (column_match, Param("rhs", LiteralPattern( AnyPattern(param_type)))), ), FunctionCallPattern( String(ConditionFunctions.IN), ( column_match, Param( "rhs", FunctionCallPattern( Or([String("array"), String("tuple")]), all_parameters=LiteralPattern(AnyPattern(param_type)), ), ), ), ), ])
logger = logging.getLogger(__name__) EQ_CONDITION_PATTERN = condition_pattern( {ConditionFunctions.EQ}, ColumnPattern(None, Param("lhs", Any(str))), LiteralPattern(Any(int)), commutative=True, ) FULL_CONDITION_PATTERN = Or([ EQ_CONDITION_PATTERN, FunctionCallPattern( String(ConditionFunctions.IN), ( ColumnPattern(None, Param("lhs", Any(str))), FunctionCallPattern(Or([String("tuple"), String("array")]), None), ), ), ], ) def _check_expression(pattern: Pattern[Expression], expression: Expression, column_name: str) -> bool: match = pattern.match(expression) return match is not None and match.optional_string("lhs") == column_name class ProjectIdEnforcer(ConditionChecker): def get_id(self) -> str: return "project_id"
def is_not_in_condition(exp: Expression) -> bool: return __is_set_condition(exp, ConditionFunctions.NOT_IN) def is_not_in_condition_pattern( lhs: Pattern[Expression]) -> FunctionCallPattern: return __set_condition_pattern(lhs, ConditionFunctions.NOT_IN) def binary_condition(alias: Optional[str], function_name: str, lhs: Expression, rhs: Expression) -> FunctionCall: return FunctionCall(alias, function_name, (lhs, rhs)) binary_condition_patterns = { op: FunctionCallPattern(String(op), (AnyExpression(), AnyExpression())) for op in BINARY_OPERATORS } def is_binary_condition(exp: Expression, operator: str) -> bool: if operator in binary_condition_patterns: return binary_condition_patterns[operator].match(exp) is not None return False def unary_condition(alias: Optional[str], function_name: str, operand: Expression) -> FunctionCall: return FunctionCall(alias, function_name, (operand, ))
def is_not_in_condition(exp: Expression) -> bool: return __is_set_condition(exp, ConditionFunctions.NOT_IN) def is_not_in_condition_pattern( lhs: Pattern[Expression]) -> FunctionCallPattern: return __set_condition_pattern(lhs, ConditionFunctions.NOT_IN) def binary_condition(function_name: str, lhs: Expression, rhs: Expression) -> FunctionCall: return FunctionCall(None, function_name, (lhs, rhs)) binary_condition_patterns = { op: FunctionCallPattern(String(op), (AnyExpression(), AnyExpression())) for op in BINARY_OPERATORS } def condition_pattern( operators: Set[str], lhs_pattern: Pattern[Expression], rhs_pattern: Pattern[Expression], commutative: bool, ) -> Pattern[Expression]: """ Matches a binary condition given the two operands and the valid operators. It also supports commutative conditions. """ pattern: Pattern[Expression]
KEY_COL_MAPPING_PARAM, KEY_MAPPING_PARAM, TABLE_MAPPING_PARAM, mapping_pattern, ) from snuba.query.conditions import ConditionFunctions, condition_pattern from snuba.query.expressions import Column, Expression, FunctionCall, Literal from snuba.query.matchers import FunctionCall as FunctionCallPattern from snuba.query.matchers import Literal as LiteralPattern from snuba.query.matchers import String from snuba.request.request_settings import RequestSettings CONDITION_PATTERN = condition_pattern( {ConditionFunctions.EQ, ConditionFunctions.NEQ}, FunctionCallPattern( String("ifNull"), (mapping_pattern, LiteralPattern(String(""))), ), LiteralPattern(String("")), commutative=False, ) class EmptyTagConditionProcessor(QueryProcessor): """ If queries have conditions of the form `ifNull(tags[key], '') =/!= ''` we can simplify this using the `has` function. """ def process_query(self, query: Query, request_settings: RequestSettings) -> None: def process_condition(exp: Expression) -> Expression: result = CONDITION_PATTERN.match(exp)