1// Copyright (C) 2021 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 {getHiddenPivotAlias} from './pivot_table_query_generator'; 16import {Row} from './query_result'; 17 18export const AVAILABLE_TABLES = ['slice']; 19export const AVAILABLE_AGGREGATIONS = ['COUNT', 'SUM', 'AVG', 'MIN', 'MAX']; 20export const WHERE_FILTERS = ['slice.dur != -1']; 21export const SLICE_STACK_HELPER_COLUMNS = 22 ['depth', 'stack_id', 'parent_stack_id']; 23export const SLICE_STACK_COLUMN = 'name (stack)'; 24export const DEFAULT_PIVOT_TABLE_ID = 'pivot-table'; 25export const SLICE_AGGREGATION_PIVOT_TABLE_ID = 'pivot-table-slices'; 26 27export interface AggregationAttrs { 28 tableName: string; 29 columnName: string; 30 aggregation: string; 31 order: string; 32} 33 34export interface PivotAttrs { 35 tableName: string; 36 columnName: string; 37 isStackPivot: boolean; 38} 39 40export interface TableAttrs { 41 tableName: string; 42 columns: string[]; 43} 44 45export interface ColumnAttrs { 46 name: string; 47 index: number; 48 tableName: string; 49 columnName: string; 50 aggregation?: string; 51 order?: string; 52 isStackColumn: boolean; 53} 54 55export interface RowAttrs { 56 row: Row; 57 expandableColumns: Set<string>; // Columns at which the row can be expanded. 58 expandedRows: Map<string, { 59 isExpanded: boolean, 60 rows: RowAttrs[] 61 }>; // Contains the expanded rows of each expanded expandableColumn. 62 whereFilters: Map<string, string>; // Where filters of each column that 63 // joins the row with its parent. 64 loadingColumn?: string; 65 depth: number; 66} 67 68export interface SubQueryAttrs { 69 rowIndices: number[]; 70 columnIdx: number; 71 value: string; 72 expandedRowColumns: string[]; 73} 74 75export interface SubQueryAttrs { 76 rowIndices: number[]; 77 columnIdx: number; 78 value: string; 79} 80 81export interface PivotTableQueryResponse { 82 columns: ColumnAttrs[]; 83 error?: string; 84 durationMs: number; 85 rows: RowAttrs[]; 86 totalAggregations?: Row; 87} 88 89// Determine if the column provided is a stack column that can be expanded 90// into descendants. 91export function isStackPivot(tableName: string, columnName: string) { 92 if (tableName === 'slice' && columnName === SLICE_STACK_COLUMN) { 93 return true; 94 } 95 return false; 96} 97 98// Get the helper columns that are needed to expand a stack pivot. 99export function getHiddenStackHelperColumns(pivot: PivotAttrs) { 100 const hiddenColumns: Array<{pivotAttrs: PivotAttrs, columnAlias: string}> = 101 []; 102 if (pivot.tableName === 'slice') { 103 for (const column of SLICE_STACK_HELPER_COLUMNS) { 104 const pivotAttrs = { 105 tableName: pivot.tableName, 106 columnName: column, 107 isStackPivot: false 108 }; 109 hiddenColumns.push( 110 {pivotAttrs, columnAlias: getHiddenPivotAlias(pivotAttrs)}); 111 } 112 } 113 return hiddenColumns; 114} 115 116// Removing unnecessary columns from table and adding stack column if it exists. 117export function removeHiddenAndAddStackColumns( 118 tableName: string, columns: string[]) { 119 if (tableName === 'slice') { 120 // Removing "cat" and "slice_id" to maintain the original schema of the 121 // slice table that's compatible with descendant_slice_by_stack table. 122 columns = columns.filter( 123 column => ['stack_id', 'parent_stack_id', 'cat', 'slice_id'].includes( 124 column) === false); 125 columns.push(SLICE_STACK_COLUMN); 126 } 127 return columns; 128} 129 130// Get a list of tables that include the descendants that need to be queried. 131export function getDescendantsTables(pivots: PivotAttrs[], stackId: string) { 132 const descendantsTables = [...AVAILABLE_TABLES]; 133 let descendantsTable = 'undefined_table'; 134 let replaceIdx = -1; 135 if (pivots.length > 0 && pivots[0].tableName === 'slice') { 136 // Replace slice table with descendants table. 137 descendantsTable = `descendant_slice_by_stack(${stackId}) AS slice`; 138 replaceIdx = descendantsTables.indexOf('slice'); 139 if (replaceIdx === -1) { 140 throw Error('Slice table not found.'); 141 } 142 } 143 if (pivots.length === 0 || 144 !isStackPivot(pivots[0].tableName, pivots[0].columnName) || 145 replaceIdx === -1) { 146 throw Error('Invalid Arguments to "getDescendantsTables"'); 147 } 148 descendantsTables[replaceIdx] = descendantsTable; 149 return descendantsTables; 150} 151 152// Get the stack id column in the stack pivot table. 153export function getStackColumn(pivot: PivotAttrs) { 154 if (pivot.tableName === 'slice') { 155 return {tableName: 'slice', columnName: 'stack_id', isStackPivot: false}; 156 } 157 throw Error('"getStackColumn" called on pivot that is not a stack column.'); 158} 159 160// Get the parent stack id column in the stack pivot table. 161export function getParentStackColumn(pivot: PivotAttrs) { 162 if (pivot.tableName === 'slice') { 163 return { 164 tableName: 'slice', 165 columnName: 'parent_stack_id', 166 isStackPivot: false 167 }; 168 } 169 throw Error( 170 '"getParentStackColumn" called on pivot that is not a stack column.'); 171} 172 173// Get the depth column in the stack pivot table. 174export function getStackDepthColumn(pivot: PivotAttrs) { 175 if (pivot.tableName === 'slice') { 176 return {tableName: 'slice', columnName: 'depth', isStackPivot: false}; 177 } 178 throw Error( 179 '"getStackDepthColumn" called on pivot that is not a stack column.'); 180} 181 182// Get a where filter that restricts the query by the given stack id. 183export function getParentStackWhereFilter(pivot: PivotAttrs, stackId: string) { 184 const stackColumn = getStackColumn(pivot); 185 return `${stackColumn.tableName}.${stackColumn.columnName} = ${stackId}`; 186} 187