@finos/legend-data-cube
Version:
451 lines (405 loc) • 13.9 kB
text/typescript
/**
* Copyright (c) 2020-present, Goldman Sachs
*
* 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 { TailwindCSSPalette } from '@finos/legend-art';
import {
DATE_FORMAT,
PRIMITIVE_TYPE,
type V1_AppliedFunction,
} from '@finos/legend-graph';
import {
guaranteeNonNullable,
IllegalStateError,
UnsupportedOperationError,
formatDate,
} from '@finos/legend-shared';
import type { DataCubeQueryFilterOperation } from './filter/DataCubeQueryFilterOperation.js';
import type { DataCubeQueryAggregateOperation } from './aggregation/DataCubeQueryAggregateOperation.js';
export enum DataCubeFunction {
// relation
EXTEND = 'meta::pure::functions::relation::extend',
FILTER = 'meta::pure::functions::relation::filter',
GROUP_BY = 'meta::pure::functions::relation::groupBy',
LIMIT = 'meta::pure::functions::relation::limit',
PIVOT = 'meta::pure::functions::relation::pivot',
SELECT = 'meta::pure::functions::relation::select',
SLICE = 'meta::pure::functions::relation::slice',
SORT = 'meta::pure::functions::relation::sort',
OVER = 'meta::pure::functions::relation::over',
// generic
CAST = 'meta::pure::functions::lang::cast',
FROM = 'meta::pure::mapping::from',
// sort
ASCENDING = 'meta::pure::functions::relation::ascending',
DESCENDING = 'meta::pure::functions::relation::descending',
ABS = 'meta::pure::functions::math::abs',
// filter
AND = 'meta::pure::functions::boolean::and',
OR = 'meta::pure::functions::boolean::or',
NOT = 'meta::pure::functions::boolean::not',
TO_LOWERCASE = 'meta::pure::functions::string::toLower',
CONTAINS = 'meta::pure::functions::string::contains',
ENDS_WITH = 'meta::pure::functions::string::endsWith',
EQUAL = 'meta::pure::functions::boolean::equal',
GREATER_THAN = 'meta::pure::functions::boolean::greaterThan',
GREATER_THAN_OR_EQUAL = 'meta::pure::functions::boolean::greaterThanEqual',
IN = 'meta::pure::functions::collection::in',
IS_EMPTY = 'meta::pure::functions::collection::isEmpty',
LESS_THAN = 'meta::pure::functions::boolean::lessThan',
LESS_THAN_OR_EQUAL = 'meta::pure::functions::boolean::lessThanEqual',
STARTS_WITH = 'meta::pure::functions::string::startsWith',
// aggregate
AVERAGE = 'meta::pure::functions::math::average',
COUNT = 'meta::pure::functions::collection::count',
DISTINCT = 'meta::pure::functions::collection::distinct',
FIRST = 'meta::pure::functions::collection::first',
JOIN_STRINGS = 'meta::pure::functions::string::joinStrings',
LAST = 'meta::pure::functions::collection::last',
MAX = 'meta::pure::functions::collection::max',
MIN = 'meta::pure::functions::collection::min',
SUM = 'meta::pure::functions::math::sum',
STANDARD_DEVIATION_POPULATION = 'meta::pure::functions::math::stdDevPopulation',
STANDARD_DEVIATION_SAMPLE = 'meta::pure::functions::math::stdDevSample',
UNIQUE_VALUE_ONLY = 'meta::pure::functions::collection::uniqueValueOnly',
VARIANCE_POPULATION = 'meta::pure::functions::math::variancePopulation',
VARIANCE_SAMPLE = 'meta::pure::functions::math::varianceSample',
// PERCENTILE = 'meta::pure::functions::math::percentile',
}
export type DataCubeQueryFunctionMap = {
leafExtend?: V1_AppliedFunction[] | undefined;
filter?: V1_AppliedFunction | undefined;
pivotSort?: V1_AppliedFunction | undefined;
pivot?: V1_AppliedFunction | undefined;
pivotCast?: V1_AppliedFunction | undefined;
groupBy?: V1_AppliedFunction | undefined;
groupBySort?: V1_AppliedFunction | undefined;
groupExtend?: V1_AppliedFunction[] | undefined;
select?: V1_AppliedFunction | undefined;
sort?: V1_AppliedFunction | undefined;
limit?: V1_AppliedFunction | undefined;
};
export enum DataCubeNumberScale {
BASIS_POINT = 'Basis Points (bp)',
PERCENT = 'Percent (%)',
THOUSANDS = 'Thousands (k)',
MILLIONS = 'Millions (m)',
BILLIONS = 'Billions (b)',
TRILLIONS = 'Trillions (t)',
AUTO = 'Auto (k/m/b/t)',
}
export enum DataCubeFont {
// sans-serif
ARIAL = 'Arial',
ROBOTO = 'Roboto',
ROBOTO_CONDENSED = 'Roboto Condensed',
// serif
TIMES_NEW_ROMAN = 'Times New Roman',
GEORGIA = 'Georgia',
ROBOTO_SERIF = 'Roboto Serif',
// monospace
JERBRAINS_MONO = 'Jetbrains Mono',
ROBOTO_MONO = 'Roboto Mono',
UBUNTU_MONO = 'Ubuntu Mono',
}
export enum DataCubeFontTextAlignment {
CENTER = 'center',
LEFT = 'left',
RIGHT = 'right',
}
export enum DataCubeFontCase {
LOWERCASE = 'lowercase',
UPPERCASE = 'uppercase',
CAPITALIZE = 'capitalize',
}
export enum DataCubeFontFormatUnderlineVariant {
SOLID = 'solid',
DASHED = 'dashed',
DOTTED = 'dotted',
DOUBLE = 'double',
WAVY = 'wavy',
}
export enum DataCubeColumnKind {
MEASURE = 'Measure',
DIMENSION = 'Dimension',
}
export enum DataCubeOperationAdvancedValueType {
COLUMN = 'COLUMN',
VOID = 'VOID',
// PARAMETER
}
export type DataCubeOperationValue = {
value?: unknown;
type: string;
};
export enum DataCubeQueryAggregateOperator {
SUM = 'sum',
AVERAGE = 'avg',
COUNT = 'count',
MIN = 'min',
MAX = 'max',
UNIQUE = 'uniq',
FIRST = 'first',
LAST = 'last',
// MEDIAN = 'median',
VARIANCE_POPULATION = 'var',
VARIANCE_SAMPLE = 'var_sample',
STANDARD_DEVIATION_POPULATION = 'std',
STANDARD_DEVIATION_SAMPLE = 'std_sample',
// STANDARD_ERROR = 'stderr',
// NULL = 'null',
// ssq
// countvalid
// countnull
// uniqunstrict
// minmagnitude
// maxmagnitude
// commonprefix
// commonprefixunstrict
JOIN_STRINGS = 'strjoin',
// strjoinuniq
// splitjoin
// daterange
// wavg
// wstderr
// wsum
// custom
}
export enum DataCubeQueryClientSideAggregateOperator {
SUM = 'sum',
AVERAGE = 'avg',
MEDIAN = 'median',
COUNT = 'count',
MIN = 'min',
MAX = 'max',
VARIANCE_POPULATION = 'var',
VARIANCE_SAMPLE = 'var_sample',
STANDARD_DEVIATION_POPULATION = 'std',
STANDARD_DEVIATION_SAMPLE = 'std_sample',
}
export enum DataCubeQueryFilterOperator {
LESS_THAN = '<',
LESS_THAN_OR_EQUAL = '<=',
EQUAL = '=',
NOT_EQUAL = '!=',
GREATER_THAN = '>',
GREATER_THAN_OR_EQUAL = '>=',
IN = 'in',
NOT_IN = 'not in',
IS_NULL = 'is null',
IS_NOT_NULL = 'is not null',
// string ONLY
EQUAL_CASE_INSENSITIVE = '= (case-insensitive)',
NOT_EQUAL_CASE_INSENSITIVE = '!= (case-insensitive)',
IN_CASE_INSENSITIVE = 'in (case-insensitive)',
NOT_IN_CASE_INSENSITIVE = 'not in (case-insensitive)',
CONTAIN = 'contains',
CONTAIN_CASE_INSENSITIVE = 'contains (case-insensitive)',
NOT_CONTAIN = 'does not contain',
START_WITH = 'starts with',
START_WITH_CASE_INSENSITIVE = 'starts with (case-insensitive)',
NOT_START_WITH = 'does not start with',
END_WITH = 'ends with',
END_WITH_CASE_INSENSITIVE = 'ends with (case-insensitive)',
NOT_END_WITH = 'does not end with',
// column
LESS_THAN_COLUMN = '< value in column',
LESS_THAN_OR_EQUAL_COLUMN = '<= value in column',
EQUAL_COLUMN = '= value in column',
EQUAL_CASE_INSENSITIVE_COLUMN = '= (case-insensitive) value in column',
NOT_EQUAL_COLUMN = '!= value in column',
NOT_EQUAL_CASE_INSENSITIVE_COLUMN = '!= (case-insensitive) value in column',
GREATER_THAN_COLUMN = '> value in column',
GREATER_THAN_OR_EQUAL_COLUMN = '>= value in column',
// TODO?: having, having in aggregate, between
}
export enum DataCubeQueryFilterGroupOperator {
AND = 'and',
OR = 'or',
}
export enum DataCubeQuerySortDirection {
ASCENDING = 'Ascending',
DESCENDING = 'Descending',
}
export enum DataCubeColumnPinPlacement {
LEFT = 'Left',
RIGHT = 'Right',
}
export enum DataCubeColumnDataType {
NUMBER = 'Numeric',
TEXT = 'Text',
DATE = 'Date',
TIME = 'Time',
}
export enum DataCubeGridMode {
STANDARD = 'Standard',
MULTIDIMENSIONAL = 'Multidimensional',
}
export enum DataCubeClientModelOption {
ROW_DATA = 'rowData',
COLUMN_DEFS = 'columnDefs',
LOADING = 'loading',
}
export enum DataCubeTitleBarMenuItems {
VIEW_SOURCE = 'View Source',
RESET_TO_LATEST_SAVE = 'Reset to Latest Save',
UPDATE_INFO = 'Update Info...',
DELETE_DATACUBE = 'Delete DataCube...',
SEE_DOCUMENTATION = 'See Documentation',
ABOUT = 'About',
UNDO = 'Undo',
REDO = 'Redo',
SETTINGS = 'Settings...',
}
export enum DataCubeOpenEditorSource {
STATUS_BAR = 'Status Bar',
GRID_MENU = 'Grid Menu',
}
export const PIVOT_COLUMN_NAME_VALUE_SEPARATOR = '__|__';
export const TREE_COLUMN_VALUE_SEPARATOR = '__/__';
export const DEFAULT_LAMBDA_VARIABLE_NAME = 'x';
export const DEFAULT_REPORT_NAME = 'New Report';
export const DEFAULT_TREE_COLUMN_SORT_DIRECTION =
DataCubeQuerySortDirection.ASCENDING;
export const DEFAULT_PIVOT_STATISTIC_COLUMN_NAME = 'Total';
export const DEFAULT_PIVOT_COLUMN_SORT_DIRECTION =
DataCubeQuerySortDirection.ASCENDING;
export const DEFAULT_ROOT_AGGREGATION_COLUMN_VALUE = '[ROOT]';
export const DEFAULT_URL_LABEL_QUERY_PARAM = 'dataCube.linkLabel';
export const DEFAULT_MISSING_VALUE_DISPLAY_TEXT = '';
export const DEFAULT_GRID_LINE_COLOR = TailwindCSSPalette.neutral[300];
export const DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR = '#d7e0eb';
export const DEFAULT_COLUMN_WIDTH = 300;
export const DEFAULT_COLUMN_MIN_WIDTH = 50;
export const DEFAULT_COLUMN_MAX_WIDTH = undefined;
export const DEFAULT_GRID_MODE = DataCubeGridMode.STANDARD;
export const DEFAULT_FONT_FAMILY = DataCubeFont.ROBOTO;
export const DEFAULT_FONT_SIZE = 11;
export const DEFAULT_FONT_BOLD = false;
export const DEFAULT_FONT_ITALIC = false;
export const DEFAULT_FONT_CASE = undefined;
export const DEFAULT_FONT_UNDERLINED = undefined;
export const DEFAULT_FONT_STRIKETHROUGH = false;
export const DEFAULT_TEXT_ALIGN = DataCubeFontTextAlignment.LEFT;
export const DEFAULT_FOREGROUND_COLOR = TailwindCSSPalette.black;
export const DEFAULT_BACKGROUND_COLOR = TailwindCSSPalette.transparent;
export const DEFAULT_ROW_BACKGROUND_COLOR = TailwindCSSPalette.white;
export const DEFAULT_NEGATIVE_FOREGROUND_COLOR = TailwindCSSPalette.red[500];
export const DEFAULT_ZERO_FOREGROUND_COLOR = TailwindCSSPalette.neutral[400];
export const DEFAULT_ERROR_FOREGROUND_COLOR = TailwindCSSPalette.blue[600];
// settings
export const TAB_SIZE = 2;
export const DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
export const TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH = 3;
export const TYPEAHEAD_SEARCH_LIMIT = 10;
export const EMPTY_VALUE_PLACEHOLDER = '(None)';
// --------------------------------- UTILITIES ---------------------------------
export function _defaultPrimitiveTypeValue(type: string): unknown {
switch (type) {
case PRIMITIVE_TYPE.STRING:
return '';
case PRIMITIVE_TYPE.BOOLEAN:
return false;
case PRIMITIVE_TYPE.BYTE:
return btoa('');
case PRIMITIVE_TYPE.NUMBER:
case PRIMITIVE_TYPE.DECIMAL:
case PRIMITIVE_TYPE.FLOAT:
case PRIMITIVE_TYPE.INTEGER:
case PRIMITIVE_TYPE.BINARY:
return 0;
case PRIMITIVE_TYPE.DATE:
case PRIMITIVE_TYPE.STRICTDATE:
return formatDate(new Date(Date.now()), DATE_FORMAT);
case PRIMITIVE_TYPE.DATETIME:
return formatDate(new Date(Date.now()), DATE_TIME_FORMAT);
default:
throw new UnsupportedOperationError(
`Can't generate value for type '${type}'`,
);
}
}
export function getFilterOperation(
operator: string,
operators: DataCubeQueryFilterOperation[],
) {
return guaranteeNonNullable(
operators.find((op) => op.operator === operator),
`Can't find filter operation '${operator}'`,
);
}
export function getAggregateOperation(
operator: string,
aggregateOperations: DataCubeQueryAggregateOperation[],
) {
return guaranteeNonNullable(
aggregateOperations.find((op) => op.operator === operator),
`Can't find aggregate operation '${operator}'`,
);
}
export function getDataType(type: string): DataCubeColumnDataType {
switch (type) {
case PRIMITIVE_TYPE.NUMBER:
case PRIMITIVE_TYPE.INTEGER:
case PRIMITIVE_TYPE.DECIMAL:
case PRIMITIVE_TYPE.FLOAT:
return DataCubeColumnDataType.NUMBER;
case PRIMITIVE_TYPE.DATE:
case PRIMITIVE_TYPE.STRICTDATE:
return DataCubeColumnDataType.DATE;
case PRIMITIVE_TYPE.DATETIME:
return DataCubeColumnDataType.TIME;
case PRIMITIVE_TYPE.STRING:
default:
return DataCubeColumnDataType.TEXT;
}
}
export function ofDataType(
type: string,
dataTypes: DataCubeColumnDataType[],
): boolean {
return dataTypes.includes(getDataType(type));
}
export function isDimensionalGridMode(gridMode: DataCubeGridMode) {
return gridMode === DataCubeGridMode.MULTIDIMENSIONAL;
}
export function isPrimitiveType(type: string) {
return (
[
PRIMITIVE_TYPE.NUMBER,
PRIMITIVE_TYPE.INTEGER,
PRIMITIVE_TYPE.DECIMAL,
PRIMITIVE_TYPE.FLOAT,
PRIMITIVE_TYPE.DATE,
PRIMITIVE_TYPE.STRICTDATE,
PRIMITIVE_TYPE.DATETIME,
PRIMITIVE_TYPE.STRING,
PRIMITIVE_TYPE.BOOLEAN,
] as string[]
).includes(type);
}
export function isPivotResultColumnName(columnName: string) {
return columnName.includes(PIVOT_COLUMN_NAME_VALUE_SEPARATOR);
}
export function getPivotResultColumnBaseColumnName(columnName: string) {
if (!isPivotResultColumnName(columnName)) {
throw new IllegalStateError(
`Column '${columnName}' is not a pivot result column`,
);
}
return columnName.substring(
columnName.lastIndexOf(PIVOT_COLUMN_NAME_VALUE_SEPARATOR) +
PIVOT_COLUMN_NAME_VALUE_SEPARATOR.length,
);
}