Skip to content

Commit

Permalink
ref(ddm): Prepare metrics query helpers for multi queries (#65146)
Browse files Browse the repository at this point in the history
- relates to #64773
  • Loading branch information
ArthurKnaus authored Feb 14, 2024
1 parent 61ffcc4 commit b103829
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 214 deletions.
176 changes: 0 additions & 176 deletions static/app/utils/metrics/useMetricsData.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {PageFilters} from 'sentry/types';
import {
createMqlQuery,
getMetricsQueryApiRequestPayload,
} from 'sentry/utils/metrics/useMetricsData';
} from 'sentry/utils/metrics/useMetricsQuery';

describe('createMqlQuery', () => {
it('should create a basic mql query', () => {
Expand Down Expand Up @@ -49,7 +49,7 @@ describe('getMetricsQueryApiRequestPayload', () => {
datetime: {start: '2023-01-01', end: '2023-01-31', period: null, utc: true},
};

const result = getMetricsQueryApiRequestPayload(metric, filters);
const result = getMetricsQueryApiRequestPayload([metric], filters);

expect(result.query).toEqual({
start: '2023-01-01T00:00:00.000Z',
Expand Down Expand Up @@ -78,7 +78,7 @@ describe('getMetricsQueryApiRequestPayload', () => {
datetime: {period: '7d', utc: true} as PageFilters['datetime'],
};

const result = getMetricsQueryApiRequestPayload(metric, filters);
const result = getMetricsQueryApiRequestPayload([metric], filters);

expect(result.query).toEqual({
statsPeriod: '7d',
Expand Down Expand Up @@ -106,7 +106,9 @@ describe('getMetricsQueryApiRequestPayload', () => {
datetime: {start: '2023-01-01', end: '2023-01-02', period: null, utc: true},
};

const result = getMetricsQueryApiRequestPayload(metric, filters, {interval: '123m'});
const result = getMetricsQueryApiRequestPayload([metric], filters, {
interval: '123m',
});

expect(result.query).toEqual({
start: '2023-01-01T00:00:00.000Z',
Expand Down Expand Up @@ -140,7 +142,7 @@ describe('getMetricsQueryApiRequestPayload', () => {
datetime: {start: '2023-01-01', end: '2023-01-02', period: null, utc: true},
};

const result = getMetricsQueryApiRequestPayload(metric, filters);
const result = getMetricsQueryApiRequestPayload([metric], filters);

expect(result.query).toEqual({
start: '2023-01-01T00:00:00.000Z',
Expand Down Expand Up @@ -173,7 +175,7 @@ describe('getMetricsQueryApiRequestPayload', () => {
datetime: {start: '2023-01-01', end: '2023-01-02', period: null, utc: true},
};

const result = getMetricsQueryApiRequestPayload(metric, filters);
const result = getMetricsQueryApiRequestPayload([metric], filters);

expect(result.query).toEqual({
start: '2023-01-01T00:00:00.000Z',
Expand Down Expand Up @@ -206,7 +208,7 @@ describe('getMetricsQueryApiRequestPayload', () => {
datetime: {start: '2023-01-01', end: '2023-01-02', period: null, utc: true},
};

const result = getMetricsQueryApiRequestPayload(metric, filters, {
const result = getMetricsQueryApiRequestPayload([metric], filters, {
intervalLadder: 'ddm',
});

Expand Down
116 changes: 116 additions & 0 deletions static/app/utils/metrics/useMetricsQuery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import {useMemo} from 'react';

import type {PageFilters} from 'sentry/types';
import {getDateTimeParams, getDDMInterval} from 'sentry/utils/metrics';
import {getUseCaseFromMRI, MRIToField, parseField} from 'sentry/utils/metrics/mri';
import {useApiQuery} from 'sentry/utils/queryClient';
import useOrganization from 'sentry/utils/useOrganization';

import type {
MetricsDataIntervalLadder,
MetricsQueryApiResponse,
MRI,
} from '../../types/metrics';

export function createMqlQuery({
field,
query,
groupBy = [],
}: {field: string; groupBy?: string[]; query?: string}) {
let mql = field;
if (query) {
mql = `${mql}{${query}}`;
}
if (groupBy.length) {
mql = `${mql} by (${groupBy.join(',')})`;
}
return mql;
}

interface MetricsQueryApiRequestQuery {
field: string;
groupBy?: string[];
limit?: number;
name?: string;
orderBy?: 'asc' | 'desc';
query?: string;
}

export function getMetricsQueryApiRequestPayload(
queries: MetricsQueryApiRequestQuery[],
{projects, environments, datetime}: PageFilters,
{
intervalLadder,
interval: intervalParam,
}: {interval?: string; intervalLadder?: MetricsDataIntervalLadder} = {}
) {
// We take the first queries useCase to determine the interval
// If no useCase is found we default to custom
// The backend will error if the interval is not valid for any of the useCases
const {mri: mri} = parseField(queries[0]?.field) ?? {};
const useCase = getUseCaseFromMRI(mri) ?? 'custom';
const interval = intervalParam ?? getDDMInterval(datetime, useCase, intervalLadder);

const requestQueries: {mql: string; name: string}[] = [];
const requestFormulas: {mql: string; limit?: number; order?: 'asc' | 'desc'}[] = [];

queries.forEach((query, index) => {
const {field, groupBy, limit, orderBy, query: queryParam, name: nameParam} = query;
const name = nameParam || `query_${index + 1}`;
const hasGoupBy = groupBy && groupBy.length > 0;
requestQueries.push({name, mql: createMqlQuery({field, query: queryParam, groupBy})});
requestFormulas.push({
mql: `$${name}`,
limit,
order: hasGoupBy ? orderBy ?? 'desc' : undefined,
});
});

return {
query: {
...getDateTimeParams(datetime),
project: projects,
environment: environments,
interval,
},
body: {
queries: requestQueries,
formulas: requestFormulas,
},
};
}

export function useMetricsQuery(
queries: (Omit<MetricsQueryApiRequestQuery, 'field'> & {mri: MRI; op?: string})[],
{projects, environments, datetime}: PageFilters,
overrides: {interval?: string; intervalLadder?: MetricsDataIntervalLadder} = {}
) {
const organization = useOrganization();

const queryIsComplete = queries.every(({op}) => op);

const {query: queryToSend, body} = useMemo(
() =>
getMetricsQueryApiRequestPayload(
queries.map(query => ({...query, field: MRIToField(query.mri, query.op!)})),
{datetime, projects, environments},
{...overrides}
),
[queries, datetime, projects, environments, overrides]
);

return useApiQuery<MetricsQueryApiResponse>(
[
`/organizations/${organization.slug}/metrics/query/`,
{query: queryToSend, data: body, method: 'POST'},
],
{
retry: 0,
staleTime: 0,
refetchOnReconnect: true,
refetchOnWindowFocus: true,
refetchInterval: false,
enabled: queryIsComplete,
}
);
}
26 changes: 14 additions & 12 deletions static/app/views/dashboards/datasetConfig/metrics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
parseField,
parseMRI,
} from 'sentry/utils/metrics/mri';
import {getMetricsQueryApiRequestPayload} from 'sentry/utils/metrics/useMetricsData';
import {getMetricsQueryApiRequestPayload} from 'sentry/utils/metrics/useMetricsQuery';
import type {OnDemandControlContext} from 'sentry/utils/performance/contexts/onDemandControl';
import {MetricSearchBar} from 'sentry/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/metricSearchBar';
import type {FieldValueOption} from 'sentry/views/discover/table/queryField';
Expand Down Expand Up @@ -402,17 +402,19 @@ function getMetricRequest(
}

const payload = getMetricsQueryApiRequestPayload(
{
field: query.aggregates[0],
query: query.conditions || undefined,
groupBy: query.columns || undefined,
orderBy: query.orderby
? query.orderby.indexOf('-') === 0
? 'desc'
: 'asc'
: undefined,
limit: limit || undefined,
},
[
{
field: query.aggregates[0],
query: query.conditions || undefined,
groupBy: query.columns || undefined,
orderBy: query.orderby
? query.orderby.indexOf('-') === 0
? 'desc'
: 'asc'
: undefined,
limit: limit || undefined,
},
],
pageFilters,
{
intervalLadder: displayType === DisplayType.BAR ? 'bar' : 'dashboard',
Expand Down
Loading

0 comments on commit b103829

Please sign in to comment.