123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- import {
- FilterType,
- joinQuery,
- parseSearch,
- type SearchConfig,
- Token,
- } from 'sentry/components/searchSyntax/parser';
- import {defined} from 'sentry/utils';
- import {
- MetricSeriesFilterUpdateType,
- type MetricsQuery,
- } from 'sentry/utils/metrics/types';
- import {MutableSearch} from 'sentry/utils/tokenizeSearch';
- import {addToFilter, excludeFromFilter} from '../../discover/table/cellAction';
- /**
- * Updates query string with tag values from the passed groupBys.
- */
- export function extendQueryWithGroupBys(
- query: string,
- groupBys: (Record<string, string> | undefined)[]
- ) {
- const mutableSearch = new MutableSearch(query);
- groupBys.forEach(groupBy => {
- if (!groupBy) {
- return;
- }
- Object.entries(groupBy).forEach(([key, value]) => {
- if (!value) {
- return;
- }
- addToFilter(mutableSearch, key, value);
- });
- });
- return mutableSearch.formatString();
- }
- /**
- * Wraps text filters of a search string in quotes if they are not already.
- */
- export function ensureQuotedTextFilters(
- query: string,
- configOverrides?: Partial<SearchConfig>
- ) {
- const parsedSearch = parseSearch(query, configOverrides);
- if (!parsedSearch) {
- return query;
- }
- for (let i = 0; i < parsedSearch.length; i++) {
- const token = parsedSearch[i];
- if (token.type === Token.FILTER && token.filter === FilterType.TEXT) {
- // joinQuery() does not access nested tokens, so we need to manipulate the text of the filter instead of it's value
- if (!token.value.quoted) {
- token.text = `${token.negated ? '!' : ''}${token.key.text}:"${token.value.text}"`;
- }
- const spaceToken = parsedSearch[i + 1];
- const afterSpaceToken = parsedSearch[i + 2];
- if (
- spaceToken &&
- afterSpaceToken &&
- spaceToken.type === Token.SPACES &&
- spaceToken.text === '' &&
- afterSpaceToken.type === Token.FILTER
- ) {
- // Ensure there is a space between two filters
- spaceToken.text = ' ';
- }
- }
- }
- return joinQuery(parsedSearch);
- }
- /**
- * Used when a user clicks on filter button in the series summary table. Applies
- * tag values to the filter string of the query. Removes the tags from query groupyBy
- */
- export function updateQueryWithSeriesFilter(
- query: MetricsQuery,
- groupBys: Record<string, string>,
- updateType: MetricSeriesFilterUpdateType
- ) {
- // TODO(metrics): This is a temporary solution to handle the case where the query has OR operator.
- // since addToFilter and excludeFromFilter do not handle it properly. We should refactor this to use
- // search syntax parser instead.
- const queryStr = query.query?.includes('OR') ? `(${query.query})` : query.query ?? '';
- const mutableSearch = new MutableSearch(queryStr);
- const groupByEntries = Object.entries(groupBys);
- groupByEntries.forEach(([key, value]) => {
- if (!defined(value)) {
- return;
- }
- updateType === MetricSeriesFilterUpdateType.ADD
- ? addToFilter(mutableSearch, key, value)
- : excludeFromFilter(mutableSearch, key, value);
- });
- const extendedQuery = mutableSearch.formatString();
- const newGroupBy = (query.groupBy ?? []).filter(tag => !groupBys[tag]);
- return {
- ...query,
- query: ensureQuotedTextFilters(extendedQuery),
- groupBy: newGroupBy,
- };
- }
|