blob: 0e4913bb555484f6f0588b0787860b6837a1d07b [file] [log] [blame]
// Copyright (C) 2022 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {EqualsBuilder} from '../common/comparator_builder';
import {ColumnType} from '../common/query_result';
import {SortDirection} from '../common/state';
// Node in the hierarchical pivot tree. Only leaf nodes contain data from the
// query result.
export interface PivotTree {
// Whether the node should be collapsed in the UI, false by default and can
// be toggled with the button.
isCollapsed: boolean;
// Non-empty only in internal nodes.
children: Map<ColumnType, PivotTree>;
aggregates: ColumnType[];
// Non-empty only in leaf nodes.
rows: ColumnType[][];
}
export type AggregationFunction = 'COUNT'|'SUM'|'MIN'|'MAX'|'AVG';
// Queried "table column" is either:
// 1. A real one, represented as object with table and column name.
// 2. Pseudo-column 'count' that's rendered as '1' in SQL to use in queries like
// `select sum(1), name from slice group by name`.
export interface RegularColumn {
kind: 'regular';
table: string;
column: string;
}
export interface ArgumentColumn {
kind: 'argument';
argument: string;
}
export type TableColumn = RegularColumn|ArgumentColumn;
export function tableColumnEquals(t1: TableColumn, t2: TableColumn): boolean {
switch (t1.kind) {
case 'argument': {
return t2.kind === 'argument' && t1.argument === t2.argument;
}
case 'regular': {
return t2.kind === 'regular' && t1.table === t2.table &&
t1.column === t2.column;
}
}
}
export function toggleEnabled<T>(
compare: (fst: T, snd: T) => boolean,
arr: T[],
column: T,
enabled: boolean): void {
if (enabled && arr.find((value) => compare(column, value)) === undefined) {
arr.push(column);
}
if (!enabled) {
const index = arr.findIndex((value) => compare(column, value));
if (index !== -1) {
arr.splice(index, 1);
}
}
}
export interface Aggregation {
aggregationFunction: AggregationFunction;
column: TableColumn;
// If the aggregation is sorted, the field contains a sorting direction.
sortDirection?: SortDirection;
}
export function aggregationEquals(agg1: Aggregation, agg2: Aggregation) {
return new EqualsBuilder(agg1, agg2)
.comparePrimitive((agg) => agg.aggregationFunction)
.compare(tableColumnEquals, (agg) => agg.column)
.equals();
}
// Used to convert TableColumn to a string in order to store it in a Map, as
// ES6 does not support compound Set/Map keys. This function should only be used
// for interning keys, and does not have any requirements beyond different
// TableColumn objects mapping to different strings.
export function columnKey(tableColumn: TableColumn): string {
switch (tableColumn.kind) {
case 'argument': {
return `argument:${tableColumn.argument}`;
}
case 'regular': {
return `${tableColumn.table}.${tableColumn.column}`;
}
}
}
export function aggregationKey(aggregation: Aggregation): string {
return `${aggregation.aggregationFunction}:${columnKey(aggregation.column)}`;
}