• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2022 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {EqualsBuilder} from '../common/comparator_builder';
16import {ColumnType} from '../common/query_result';
17import {SortDirection} from '../common/state';
18
19// Node in the hierarchical pivot tree. Only leaf nodes contain data from the
20// query result.
21export interface PivotTree {
22  // Whether the node should be collapsed in the UI, false by default and can
23  // be toggled with the button.
24  isCollapsed: boolean;
25
26  // Non-empty only in internal nodes.
27  children: Map<ColumnType, PivotTree>;
28  aggregates: ColumnType[];
29
30  // Non-empty only in leaf nodes.
31  rows: ColumnType[][];
32}
33
34export type AggregationFunction = 'COUNT'|'SUM'|'MIN'|'MAX'|'AVG';
35
36// Queried "table column" is either:
37// 1. A real one, represented as object with table and column name.
38// 2. Pseudo-column 'count' that's rendered as '1' in SQL to use in queries like
39// `select sum(1), name from slice group by name`.
40
41export interface RegularColumn {
42  kind: 'regular';
43  table: string;
44  column: string;
45}
46
47export interface ArgumentColumn {
48  kind: 'argument';
49  argument: string;
50}
51
52export type TableColumn = RegularColumn|ArgumentColumn;
53
54export function tableColumnEquals(t1: TableColumn, t2: TableColumn): boolean {
55  switch (t1.kind) {
56    case 'argument': {
57      return t2.kind === 'argument' && t1.argument === t2.argument;
58    }
59    case 'regular': {
60      return t2.kind === 'regular' && t1.table === t2.table &&
61          t1.column === t2.column;
62    }
63  }
64}
65
66export function toggleEnabled<T>(
67    compare: (fst: T, snd: T) => boolean,
68    arr: T[],
69    column: T,
70    enabled: boolean): void {
71  if (enabled && arr.find((value) => compare(column, value)) === undefined) {
72    arr.push(column);
73  }
74  if (!enabled) {
75    const index = arr.findIndex((value) => compare(column, value));
76    if (index !== -1) {
77      arr.splice(index, 1);
78    }
79  }
80}
81
82export interface Aggregation {
83  aggregationFunction: AggregationFunction;
84  column: TableColumn;
85
86  // If the aggregation is sorted, the field contains a sorting direction.
87  sortDirection?: SortDirection;
88}
89
90export function aggregationEquals(agg1: Aggregation, agg2: Aggregation) {
91  return new EqualsBuilder(agg1, agg2)
92      .comparePrimitive((agg) => agg.aggregationFunction)
93      .compare(tableColumnEquals, (agg) => agg.column)
94      .equals();
95}
96
97// Used to convert TableColumn to a string in order to store it in a Map, as
98// ES6 does not support compound Set/Map keys. This function should only be used
99// for interning keys, and does not have any requirements beyond different
100// TableColumn objects mapping to different strings.
101export function columnKey(tableColumn: TableColumn): string {
102  switch (tableColumn.kind) {
103    case 'argument': {
104      return `argument:${tableColumn.argument}`;
105    }
106    case 'regular': {
107      return `${tableColumn.table}.${tableColumn.column}`;
108    }
109  }
110}
111
112export function aggregationKey(aggregation: Aggregation): string {
113  return `${aggregation.aggregationFunction}:${columnKey(aggregation.column)}`;
114}
115