mirror of
https://github.com/apache/superset.git
synced 2026-06-01 13:49:21 +00:00
chore(frontend): migrate SqlLab and explore JS/JSX files to TypeScript (#36760)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 type { AdhocMetric as CoreAdhocMetric } from '@superset-ui/core';
|
||||
import {
|
||||
sqlaAutoGeneratedMetricRegex,
|
||||
AGGREGATES,
|
||||
} from 'src/explore/constants';
|
||||
|
||||
export const EXPRESSION_TYPES = {
|
||||
SIMPLE: 'SIMPLE',
|
||||
SQL: 'SQL',
|
||||
};
|
||||
|
||||
interface ColumnType {
|
||||
column_name: string;
|
||||
verbose_name?: string;
|
||||
// Allow additional properties from ColumnMeta and other column types
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface AdhocMetricInput {
|
||||
expressionType?: string;
|
||||
column?: ColumnType | null;
|
||||
aggregate?: string | null;
|
||||
sqlExpression?: string | null;
|
||||
datasourceWarning?: boolean;
|
||||
hasCustomLabel?: boolean;
|
||||
label?: string;
|
||||
optionName?: string;
|
||||
// Additional properties that may be passed in
|
||||
metric_name?: string;
|
||||
expression?: string;
|
||||
error_text?: string;
|
||||
uuid?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
function inferSqlExpressionColumn(
|
||||
adhocMetric: AdhocMetricInput,
|
||||
): string | null {
|
||||
if (
|
||||
adhocMetric.sqlExpression &&
|
||||
sqlaAutoGeneratedMetricRegex.test(adhocMetric.sqlExpression)
|
||||
) {
|
||||
const indexFirstCloseParen = adhocMetric.sqlExpression.indexOf(')');
|
||||
const indexPairedOpenParen = adhocMetric.sqlExpression
|
||||
.substring(0, indexFirstCloseParen)
|
||||
.lastIndexOf('(');
|
||||
if (indexFirstCloseParen > 0 && indexPairedOpenParen > 0) {
|
||||
return adhocMetric.sqlExpression.substring(
|
||||
indexPairedOpenParen + 1,
|
||||
indexFirstCloseParen,
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function inferSqlExpressionAggregate(
|
||||
adhocMetric: AdhocMetricInput,
|
||||
): string | null {
|
||||
if (
|
||||
adhocMetric.sqlExpression &&
|
||||
sqlaAutoGeneratedMetricRegex.test(adhocMetric.sqlExpression)
|
||||
) {
|
||||
const indexFirstOpenParen = adhocMetric.sqlExpression.indexOf('(');
|
||||
if (indexFirstOpenParen > 0) {
|
||||
return adhocMetric.sqlExpression.substring(0, indexFirstOpenParen);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter function to create an AdhocMetric instance from a core AdhocMetric type.
|
||||
* This bridges the type gap between @superset-ui/core's AdhocMetric and the local class.
|
||||
*/
|
||||
export function fromCoreAdhocMetric(metric: CoreAdhocMetric): AdhocMetric {
|
||||
return new AdhocMetric(metric as AdhocMetricInput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard to check if an object can be used to construct an AdhocMetric.
|
||||
* Returns true for plain objects that have metric-like properties.
|
||||
*/
|
||||
export function isDictionaryForAdhocMetric(
|
||||
value: unknown,
|
||||
): value is AdhocMetricInput {
|
||||
return (
|
||||
typeof value === 'object' &&
|
||||
value !== null &&
|
||||
!(value instanceof AdhocMetric) &&
|
||||
('expressionType' in value ||
|
||||
'column' in value ||
|
||||
'aggregate' in value ||
|
||||
'sqlExpression' in value ||
|
||||
'metric_name' in value)
|
||||
);
|
||||
}
|
||||
|
||||
export default class AdhocMetric {
|
||||
expressionType: string;
|
||||
column?: ColumnType | null;
|
||||
aggregate?: string | null;
|
||||
sqlExpression?: string | null;
|
||||
datasourceWarning: boolean;
|
||||
hasCustomLabel: boolean;
|
||||
label: string;
|
||||
optionName: string;
|
||||
|
||||
constructor(adhocMetric: AdhocMetricInput) {
|
||||
this.expressionType = adhocMetric.expressionType || EXPRESSION_TYPES.SIMPLE;
|
||||
if (this.expressionType === EXPRESSION_TYPES.SIMPLE) {
|
||||
// try to be clever in the case of transitioning from Sql expression back to simple expression
|
||||
const inferredColumn = inferSqlExpressionColumn(adhocMetric);
|
||||
this.column =
|
||||
adhocMetric.column ??
|
||||
(inferredColumn ? { column_name: inferredColumn } : null);
|
||||
this.aggregate =
|
||||
adhocMetric.aggregate || inferSqlExpressionAggregate(adhocMetric);
|
||||
this.sqlExpression = null;
|
||||
} else if (this.expressionType === EXPRESSION_TYPES.SQL) {
|
||||
this.sqlExpression = adhocMetric.sqlExpression;
|
||||
this.column = null;
|
||||
this.aggregate = null;
|
||||
}
|
||||
this.datasourceWarning = !!adhocMetric.datasourceWarning;
|
||||
this.hasCustomLabel = !!(adhocMetric.hasCustomLabel && adhocMetric.label);
|
||||
this.label = this.hasCustomLabel
|
||||
? (adhocMetric.label ?? this.getDefaultLabel())
|
||||
: this.getDefaultLabel();
|
||||
|
||||
this.optionName =
|
||||
adhocMetric.optionName ||
|
||||
`metric_${Math.random().toString(36).substring(2, 15)}_${Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 15)}`;
|
||||
}
|
||||
|
||||
getDefaultLabel(): string {
|
||||
return this.translateToSql({ useVerboseName: true });
|
||||
}
|
||||
|
||||
translateToSql(
|
||||
params: { useVerboseName?: boolean; transformCountDistinct?: boolean } = {
|
||||
useVerboseName: false,
|
||||
transformCountDistinct: false,
|
||||
},
|
||||
): string {
|
||||
if (this.expressionType === EXPRESSION_TYPES.SIMPLE) {
|
||||
const aggregate = this.aggregate || '';
|
||||
// eslint-disable-next-line camelcase
|
||||
const column =
|
||||
params.useVerboseName && this.column?.verbose_name
|
||||
? `(${this.column.verbose_name})`
|
||||
: this.column?.column_name
|
||||
? `(${this.column.column_name})`
|
||||
: '';
|
||||
// transform from `count_distinct(column)` to `count(distinct column)`
|
||||
if (
|
||||
params.transformCountDistinct &&
|
||||
aggregate === AGGREGATES.COUNT_DISTINCT &&
|
||||
/^\(.*\)$/.test(column)
|
||||
) {
|
||||
return `COUNT(DISTINCT ${column.slice(1, -1)})`;
|
||||
}
|
||||
return aggregate + column;
|
||||
}
|
||||
if (this.expressionType === EXPRESSION_TYPES.SQL) {
|
||||
return this.sqlExpression ?? '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
duplicateWith(nextFields: Partial<AdhocMetricInput>): AdhocMetric {
|
||||
return new AdhocMetric({
|
||||
...this,
|
||||
...nextFields,
|
||||
});
|
||||
}
|
||||
|
||||
equals(adhocMetric: AdhocMetric): boolean {
|
||||
return (
|
||||
adhocMetric.label === this.label &&
|
||||
adhocMetric.expressionType === this.expressionType &&
|
||||
adhocMetric.sqlExpression === this.sqlExpression &&
|
||||
adhocMetric.aggregate === this.aggregate &&
|
||||
(adhocMetric.column && adhocMetric.column.column_name) ===
|
||||
(this.column && this.column.column_name)
|
||||
);
|
||||
}
|
||||
|
||||
isValid(): boolean {
|
||||
if (this.expressionType === EXPRESSION_TYPES.SIMPLE) {
|
||||
return !!(this.column && this.aggregate);
|
||||
}
|
||||
if (this.expressionType === EXPRESSION_TYPES.SQL) {
|
||||
return !!this.sqlExpression;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inferSqlExpressionAggregate(): string | null {
|
||||
return inferSqlExpressionAggregate(this as unknown as AdhocMetricInput);
|
||||
}
|
||||
|
||||
inferSqlExpressionColumn(): string | null {
|
||||
return inferSqlExpressionColumn(this as unknown as AdhocMetricInput);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user