transformSessionsResponseToTable.tsx 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import omit from 'lodash/omit';
  2. import type {MetricsApiResponse, SessionApiResponse} from 'sentry/types';
  3. import type {TableData} from 'sentry/utils/discover/discoverQuery';
  4. import {aggregateOutputType} from 'sentry/utils/discover/fields';
  5. import {
  6. DERIVED_STATUS_METRICS_PATTERN,
  7. SESSIONS_TAGS,
  8. } from 'sentry/views/dashboards/widgetBuilder/releaseWidget/fields';
  9. import {derivedMetricsToField} from './releaseWidgetQueries';
  10. export function changeObjectValuesToTypes(
  11. obj: Record<string, number | string | null> | undefined
  12. ) {
  13. return Object.keys(obj ?? {}).reduce((acc, key) => {
  14. acc[key] = SESSIONS_TAGS.includes(key) ? 'string' : aggregateOutputType(key);
  15. return acc;
  16. }, {});
  17. }
  18. export function mapDerivedMetricsToFields(results: Record<string, number | null>) {
  19. const mappedResults: Record<string, number | null> = {};
  20. for (const [key, value] of Object.entries(results)) {
  21. mappedResults[derivedMetricsToField(key)] = value;
  22. }
  23. return mappedResults;
  24. }
  25. export function getDerivedMetrics(groupBy, totals, requestedStatusMetrics) {
  26. const derivedTotals = {};
  27. if (!requestedStatusMetrics.length) {
  28. return derivedTotals;
  29. }
  30. if (groupBy['session.status'] === undefined) {
  31. return derivedTotals;
  32. }
  33. requestedStatusMetrics.forEach(status => {
  34. const result = status.match(DERIVED_STATUS_METRICS_PATTERN);
  35. if (result) {
  36. if (groupBy['session.status'] === result[1]) {
  37. if (result[2] === 'session') {
  38. derivedTotals[status] = totals['sum(session)'];
  39. } else if (result[2] === 'user') {
  40. derivedTotals[status] = totals['count_unique(user)'];
  41. }
  42. } else {
  43. derivedTotals[status] = 0;
  44. }
  45. }
  46. });
  47. return derivedTotals;
  48. }
  49. export function transformSessionsResponseToTable(
  50. response: SessionApiResponse | MetricsApiResponse | null,
  51. requestedStatusMetrics: string[],
  52. injectedFields: string[]
  53. ): TableData {
  54. const data =
  55. response?.groups.map((group, index) => ({
  56. id: String(index),
  57. ...mapDerivedMetricsToFields(group.by),
  58. // if `sum(session)` or `count_unique(user)` are not
  59. // requested as a part of the payload for
  60. // derived status metrics through the Sessions API,
  61. // they are injected into the payload and need to be
  62. // stripped.
  63. ...omit(mapDerivedMetricsToFields(group.totals), injectedFields),
  64. // if session.status is a groupby, some post processing
  65. // is needed to calculate the status derived metrics
  66. // from grouped results of `sum(session)` or `count_unique(user)`
  67. ...getDerivedMetrics(group.by, group.totals, requestedStatusMetrics),
  68. })) ?? [];
  69. const singleRow = data[0];
  70. // TODO(metrics): these should come from the API in the future
  71. const meta = {
  72. ...changeObjectValuesToTypes(omit(singleRow, 'id')),
  73. };
  74. return {meta, data};
  75. }