def __init__(self, query, params, allow_minute_resolution=False): self.query = query.get("query", "") self.raw_fields = raw_fields = query.getlist("field", []) self.raw_groupby = raw_groupby = query.getlist("groupBy", []) if len(raw_fields) == 0: raise InvalidField('Request is missing a "field"') self.fields = {} for key in raw_fields: if key not in COLUMN_MAP: raise InvalidField(f'Invalid field: "{key}"') self.fields[key] = COLUMN_MAP[key] self.groupby = [] for key in raw_groupby: if key not in GROUPBY_MAP: raise InvalidField(f'Invalid groupBy: "{key}"') self.groupby.append(GROUPBY_MAP[key]) start, end, rollup = get_constrained_date_range( query, allow_minute_resolution) self.rollup = rollup self.start = start self.end = end self.params = params query_columns = set() for field in self.fields.values(): query_columns.update(field.get_snuba_columns(raw_groupby)) for groupby in self.groupby: query_columns.update(groupby.get_snuba_columns()) self.query_columns = list(query_columns) query_groupby = set() for groupby in self.groupby: query_groupby.update(groupby.get_snuba_groupby()) self.query_groupby = list(query_groupby) # the `params` are: # project_id, organization_id, environment; # also: start, end; but we got those ourselves. snuba_filter = get_filter(self.query, params) # this makes sure that literals in complex queries are properly quoted, # and unknown fields are raised as errors conditions = [ resolve_condition(c, resolve_column) for c in snuba_filter.conditions ] self.aggregations = snuba_filter.aggregations self.conditions = conditions self.filter_keys = snuba_filter.filter_keys
def resolve_discover_aliases(snuba_filter, function_translations=None): """ Resolve the public schema aliases to the discover dataset. Returns a copy of the input structure, and includes a `translated_columns` key containing the selected fields that need to be renamed in the result set. """ resolved = snuba_filter.clone() translated_columns = {} derived_columns = set() if function_translations: for snuba_name, sentry_name in six.iteritems(function_translations): derived_columns.add(snuba_name) translated_columns[snuba_name] = sentry_name selected_columns = resolved.selected_columns if selected_columns: for (idx, col) in enumerate(selected_columns): if isinstance(col, (list, tuple)): resolve_complex_column(col) else: name = resolve_column(col) selected_columns[idx] = name translated_columns[name] = col resolved.selected_columns = selected_columns groupby = resolved.groupby if groupby: for (idx, col) in enumerate(groupby): name = col if isinstance(col, (list, tuple)): if len(col) == 3: name = col[2] elif col not in derived_columns: name = resolve_column(col) groupby[idx] = name resolved.groupby = groupby aggregations = resolved.aggregations for aggregation in aggregations or []: derived_columns.add(aggregation[2]) if isinstance(aggregation[1], six.string_types): aggregation[1] = resolve_column(aggregation[1]) elif isinstance(aggregation[1], (set, tuple, list)): aggregation[1] = [resolve_column(col) for col in aggregation[1]] resolved.aggregations = aggregations conditions = resolved.conditions if conditions: for (i, condition) in enumerate(conditions): replacement = resolve_condition(condition, resolve_column) conditions[i] = replacement resolved.conditions = [c for c in conditions if c] orderby = resolved.orderby if orderby: orderby = orderby if isinstance(orderby, (list, tuple)) else [orderby] resolved_orderby = [] for field_with_order in orderby: field = field_with_order.lstrip("-") resolved_orderby.append(u"{}{}".format( "-" if field_with_order.startswith("-") else "", field if field in derived_columns else resolve_column(field), )) resolved.orderby = resolved_orderby return resolved, translated_columns
def resolve_discover_aliases(snuba_args): """ Resolve the public schema aliases to the discover dataset. Returns a copy of the input structure, and includes a `translated_columns` key containing the selected fields that need to be renamed in the result set. """ resolved = deepcopy(snuba_args) translated_columns = {} derived_columns = set() selected_columns = resolved.get("selected_columns") if selected_columns: for (idx, col) in enumerate(selected_columns): if isinstance(col, (list, tuple)): raise ValueError( "discover selected_columns should only be str. got %s" % col) name = resolve_column(col) selected_columns[idx] = name translated_columns[name] = col resolved["selected_columns"] = selected_columns groupby = resolved.get("groupby") if groupby: for (idx, col) in enumerate(groupby): name = col if col not in derived_columns: name = resolve_column(col) groupby[idx] = name resolved["groupby"] = groupby aggregations = resolved.get("aggregations") for aggregation in aggregations or []: derived_columns.add(aggregation[2]) if isinstance(aggregation[1], six.string_types): aggregation[1] = resolve_column(aggregation[1]) elif isinstance(aggregation[1], (set, tuple, list)): aggregation[1] = [resolve_column(col) for col in aggregation[1]] resolved["aggregations"] = aggregations conditions = resolved.get("conditions") if conditions: for (i, condition) in enumerate(conditions): replacement = resolve_condition(condition, resolve_column) conditions[i] = replacement resolved["conditions"] = list(filter(None, conditions)) # TODO add support for extracting having conditions. orderby = resolved.get("orderby") if orderby: orderby = orderby if isinstance(orderby, (list, tuple)) else [orderby] resolved_orderby = [] for field_with_order in orderby: field = field_with_order.lstrip("-") resolved_orderby.append(u"{}{}".format( "-" if field_with_order.startswith("-") else "", field if field in derived_columns else resolve_column(field), )) resolved["orderby"] = resolved_orderby return resolved, translated_columns