import { MetricSeriesFilterUpdateType, type MetricsQuery, } from 'sentry/utils/metrics/types'; import {ensureQuotedTextFilters, updateQueryWithSeriesFilter} from './index'; describe('updateQueryWithSeriesFilter', () => { it('should add a filter an empty query stirng', () => { const query = { mri: 'd:transactions/duration@milisecond', aggregation: 'count', groupBy: [], query: '', } as MetricsQuery; const updatedQuery = updateQueryWithSeriesFilter( query, {project: '1'}, MetricSeriesFilterUpdateType.ADD ); expect(updatedQuery.query).toEqual('project:"1"'); expect(updatedQuery.groupBy).toEqual([]); }); it('should add a filter to an existing query string', () => { const query = { mri: 'd:transactions/duration@milisecond', aggregation: 'count', groupBy: [], query: 'release:"latest" AND (environment:production OR environment:staging)', } as MetricsQuery; const updatedQuery = updateQueryWithSeriesFilter( query, {project: '1'}, MetricSeriesFilterUpdateType.ADD ); expect(updatedQuery.query).toEqual( '( release:latest AND ( environment:production OR environment:staging ) ) project:"1"' ); expect(updatedQuery.groupBy).toEqual([]); }); it('should exclude a filter from an empty query string', () => { const query = { mri: 'd:transactions/duration@milisecond', aggregation: 'count', groupBy: [], query: '', } as MetricsQuery; const updatedQuery = updateQueryWithSeriesFilter( query, {project: '1'}, MetricSeriesFilterUpdateType.EXCLUDE ); expect(updatedQuery.query).toEqual('!project:"1"'); expect(updatedQuery.groupBy).toEqual([]); }); it('should exclude a filter from an existing query string', () => { const query = { mri: 'd:transactions/duration@milisecond', aggregation: 'count', groupBy: [], query: 'environment:prod1 OR environment:prod2', } as MetricsQuery; const updatedQuery = updateQueryWithSeriesFilter( query, {project: '2'}, MetricSeriesFilterUpdateType.EXCLUDE ); expect(updatedQuery.query).toEqual( '( environment:prod1 OR environment:prod2 ) !project:"2"' ); expect(updatedQuery.groupBy).toEqual([]); }); it('should add multiple filters and remove them from grouping', () => { const query = { mri: 'd:transactions/duration@milisecond', aggregation: 'count', groupBy: ['project', 'release', 'environment'], query: '', } as MetricsQuery; const updatedQuery = updateQueryWithSeriesFilter( query, {project: '1', release: 'latest'}, MetricSeriesFilterUpdateType.ADD ); expect(updatedQuery.query).toEqual('project:"1" release:"latest"'); expect(updatedQuery.groupBy).toEqual(['environment']); }); it('should add an empty filter value', () => { const query = { mri: 'd:transactions/duration@milisecond', aggregation: 'count', groupBy: [], query: '', } as MetricsQuery; const updatedQuery = updateQueryWithSeriesFilter( query, {project: ''}, MetricSeriesFilterUpdateType.ADD ); expect(updatedQuery.query).toEqual('project:""'); expect(updatedQuery.groupBy).toEqual([]); }); }); describe('ensureQuotedTextFilters', () => { it('returns a query with all text filters quoted', () => { expect(ensureQuotedTextFilters('transaction:/{organization_slug}/')).toEqual( 'transaction:"/{organization_slug}/"' ); // transaction.duration defaults to a number filter expect(ensureQuotedTextFilters('transaction.duration:100')).toEqual( 'transaction.duration:100' ); }); it('handles negated filters', () => { expect(ensureQuotedTextFilters('!transaction:/{organization_slug}/')).toEqual( '!transaction:"/{organization_slug}/"' ); // transaction.duration defaults to a number filter expect(ensureQuotedTextFilters('!transaction.duration:100')).toEqual( '!transaction.duration:100' ); }); it('applies config overrides', () => { expect( ensureQuotedTextFilters('transaction:100', { numericKeys: new Set(['transaction']), }) ).toEqual('transaction:100'); expect( ensureQuotedTextFilters('transaction.duration:100', { numericKeys: new Set([]), }) ).toEqual('transaction.duration:"100"'); }); });