mirror of
https://github.com/apache/superset.git
synced 2026-04-17 23:25:05 +00:00
feat(table): Table with Time Comparison (#28057)
Co-authored-by: Lily Kuang <lily@preset.io> Co-authored-by: lilykuang <jialikuang@gmail.com> Co-authored-by: Kamil Gabryjelski <kamil.gabryjelski@gmail.com>
This commit is contained in:
@@ -21,13 +21,21 @@ import {
|
||||
buildQueryContext,
|
||||
ensureIsArray,
|
||||
getMetricLabel,
|
||||
getTimeOffset,
|
||||
isPhysicalColumn,
|
||||
parseDttmToDate,
|
||||
QueryMode,
|
||||
QueryObject,
|
||||
removeDuplicates,
|
||||
SimpleAdhocFilter,
|
||||
} from '@superset-ui/core';
|
||||
import { PostProcessingRule } from '@superset-ui/core/src/query/types/PostProcessing';
|
||||
import { BuildQuery } from '@superset-ui/core/src/chart/registries/ChartBuildQueryRegistrySingleton';
|
||||
import {
|
||||
isTimeComparison,
|
||||
timeCompareOperator,
|
||||
} from '@superset-ui/chart-controls';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { TableChartFormData } from './types';
|
||||
import { updateExternalFormData } from './DataTable/utils/externalAPIs';
|
||||
|
||||
@@ -69,9 +77,51 @@ const buildQuery: BuildQuery<TableChartFormData> = (
|
||||
};
|
||||
}
|
||||
|
||||
const addComparisonPercentMetrics = (metrics: string[], suffixes: string[]) =>
|
||||
metrics.reduce<string[]>((acc, metric) => {
|
||||
const newMetrics = suffixes.map(suffix => `${metric}__${suffix}`);
|
||||
return acc.concat([metric, ...newMetrics]);
|
||||
}, []);
|
||||
|
||||
return buildQueryContext(formDataCopy, baseQueryObject => {
|
||||
let { metrics, orderby = [], columns = [] } = baseQueryObject;
|
||||
const { extras = {} } = baseQueryObject;
|
||||
let postProcessing: PostProcessingRule[] = [];
|
||||
const TimeRangeFilters =
|
||||
formData.adhoc_filters?.filter(
|
||||
(filter: SimpleAdhocFilter) => filter.operator === 'TEMPORAL_RANGE',
|
||||
) || [];
|
||||
|
||||
// In case the viz is using all version of controls, we try to load them
|
||||
const previousCustomTimeRangeFilters: any =
|
||||
formData.adhoc_custom?.filter(
|
||||
(filter: SimpleAdhocFilter) => filter.operator === 'TEMPORAL_RANGE',
|
||||
) || [];
|
||||
|
||||
let previousCustomStartDate = '';
|
||||
if (
|
||||
!isEmpty(previousCustomTimeRangeFilters) &&
|
||||
previousCustomTimeRangeFilters[0]?.comparator !== 'No Filter'
|
||||
) {
|
||||
previousCustomStartDate =
|
||||
previousCustomTimeRangeFilters[0]?.comparator.split(' : ')[0];
|
||||
}
|
||||
|
||||
const timeOffsets = ensureIsArray(
|
||||
isTimeComparison(formData, baseQueryObject)
|
||||
? getTimeOffset({
|
||||
timeRangeFilter: TimeRangeFilters[0],
|
||||
shifts: formData.time_compare,
|
||||
startDate:
|
||||
previousCustomStartDate && !formData.start_date_offset
|
||||
? parseDttmToDate(previousCustomStartDate)?.toUTCString()
|
||||
: formData.start_date_offset,
|
||||
})
|
||||
: [],
|
||||
);
|
||||
|
||||
let temporalColumAdded = false;
|
||||
let temporalColum = null;
|
||||
|
||||
if (queryMode === QueryMode.Aggregate) {
|
||||
metrics = metrics || [];
|
||||
@@ -85,8 +135,17 @@ const buildQuery: BuildQuery<TableChartFormData> = (
|
||||
}
|
||||
// add postprocessing for percent metrics only when in aggregation mode
|
||||
if (percentMetrics && percentMetrics.length > 0) {
|
||||
const percentMetricsLabelsWithTimeComparison = isTimeComparison(
|
||||
formData,
|
||||
baseQueryObject,
|
||||
)
|
||||
? addComparisonPercentMetrics(
|
||||
percentMetrics.map(getMetricLabel),
|
||||
timeOffsets,
|
||||
)
|
||||
: percentMetrics.map(getMetricLabel);
|
||||
const percentMetricLabels = removeDuplicates(
|
||||
percentMetrics.map(getMetricLabel),
|
||||
percentMetricsLabelsWithTimeComparison,
|
||||
);
|
||||
metrics = removeDuplicates(
|
||||
metrics.concat(percentMetrics),
|
||||
@@ -102,23 +161,38 @@ const buildQuery: BuildQuery<TableChartFormData> = (
|
||||
},
|
||||
];
|
||||
}
|
||||
// Add the operator for the time comparison if some is selected
|
||||
if (!isEmpty(timeOffsets)) {
|
||||
postProcessing.push(timeCompareOperator(formData, baseQueryObject));
|
||||
}
|
||||
|
||||
columns = columns.map(col => {
|
||||
if (
|
||||
const temporalColumnsLookup = formData?.temporal_columns_lookup;
|
||||
// Filter out the column if needed and prepare the temporal column object
|
||||
|
||||
columns = columns.filter(col => {
|
||||
const shouldBeAdded =
|
||||
isPhysicalColumn(col) &&
|
||||
time_grain_sqla &&
|
||||
formData?.temporal_columns_lookup?.[col]
|
||||
) {
|
||||
return {
|
||||
temporalColumnsLookup?.[col];
|
||||
|
||||
if (shouldBeAdded && !temporalColumAdded) {
|
||||
temporalColum = {
|
||||
timeGrain: time_grain_sqla,
|
||||
columnType: 'BASE_AXIS',
|
||||
sqlExpression: col,
|
||||
label: col,
|
||||
expressionType: 'SQL',
|
||||
} as AdhocColumn;
|
||||
temporalColumAdded = true;
|
||||
return false; // Do not include this in the output; it's added separately
|
||||
}
|
||||
return col;
|
||||
return true;
|
||||
});
|
||||
|
||||
// So we ensure the temporal column is added first
|
||||
if (temporalColum) {
|
||||
columns = [temporalColum, ...columns];
|
||||
}
|
||||
}
|
||||
|
||||
const moreProps: Partial<QueryObject> = {};
|
||||
@@ -133,9 +207,11 @@ const buildQuery: BuildQuery<TableChartFormData> = (
|
||||
let queryObject = {
|
||||
...baseQueryObject,
|
||||
columns,
|
||||
extras: !isEmpty(timeOffsets) && !temporalColum ? {} : extras,
|
||||
orderby,
|
||||
metrics,
|
||||
post_processing: postProcessing,
|
||||
time_offsets: timeOffsets,
|
||||
...moreProps,
|
||||
};
|
||||
|
||||
@@ -169,6 +245,7 @@ const buildQuery: BuildQuery<TableChartFormData> = (
|
||||
row_limit: 0,
|
||||
row_offset: 0,
|
||||
post_processing: [],
|
||||
extras: undefined, // we don't need time grain here
|
||||
order_desc: undefined, // we don't need orderby stuff here,
|
||||
orderby: undefined, // because this query will be used for get total aggregation.
|
||||
});
|
||||
@@ -186,6 +263,7 @@ const buildQuery: BuildQuery<TableChartFormData> = (
|
||||
{ ...queryObject },
|
||||
{
|
||||
...queryObject,
|
||||
time_offsets: [],
|
||||
row_limit: 0,
|
||||
row_offset: 0,
|
||||
post_processing: [],
|
||||
|
||||
Reference in New Issue
Block a user