transformSessionsResponseToTable.tsx 2.8 KB

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