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 {SortDirection} from '../base/comparison_utils'; 16import {EqualsBuilder} from '../common/comparator_builder'; 17import {ColumnType} from '../trace_processor/query_result'; 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 ( 61 t2.kind === 'regular' && 62 t1.table === t2.table && 63 t1.column === t2.column 64 ); 65 } 66 } 67} 68 69export function toggleEnabled<T>( 70 compare: (fst: T, snd: T) => boolean, 71 arr: T[], 72 column: T, 73 enabled: boolean, 74): void { 75 if (enabled && arr.find((value) => compare(column, value)) === undefined) { 76 arr.push(column); 77 } 78 if (!enabled) { 79 const index = arr.findIndex((value) => compare(column, value)); 80 if (index !== -1) { 81 arr.splice(index, 1); 82 } 83 } 84} 85 86export interface Aggregation { 87 aggregationFunction: AggregationFunction; 88 column: TableColumn; 89 90 // If the aggregation is sorted, the field contains a sorting direction. 91 sortDirection?: SortDirection; 92} 93 94export function aggregationEquals(agg1: Aggregation, agg2: Aggregation) { 95 return new EqualsBuilder(agg1, agg2) 96 .comparePrimitive((agg) => agg.aggregationFunction) 97 .compare(tableColumnEquals, (agg) => agg.column) 98 .equals(); 99} 100 101// Used to convert TableColumn to a string in order to store it in a Map, as 102// ES6 does not support compound Set/Map keys. This function should only be used 103// for interning keys, and does not have any requirements beyond different 104// TableColumn objects mapping to different strings. 105export function columnKey(tableColumn: TableColumn): string { 106 switch (tableColumn.kind) { 107 case 'argument': { 108 return `argument:${tableColumn.argument}`; 109 } 110 case 'regular': { 111 return `${tableColumn.table}.${tableColumn.column}`; 112 } 113 } 114} 115 116export function aggregationKey(aggregation: Aggregation): string { 117 return `${aggregation.aggregationFunction}:${columnKey(aggregation.column)}`; 118} 119